606 lines
16 KiB
C
606 lines
16 KiB
C
|
/**
|
||
|
* @file ole.c
|
||
|
* @author Alex Ott, Victor B Wagner
|
||
|
* @date Wed Jun 11 12:33:01 2003
|
||
|
* Version: $Id: ole.c,v 1.2 2006/02/25 15:28:14 vitus Exp $
|
||
|
* Copyright: Victor B Wagner, 1996-2003 Alex Ott, 2003
|
||
|
*
|
||
|
* @brief Parsing structure of MS Office compound document
|
||
|
*
|
||
|
* This file is part of catdoc project
|
||
|
* and distributed under GNU Public License
|
||
|
*
|
||
|
*/
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
#include "catdoc.h"
|
||
|
|
||
|
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||
|
|
||
|
const static unsigned char ole_sign[]={0xD0,0xCF,0x11,0xE0,0xA1,0xB1,0x1A,0xE1,0};
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Initializes ole structure
|
||
|
*
|
||
|
* @param f (FILE *) compound document file, positioned at bufSize
|
||
|
* byte. Might be pipe or socket
|
||
|
* @param buffer (void *) bytes already read from f
|
||
|
* @param bufSize number of bytes already read from f should be less
|
||
|
* than 512
|
||
|
*
|
||
|
* @return
|
||
|
*/
|
||
|
FILE* ole_init(FILE *f, void *buffer, size_t bufSize, struct ole_params_t *ole_params) {
|
||
|
unsigned char oleBuf[BBD_BLOCK_SIZE];
|
||
|
unsigned char *tmpBuf;
|
||
|
FILE *newfile;
|
||
|
int ret=0, i;
|
||
|
long int sbdMaxLen, sbdCurrent, propMaxLen, propCurrent, mblock, msat_size;
|
||
|
oleEntry *tEntry;
|
||
|
long int sectorSize;
|
||
|
long int shortSectorSize;
|
||
|
long int bbdNumBlocks;
|
||
|
|
||
|
/* deleting old data (if it was allocated) */
|
||
|
ole_finish(ole_params);
|
||
|
|
||
|
if (fseek(f,0,SEEK_SET) == -1) {
|
||
|
if ( errno == ESPIPE ) {
|
||
|
/* We got non-seekable file, create temp file */
|
||
|
if((newfile=tmpfile()) == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
if (bufSize > 0) {
|
||
|
ret=fwrite(buffer, 1, bufSize, newfile);
|
||
|
if(ret != bufSize) {
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while(!feof(f)){
|
||
|
ret=fread(oleBuf,1,BBD_BLOCK_SIZE,f);
|
||
|
fwrite(oleBuf, 1, ret, newfile);
|
||
|
}
|
||
|
fseek(newfile,0,SEEK_SET);
|
||
|
} else {
|
||
|
return NULL;
|
||
|
}
|
||
|
} else {
|
||
|
newfile=f;
|
||
|
}
|
||
|
fseek(newfile,0,SEEK_END);
|
||
|
ole_params->fileLength=ftell(newfile);
|
||
|
|
||
|
fseek(newfile,0,SEEK_SET);
|
||
|
ret=fread(oleBuf,1,BBD_BLOCK_SIZE,newfile);
|
||
|
if ( ret != BBD_BLOCK_SIZE ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
if (strncmp(oleBuf,ole_sign,8) != 0) {
|
||
|
return NULL;
|
||
|
}
|
||
|
ole_params->sectorSize = 1<<getshort(oleBuf,0x1e);
|
||
|
if (ole_params->sectorSize == 0) {
|
||
|
return NULL;
|
||
|
}
|
||
|
sectorSize = ole_params->sectorSize;
|
||
|
ole_params->shortSectorSize = 1<<getshort(oleBuf,0x20);
|
||
|
shortSectorSize= ole_params->shortSectorSize;
|
||
|
if (shortSectorSize > sectorSize) {
|
||
|
return NULL;
|
||
|
}
|
||
|
/* Read BBD into memory */
|
||
|
ole_params->bbdNumBlocks = getulong(oleBuf,0x2c);
|
||
|
bbdNumBlocks = ole_params->bbdNumBlocks;
|
||
|
if((ole_params->BBD=malloc(bbdNumBlocks*sectorSize)) == NULL ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if((tmpBuf=malloc(MSAT_ORIG_SIZE)) == NULL ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
memcpy(tmpBuf,oleBuf+0x4c,MSAT_ORIG_SIZE);
|
||
|
mblock=getlong(oleBuf,0x44);
|
||
|
msat_size=getlong(oleBuf,0x48);
|
||
|
|
||
|
/* fprintf(stderr, "msat_size=%ld\n", msat_size); */
|
||
|
|
||
|
i=0;
|
||
|
while((mblock >= 0) && (i < msat_size)) {
|
||
|
unsigned char *newbuf;
|
||
|
/* fprintf(stderr, "i=%d mblock=%ld\n", i, mblock); */
|
||
|
if ((newbuf=realloc(tmpBuf, sectorSize*(i+1)+MSAT_ORIG_SIZE)) != NULL) {
|
||
|
tmpBuf=newbuf;
|
||
|
} else {
|
||
|
free(tmpBuf);
|
||
|
ole_finish(ole_params);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
fseek(newfile, 512+mblock*sectorSize, SEEK_SET);
|
||
|
if(fread(tmpBuf+MSAT_ORIG_SIZE+(sectorSize-4)*i,
|
||
|
1, sectorSize, newfile) != sectorSize) {
|
||
|
ole_finish(ole_params);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
mblock=getlong(tmpBuf, MSAT_ORIG_SIZE+(sectorSize-4)*i);
|
||
|
}
|
||
|
|
||
|
/* fprintf(stderr, "bbdNumBlocks=%ld\n", bbdNumBlocks); */
|
||
|
for(i=0; i< bbdNumBlocks; i++) {
|
||
|
long int bbdSector=getlong(tmpBuf,4*i);
|
||
|
|
||
|
if (bbdSector >= ole_params->fileLength/sectorSize || bbdSector < 0) {
|
||
|
errno = EINVAL;
|
||
|
ole_finish(ole_params);
|
||
|
return NULL;
|
||
|
}
|
||
|
fseek(newfile, 512+bbdSector*sectorSize, SEEK_SET);
|
||
|
if ( fread(ole_params->BBD+i*sectorSize, 1, sectorSize, newfile) != sectorSize ) {
|
||
|
free(tmpBuf);
|
||
|
ole_finish(ole_params);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
free(tmpBuf);
|
||
|
|
||
|
/* Read SBD into memory */
|
||
|
ole_params->sbdLen=0;
|
||
|
sbdMaxLen=10;
|
||
|
sbdCurrent = ole_params->sbdStart = getlong(oleBuf,0x3c);
|
||
|
if (ole_params->sbdStart > 0) {
|
||
|
if((ole_params->SBD=malloc(sectorSize*sbdMaxLen)) == NULL ) {
|
||
|
ole_finish(ole_params);
|
||
|
return NULL;
|
||
|
}
|
||
|
while(1) {
|
||
|
fseek(newfile, 512+sbdCurrent*sectorSize, SEEK_SET);
|
||
|
fread(ole_params->SBD+ole_params->sbdLen*sectorSize, 1, sectorSize, newfile);
|
||
|
ole_params->sbdLen++;
|
||
|
if (ole_params->sbdLen >= sbdMaxLen) {
|
||
|
unsigned char *newSBD;
|
||
|
|
||
|
sbdMaxLen+=5;
|
||
|
if ((newSBD=realloc(ole_params->SBD, sectorSize*sbdMaxLen)) != NULL) {
|
||
|
ole_params->SBD=newSBD;
|
||
|
} else {
|
||
|
ole_finish(ole_params);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
if (sbdCurrent < 0 || sbdCurrent * 4 >= bbdNumBlocks * sectorSize)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
sbdCurrent = getlong(ole_params->BBD, sbdCurrent*4);
|
||
|
if(sbdCurrent < 0 ||
|
||
|
sbdCurrent >= ole_params->fileLength/sectorSize)
|
||
|
break;
|
||
|
}
|
||
|
ole_params->sbdNumber = (ole_params->sbdLen*sectorSize)/shortSectorSize;
|
||
|
} else {
|
||
|
ole_params->SBD=NULL;
|
||
|
}
|
||
|
/* Read property catalog into memory */
|
||
|
ole_params->propLen = 0;
|
||
|
propMaxLen = 5;
|
||
|
propCurrent = ole_params->propStart = getlong(oleBuf,0x30);
|
||
|
if (ole_params->propStart >= 0) {
|
||
|
if((ole_params->properties=malloc(propMaxLen*sectorSize)) == NULL ) {
|
||
|
ole_finish(ole_params);
|
||
|
return NULL;
|
||
|
}
|
||
|
while(1) {
|
||
|
/* fprintf(stderr, "propCurrent=%ld\n",propCurrent); */
|
||
|
fseek(newfile, 512+propCurrent*sectorSize, SEEK_SET);
|
||
|
fread(ole_params->properties+ole_params->propLen*sectorSize,
|
||
|
1, sectorSize, newfile);
|
||
|
(ole_params->propLen)++;
|
||
|
if (ole_params->propLen >= propMaxLen) {
|
||
|
unsigned char *newProp;
|
||
|
|
||
|
propMaxLen+=5;
|
||
|
if ((newProp=realloc(ole_params->properties, propMaxLen*sectorSize)) != NULL)
|
||
|
ole_params->properties=newProp;
|
||
|
else {
|
||
|
ole_finish(ole_params);
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
propCurrent = getlong(ole_params->BBD, propCurrent*4);
|
||
|
if(propCurrent < 0 ||
|
||
|
propCurrent >= ole_params->fileLength/sectorSize ) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ole_params->propNumber = (ole_params->propLen*sectorSize)/PROP_BLOCK_SIZE;
|
||
|
ole_params->propCurNumber = 0;
|
||
|
} else {
|
||
|
ole_finish(ole_params);
|
||
|
ole_params->properties = NULL;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Find Root Entry */
|
||
|
while((tEntry=(oleEntry*)ole_readdir(newfile, ole_params)) != NULL) {
|
||
|
if (tEntry->type == oleRootDir ) {
|
||
|
ole_params->rootEntry=tEntry;
|
||
|
break;
|
||
|
}
|
||
|
ole_close((FILE*)tEntry);
|
||
|
}
|
||
|
ole_params->propCurNumber = 0;
|
||
|
fseek(newfile, 0, SEEK_SET);
|
||
|
if (!ole_params->rootEntry) {
|
||
|
errno = EINVAL;
|
||
|
ole_finish(ole_params);
|
||
|
return NULL;
|
||
|
}
|
||
|
return newfile;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*
|
||
|
* @param oleBuf
|
||
|
*
|
||
|
* @return
|
||
|
*/
|
||
|
int rightOleType(unsigned char *oleBuf) {
|
||
|
return (oleBuf[0x42] == 1 || oleBuf[0x42] == 2 ||
|
||
|
oleBuf[0x42] == 3 || oleBuf[0x42] == 5 );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*
|
||
|
* @param oleBuf
|
||
|
*
|
||
|
* @return
|
||
|
*/
|
||
|
oleType getOleType(unsigned char *oleBuf) {
|
||
|
return (oleType)((unsigned char)oleBuf[0x42]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reads next directory entry from file
|
||
|
*
|
||
|
* @param name buffer for name converted to us-ascii should be at least 33 chars long
|
||
|
* @param size size of file
|
||
|
*
|
||
|
* @return 0 if everything is ok -1 on error
|
||
|
*/
|
||
|
FILE *ole_readdir(FILE *f, struct ole_params_t *ole_params) {
|
||
|
int i, nLen;
|
||
|
unsigned char *oleBuf;
|
||
|
oleEntry *e=NULL;
|
||
|
long int chainMaxLen, chainCurrent;
|
||
|
|
||
|
if ( ole_params->properties == NULL || ole_params->propCurNumber >= ole_params->propNumber || f == NULL )
|
||
|
return NULL;
|
||
|
oleBuf=ole_params->properties + ole_params->propCurNumber*PROP_BLOCK_SIZE;
|
||
|
if( !rightOleType(oleBuf))
|
||
|
return NULL;
|
||
|
if ((e = (oleEntry*)malloc(sizeof(oleEntry))) == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
e->dirPos=oleBuf;
|
||
|
e->type=getOleType(oleBuf);
|
||
|
e->file=f;
|
||
|
e->startBlock=getlong(oleBuf,0x74);
|
||
|
e->blocks=NULL;
|
||
|
|
||
|
nLen=getshort(oleBuf,0x40);
|
||
|
for (i=0 ; i < nLen/2 && i < OLENAMELENGHT; i++)
|
||
|
e->name[i]=(char)oleBuf[i*2];
|
||
|
e->name[i]='\0';
|
||
|
(ole_params->propCurNumber)++;
|
||
|
e->length=getulong(oleBuf,0x78);
|
||
|
/* Read sector chain for object */
|
||
|
chainMaxLen = 25;
|
||
|
e->numOfBlocks = 0;
|
||
|
chainCurrent = e->startBlock;
|
||
|
e->isBigBlock = (e->length >= 0x1000) || !strcmp(e->name, "Root Entry");
|
||
|
/* fprintf(stderr, "e->name=%s e->length=%ld\n", e->name, e->length); */
|
||
|
/* fprintf(stderr, "e->startBlock=%ld BBD=%p\n", e->startBlock, BBD); */
|
||
|
if (e->startBlock >= 0 &&
|
||
|
e->length >= 0 &&
|
||
|
(e->startBlock <=
|
||
|
ole_params->fileLength/(e->isBigBlock ? ole_params->sectorSize : ole_params->shortSectorSize))) {
|
||
|
if((e->blocks=malloc(chainMaxLen*sizeof(long int))) == NULL ) {
|
||
|
return NULL;
|
||
|
}
|
||
|
while(1) {
|
||
|
/* fprintf(stderr, "chainCurrent=%ld\n", chainCurrent); */
|
||
|
e->blocks[e->numOfBlocks++] = chainCurrent;
|
||
|
if (e->numOfBlocks >= chainMaxLen) {
|
||
|
long int *newChain;
|
||
|
chainMaxLen+=25;
|
||
|
if ((newChain=realloc(e->blocks,
|
||
|
chainMaxLen*sizeof(long int))) != NULL)
|
||
|
e->blocks=newChain;
|
||
|
else {
|
||
|
free(e->blocks);
|
||
|
e->blocks=NULL;
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
if ( e->isBigBlock ) {
|
||
|
chainCurrent = getlong(ole_params->BBD, chainCurrent*4);
|
||
|
} else if ( ole_params->SBD != NULL ) {
|
||
|
chainCurrent = getlong(ole_params->SBD, chainCurrent*4);
|
||
|
} else {
|
||
|
chainCurrent=-1;
|
||
|
}
|
||
|
if(chainCurrent <= 0 ||
|
||
|
chainCurrent >= ( e->isBigBlock ?
|
||
|
((ole_params->bbdNumBlocks*ole_params->sectorSize)/4)
|
||
|
: ((ole_params->sbdNumber*ole_params->shortSectorSize)/4) ) ||
|
||
|
(e->numOfBlocks >
|
||
|
e->length/(e->isBigBlock ? ole_params->sectorSize : ole_params->shortSectorSize))) {
|
||
|
/* fprintf(stderr, "chain End=%ld\n", chainCurrent); */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(e->length > (e->isBigBlock ? ole_params->sectorSize : ole_params->shortSectorSize)*e->numOfBlocks)
|
||
|
e->length = (e->isBigBlock ? ole_params->sectorSize : ole_params->shortSectorSize)*e->numOfBlocks;
|
||
|
/* fprintf(stderr, "READDIR: e->name=%s e->numOfBlocks=%ld length=%ld\n", */
|
||
|
/* e->name, e->numOfBlocks, e->length); */
|
||
|
|
||
|
return (FILE*)e;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Open stream, which correspond to directory entry last read by
|
||
|
* ole_readdir
|
||
|
*
|
||
|
*
|
||
|
* @return opaque pointer to pass to ole_read, casted to (FILE *)
|
||
|
*/
|
||
|
int ole_open(FILE *stream) {
|
||
|
oleEntry *e=(oleEntry *)stream;
|
||
|
if ( e->type != oleStream)
|
||
|
return -2;
|
||
|
|
||
|
e->ole_offset=0;
|
||
|
e->file_offset= ftell(e->file);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*
|
||
|
* @param e
|
||
|
* @param blk
|
||
|
*
|
||
|
* @return
|
||
|
*/
|
||
|
long int calcFileBlockOffset(oleEntry *e, long int blk, struct ole_params_t *ole_params) {
|
||
|
long int res;
|
||
|
if ( e->isBigBlock ) {
|
||
|
res=512+e->blocks[blk]*ole_params->sectorSize;
|
||
|
} else {
|
||
|
long int sbdPerSector=(ole_params->sectorSize)/(ole_params->shortSectorSize);
|
||
|
long int sbdSecNum=e->blocks[blk]/sbdPerSector;
|
||
|
long int sbdSecMod=e->blocks[blk]%sbdPerSector;
|
||
|
|
||
|
res=512 + ole_params->rootEntry->blocks[sbdSecNum]*ole_params->sectorSize + sbdSecMod*ole_params->shortSectorSize;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Reads block from open ole stream interface-compatible with fread
|
||
|
*
|
||
|
* @param ptr pointer to buffer for read to
|
||
|
* @param size size of block
|
||
|
* @param nmemb size in blocks
|
||
|
* @param stream pointer to FILE* structure
|
||
|
*
|
||
|
* @return number of readed blocks
|
||
|
*/
|
||
|
size_t ole_read(void *ptr, size_t size, size_t nmemb, FILE *stream, struct ole_params_t *ole_params) {
|
||
|
oleEntry *e = (oleEntry*)stream;
|
||
|
long int llen = size*nmemb, rread=0, i;
|
||
|
long int blockNumber, modBlock, toReadBlocks, toReadBytes, bytesInBlock;
|
||
|
long int ssize; /**< Size of block */
|
||
|
long int newoffset;
|
||
|
unsigned char *cptr = ptr;
|
||
|
if( e->ole_offset+llen > e->length )
|
||
|
llen= e->length - e->ole_offset;
|
||
|
|
||
|
ssize = (e->isBigBlock ? ole_params->sectorSize : ole_params->shortSectorSize);
|
||
|
blockNumber=e->ole_offset/ssize;
|
||
|
/* fprintf(stderr, "blockNumber=%ld e->numOfBlocks=%ld llen=%ld\n", */
|
||
|
/* blockNumber, e->numOfBlocks, llen); */
|
||
|
if ( blockNumber >= e->numOfBlocks || llen <=0 )
|
||
|
return 0;
|
||
|
|
||
|
modBlock=e->ole_offset%ssize;
|
||
|
bytesInBlock = ssize - modBlock;
|
||
|
if(bytesInBlock < llen) {
|
||
|
toReadBlocks = (llen-bytesInBlock)/ssize;
|
||
|
toReadBytes = (llen-bytesInBlock)%ssize;
|
||
|
} else {
|
||
|
toReadBlocks = toReadBytes = 0;
|
||
|
}
|
||
|
/* fprintf(stderr, "llen=%ld toReadBlocks=%ld toReadBytes=%ld bytesInBlock=%ld blockNumber=%ld modBlock=%ld\n", */
|
||
|
/* llen, toReadBlocks, toReadBytes, bytesInBlock, blockNumber, modBlock); */
|
||
|
newoffset = calcFileBlockOffset(e,blockNumber, ole_params)+modBlock;
|
||
|
if (e->file_offset != newoffset) {
|
||
|
fseek(e->file, e->file_offset=newoffset, SEEK_SET);
|
||
|
}
|
||
|
rread=fread(ptr, 1, min(llen,bytesInBlock), e->file);
|
||
|
e->file_offset += rread;
|
||
|
for(i=0; i<toReadBlocks; i++) {
|
||
|
int readbytes;
|
||
|
blockNumber++;
|
||
|
newoffset = calcFileBlockOffset(e,blockNumber, ole_params);
|
||
|
if (newoffset != e->file_offset);
|
||
|
fseek(e->file, e->file_offset=newoffset , SEEK_SET);
|
||
|
readbytes=fread(cptr+rread, 1, min(llen-rread, ssize), e->file);
|
||
|
rread +=readbytes;
|
||
|
e->file_offset +=readbytes;
|
||
|
}
|
||
|
if(toReadBytes > 0) {
|
||
|
int readbytes;
|
||
|
blockNumber++;
|
||
|
newoffset = calcFileBlockOffset(e,blockNumber, ole_params);
|
||
|
fseek(e->file, e->file_offset=newoffset, SEEK_SET);
|
||
|
readbytes=fread(cptr+rread, 1, toReadBytes,e ->file);
|
||
|
rread +=readbytes;
|
||
|
e->file_offset +=readbytes;
|
||
|
}
|
||
|
/* fprintf(stderr, "ole_offset=%ld rread=%ld llen=%ld\n",
|
||
|
e->ole_offset, rread, llen);*/
|
||
|
e->ole_offset+=rread;
|
||
|
return rread;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*
|
||
|
* @param stream
|
||
|
*
|
||
|
* @return
|
||
|
*/
|
||
|
int ole_eof(FILE *stream) {
|
||
|
oleEntry *e=(oleEntry*)stream;
|
||
|
/* fprintf(stderr, "EOF: e->ole_offset=%ld e->length=%ld\n",
|
||
|
e->ole_offset, e->length);*/
|
||
|
return (e->ole_offset >= e->length);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
void ole_finish(struct ole_params_t *ole_params) {
|
||
|
if ( ole_params->BBD != NULL ) free(ole_params->BBD);
|
||
|
if ( ole_params->SBD != NULL ) free(ole_params->SBD);
|
||
|
if ( ole_params->properties != NULL ) free(ole_params->properties);
|
||
|
if ( ole_params->rootEntry != NULL ) ole_close((FILE*)(ole_params->rootEntry));
|
||
|
ole_params->properties = ole_params->SBD = ole_params->BBD = NULL;
|
||
|
ole_params->rootEntry = NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*
|
||
|
* @param stream
|
||
|
*
|
||
|
* @return
|
||
|
*/
|
||
|
int ole_close(FILE *stream) {
|
||
|
oleEntry *e=(oleEntry*)stream;
|
||
|
if(e == NULL)
|
||
|
return -1;
|
||
|
if (e->blocks != NULL)
|
||
|
free(e->blocks);
|
||
|
free(e);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*
|
||
|
* @param stream pointer to OLE stream structure
|
||
|
* @param offset
|
||
|
* @param whence
|
||
|
*
|
||
|
* @return
|
||
|
*/
|
||
|
int ole_seek(FILE *stream, long offset, int whence, struct ole_params_t *ole_params) {
|
||
|
oleEntry *e=(oleEntry*)stream;
|
||
|
long int new_ole_offset=0, new_file_offset;
|
||
|
int ssize, modBlock, blockNumber;
|
||
|
|
||
|
switch(whence) {
|
||
|
case SEEK_SET:
|
||
|
new_ole_offset=offset;
|
||
|
break;
|
||
|
|
||
|
case SEEK_CUR:
|
||
|
new_ole_offset=e->ole_offset+offset;
|
||
|
break;
|
||
|
|
||
|
case SEEK_END:
|
||
|
new_ole_offset=e->length+offset;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
errno=EINVAL;
|
||
|
return -1;
|
||
|
}
|
||
|
if(new_ole_offset<0)
|
||
|
new_ole_offset=0;
|
||
|
if(new_ole_offset >= e->length)
|
||
|
new_ole_offset=e->length;
|
||
|
|
||
|
ssize = (e->isBigBlock ? ole_params->sectorSize : ole_params->shortSectorSize);
|
||
|
blockNumber=new_ole_offset/ssize;
|
||
|
if ( blockNumber >= e->numOfBlocks )
|
||
|
return -1;
|
||
|
|
||
|
modBlock=new_ole_offset%ssize;
|
||
|
new_file_offset = calcFileBlockOffset(e,blockNumber, ole_params)+modBlock;
|
||
|
fseek(e->file, e->file_offset=new_file_offset, SEEK_SET);
|
||
|
e->ole_offset=new_ole_offset;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Tell position inside OLE stream
|
||
|
*
|
||
|
* @param stream pointer to OLE stream
|
||
|
*
|
||
|
* @return current position inside OLE stream
|
||
|
*/
|
||
|
long ole_tell(FILE *stream) {
|
||
|
oleEntry *e=(oleEntry*)stream;
|
||
|
return e->ole_offset;
|
||
|
}
|
||
|
|
||
|
|
||
|
void set_ole_func(struct io_funcs_t *io_funcs) {
|
||
|
io_funcs->catdoc_read=ole_read;
|
||
|
io_funcs->catdoc_eof=ole_eof;
|
||
|
io_funcs->catdoc_seek=ole_seek;
|
||
|
io_funcs->catdoc_tell=ole_tell;
|
||
|
}
|
||
|
|
||
|
|
||
|
size_t my_fread(void *ptr, size_t size, size_t nmemb, FILE *stream, struct ole_params_t *ole_params)
|
||
|
{
|
||
|
return fread(ptr, size, nmemb, stream);
|
||
|
}
|
||
|
|
||
|
int my_fseek(FILE *stream, long offset, int whence, struct ole_params_t *ole_params)
|
||
|
{
|
||
|
return fseek(stream, offset, whence);
|
||
|
}
|
||
|
|
||
|
void set_std_func(struct io_funcs_t *io_funcs) {
|
||
|
io_funcs->catdoc_read=my_fread;
|
||
|
io_funcs->catdoc_eof=feof;
|
||
|
io_funcs->catdoc_seek=my_fseek;
|
||
|
io_funcs->catdoc_tell=ftell;
|
||
|
}
|