#ifdef _MSC_VER #include #endif #include #include #include #include #include #include "logger.h" #include "pldstr.h" #include "bt-int.h" #include "bytedecoders.h" #include "olestream-unwrap.h" #include "ole.h" #include "localization.h" #include "charEncoding.h" #include "createdirectory.h" /** Sector ID values (predefined) **/ #define OLE_SECTORID_FREE -1 /** Unallocated sector **/ #define OLE_SECTORID_ENDOFCHAIN -2 /** Sector marks the end of the a sector-ID chain **/ #define OLE_SECTORID_SAT -3 /** Sector used by sector allocation Table **/ #define OLE_SECTORID_MSAT -4 /** Sector used by master sector allocation Table **/ #include "MALLOC.h" /* MALLOC */ /* Main header accessors*/ #define header_id(x) ((x) +0) #define header_clid(x) ((x) +0x08) #define header_minor_version(x) ((x) +0x18) #define header_dll_version(x) ((x) +0x1a) #define header_byte_order(x) ((x) +0x1c) #define header_sector_shift(x) ((x) +0x1e) #define header_mini_sector_shift(x) ((x) +0x20) #define header_fat_sector_count(x) ((x) +0x2c) #define header_directory_stream_start_sector(x) ((x) +0x30) #define header_mini_cutoff_size(x) ((x) +0x38) #define header_mini_fat_start(x) ((x) +0x3c) #define header_mini_fat_sector_count(x) ((x) +0x40) #define header_dif_start_sector(x) ((x) +0x44) #define header_dif_sector_count(x) ((x) +0x48) #define header_fat_sectors(x) ((x) +0x4c) /*Property Storage accessor macros*/ #define pps_rawname(x) ((x) +0) #define pps_sizeofname(x) ((x) +0x40) #define pps_type(x) ((x) +0x42) #define pps_previouspps(x) ((x) +0x44) #define pps_nextpps(x) ((x) +0x48) #define pps_directorypps(x) ((x) +0x4c) #define pps_time1seconds(x) ((x) +0x64) #define pps_time1days(x) ((x) +0x68) #define pps_time2seconds(x) ((x) +0x6c) #define pps_time2days(x) ((x) +0x70) #define pps_propertystart(x) ((x) +0x74) #define pps_sizeofproperty(x) ((x) +0x78) /* Type lengths*/ #define LEN_BYTE 1 #define LEN_USHORT 2 #define LEN_ULONG 4 /* Directory types*/ #define STGTY_INVALID 0 #define STGTY_STORAGE 1 #define STGTY_STREAM 2 #define STGTY_LOCKBYTES 3 #define STGTY_PROPERTY 4 #define STGTY_ROOT 5 /* Directory tag colours*/ #define DE_RED 0 #define DE_BLACK 1 #define DOLE if (OLE_DNORMAL(ole->debug)) #define VOLE if (ole->verbose) unsigned char OLE_id_v2[] = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 }; unsigned char OLE_id_v1[] = { 0x0e, 0x11, 0xfc, 0x0d, 0xd0, 0xcf, 0x11, 0xe0 }; /*-----------------------------------------------------------------\ Function Name : OLE_version Returns Type : int ----Parameter List 1. void , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_version(void) { fprintf(stderr, _("ripOLE: %s\n"), LIBOLE_VERSION); return 0; } /*-----------------------------------------------------------------\ Function Name : OLE_init Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: 20041127-2029:PLD: Added file_size initialization \------------------------------------------------------------------*/ int OLE_init(struct OLE_object *ole) { ole->debug = 0; ole->verbose = 0; ole->quiet = 0; ole->filename_report_fn = NULL; ole->f = NULL; ole->file_size = 0; ole->FAT = NULL; ole->FAT_limit = NULL; ole->miniFAT = NULL; ole->miniFAT_limit = NULL; ole->header_block[0] = '\0'; ole->ministream = NULL; ole->properties = NULL; ole->header.sector_shift = 0; ole->header.mini_sector_shift = 0; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_dir_init Returns Type : int ----Parameter List 1. struct OLE_directory_entry *dir , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_dir_init(struct OLE_directory_entry *dir) { memset(dir->element_name, '\0', OLE_DIRECTORY_ELEMENT_NAME_SIZE); dir->element_name_byte_count = 0; dir->element_type = 0; dir->element_colour = 0; dir->left_child = 0; dir->right_child = 0; dir->root = 0; dir->class[0] = '\0'; dir->userflags = 0; dir->timestamps[0] = '\0'; dir->start_sector = 0; dir->stream_size = 0; return 0; }; /*-----------------------------------------------------------------\ Function Name : OLE_set_verbose Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_verbose(struct OLE_object *ole, int level) { ole->verbose = level; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_set_quiet Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_quiet(struct OLE_object *ole, int level) { ole->quiet = level; ole->verbose = 0; ole->debug = 0; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_set_debug Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_debug(struct OLE_object *ole, int level) { ole->debug = level; if (ole->debug > 0) { LOGGER_log(_("%s:%d:OLE_set_debug: Debug level set to %d"), FL, ole->debug); } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_set_save_unknown_streams Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_save_unknown_streams(struct OLE_object *ole, int level) { ole->save_unknown_streams = level; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_sectorpos Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int SID , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: Given a sector ID, this function will return the file position offset. Assumes that the offset for the file starts at 512 bytes (which is the size of the OLE header) -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_sectorpos(struct OLE_object *ole, int SID) { int pos = 0; pos = 512 + (SID * ole->header.sector_size); return pos; } /*-----------------------------------------------------------------\ Function Name : OLE_get_block Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int block_index, Block indexes / Sector ID's are signed ints. 3. unsigned char *block_buffer , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_get_block(struct OLE_object *ole, int block_index, unsigned char *block_buffer) { if (block_buffer == NULL) { LOGGER_log(_("%s:%d:OLE_get_block:ERROR: Block buffer is NULL"), FL); return -1; } if (ole->f != NULL) { int read_count = 0; int fseek_result = 0; size_t offset = 0; unsigned char *bb = NULL; bb = MALLOC(sizeof(unsigned char) * ole->header.sector_size); if (bb == NULL) { LOGGER_log(_("%s:%d:OLE_get_block:ERROR: Cannot allocate %d bytes for OLE block"), FL, ole->header.sector_size); return -1; } DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: BlockIndex=%d, Buffer=0x%x", FL, block_index, block_buffer); /*20051211-2343:PLD: offset = (block_index +1) << ole->header.sector_shift; */ offset = OLE_sectorpos(ole, block_index); DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Read offset in file = 0x%x size to read= 0x%x", FL, offset, ole->header.sector_size); fseek_result = fseek(ole->f, (long)offset, SEEK_SET); if (fseek_result != 0) { if (bb != NULL) { FREE(bb); bb = NULL; } LOGGER_log(_("%s:%d:OLE_get_block:ERROR: Seek failure (block=%d:%d)"), FL, block_index, offset, strerror(errno)); return OLEER_GET_BLOCK_SEEK; } /*read_count = fread(block_buffer, sizeof(unsigned char), ole->header.sector_size, ole->f); */ read_count = (int)fread(bb, sizeof(unsigned char), ole->header.sector_size, ole->f); DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Read %d byte of data", FL, read_count); if (read_count != (int)ole->header.sector_size) { if (bb != NULL) { FREE(bb); bb = NULL; } VOLE LOGGER_log(_("%s:%d:Mismatch in bytes read. Requested %d, got %d\n"), FL, ole->header.sector_size, read_count); return OLEER_GET_BLOCK_READ; } DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Copying over memory read from file", FL); memcpy(block_buffer, bb, ole->header.sector_size); DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: memory block copied to block_buffer", FL); /* We're now done with BB, dispose of it */ if (bb) { FREE(bb); bb = NULL; } DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Disposed of temporary bb block", FL); } else { LOGGER_log(_("%s:%d:OLE_get_block:ERROR: OLE file is closed\n"), FL); return -1; } DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Done", FL); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_get_miniblock Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. unsigned int block_index, 3. unsigned char *block_buffer , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_get_miniblock(struct OLE_object *ole, int block_index, unsigned char *block_buffer) { /* This code may refer memory outside of the allocated one for ole->ministream * * in case of VBA Streams Serge Steer 26/01/2007 */ if (ole->ministream) { int offset = block_index << ole->header.mini_sector_shift; memcpy(block_buffer, ole->ministream + offset, ole->header.mini_sector_size); } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_dbstosbs Returns Type : int ----Parameter List 1. char *raw_string, 2. size_t char_count, 3. char *clean_string , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_dbstosbs(char *raw_string, size_t byte_count, char *clean_string, int clean_string_len) { char *limit = raw_string + byte_count - 1; clean_string_len--; while ((raw_string < limit) && (byte_count > 0) && (byte_count--) && (clean_string_len--)) { int v = (char) * raw_string; if (isprint(v)) { *clean_string = (char)v; clean_string++; } raw_string += 2; } *clean_string = '\0'; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_print_string Returns Type : int ----Parameter List 1. char *string, 2. size_t length , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_print_string(char *string, size_t char_count) { while (char_count--) { printf("%c", *string); string += 2; } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_print_sector Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. unsigned char *sector , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ static int OLE_print_sector(struct OLE_object *ole, unsigned char *sector, unsigned int bytes) { int current_byte; int ubytes = bytes; printf("\n"); for (current_byte = 0; current_byte < ubytes; current_byte++) { printf("%02X ", *(sector + current_byte)); if (((current_byte + 1) % 32) == 0) { int j; for (j = current_byte - 31; j <= current_byte; j++) { if (isalnum(*(sector + j))) { printf("%c", *(sector + j)); } else { printf("."); } } printf("\n"); } } printf("\n"); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_is_OLE_file Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_is_file_OLE(struct OLE_object *ole) { if (memcmp(OLE_id_v1, ole->header_block, sizeof(OLE_id_v1)) == 0) { return 1; } if (memcmp(OLE_id_v2, ole->header_block, sizeof(OLE_id_v2)) == 0) { return 1; } return 0; } /*-----------------------------------------------------------------\ Function Name : OLE_get_header Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_get_header(struct OLE_object *ole) { int result = 0; ole->header.sector_size = OLE_HEADER_BLOCK_SIZE; result = OLE_get_block(ole, -1, ole->header_block); if (OLE_is_file_OLE(ole) == 0) { return OLEER_NOT_OLE_FILE; } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_convert_header Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_convert_header(struct OLE_object *ole) { struct OLE_header *h; unsigned char *hb; /** pointer to the header block **/ unsigned char *fat_start; unsigned int i; h = &(ole->header); hb = ole->header_block; /** Note that the header_*(hb) calls are actually macros which are ** defined in the ole.h file. These macros basically take the ** hb value and add the required offset, they don't affect the ** value of hb (or they certainly SHOULD NOT! ) **/ h->minor_version = get_2byte_value(header_minor_version(hb)); h->dll_version = get_2byte_value(header_dll_version(hb)); h->byte_order = get_2byte_value(header_byte_order(hb)); /** 0xFEFF = Little endian, 0xFFFE = big endian **/ h->sector_shift = get_2byte_value(header_sector_shift(hb)); h->sector_size = 1 << h->sector_shift; h->mini_sector_shift = get_2byte_value(header_mini_sector_shift(hb)); h->mini_sector_size = 1 << h->mini_sector_shift; h->fat_sector_count = get_4byte_value(header_fat_sector_count(hb)); /** Total number of sectors use for the SAT **/ h->directory_stream_start_sector = get_4byte_value(header_directory_stream_start_sector(hb)); /** Start sector-ID for the DIRECTORY STREAM **/ h->mini_cutoff_size = get_4byte_value(header_mini_cutoff_size(hb)); h->mini_fat_start = get_4byte_value(header_mini_fat_start(hb)); h->mini_fat_sector_count = get_4byte_value(header_mini_fat_sector_count(hb)); h->dif_start_sector = get_4byte_value(header_dif_start_sector(hb)); h->dif_sector_count = get_4byte_value(header_dif_sector_count(hb)); /** Compute the maximum possible sector number by taking our OLE filesize ** and dividing it by the size of our sector size. While this isn't ** absolutely accurate it is at least useful in providing us with an ** upper-bound of what is an acceptable sector ID **/ ole->last_sector = (int)(ole->file_size >> h->sector_shift); /** Decode our first 109 sector-ID's into the master sector allocation table (MSAT/FAT) **/ fat_start = header_fat_sectors(hb); for (i = 0; i < h->fat_sector_count; i++) { if (i >= OLE_HEADER_FAT_SECTOR_COUNT_LIMIT) { break; } h->FAT[i] = get_4byte_value(fat_start + (LEN_ULONG * i)); } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_header_sanity_check Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: Determines the degree of insanity in the header, returning it as an integer, 1 per degree of insanity. -------------------------------------------------------------------- Changes: 20041127-2027:PLD: Initial version \------------------------------------------------------------------*/ static int OLE_header_sanity_check(struct OLE_object *ole) { int insanity = 0; int max_sectors; struct OLE_header *h; h = &(ole->header); max_sectors = (int)(ole->file_size / h->sector_size); if (h->sector_shift > 20) { insanity++; } if (h->mini_sector_shift > 10) { insanity++; } if ((int)h->fat_sector_count < 0) { insanity++; } if (h->fat_sector_count > (unsigned int)max_sectors) { insanity++; } if (h->directory_stream_start_sector > (unsigned int)max_sectors) { insanity++; } return insanity; } /*-----------------------------------------------------------------\ Function Name : OLE_print_header Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_print_header(struct OLE_object *ole) { unsigned int i; struct OLE_header *h; h = &(ole->header); printf("Minor version = %d\n" "DLL version = %d\n" "Byte order = %d\n\n" "Sector shift = %d\n" "Sector size = %d\n" "Mini Sector shift = %d\n" "Mini sector size = %d\n\n" "FAT sector count = %d\n" "First FAT sector = %d\n\n" "Maximum ministream size = %d\n\n" "First MiniFAT sector = %d\n" "MiniFAT sector count = %d\n\n" "First DIF sector = %d\n" "DIF sector count = %d\n" "--------------------------------\n", h->minor_version, h->dll_version, h->byte_order, h->sector_shift, h->sector_size, h->mini_sector_shift, h->mini_sector_size, h->fat_sector_count, h->directory_stream_start_sector, h->mini_cutoff_size, h->mini_fat_start, h->mini_fat_sector_count, h->dif_start_sector, h->dif_sector_count); /* Print out the FAT chain */ for (i = 0; i < h->fat_sector_count; i++) { if (i >= OLE_HEADER_FAT_SECTOR_COUNT_LIMIT) { break; /* We can't read beyond the 109th sector location */ } printf("FAT[%d] = %d\n", i, h->FAT[i]); } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_convert_directory Returns Type : int ----Parameter List 1. unsigned char *buf, 2. struct OLE_directory_entry *dir , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_convert_directory(struct OLE_object *ole, unsigned char *buf, struct OLE_directory_entry *dir) { /** Converts a raw block of 128 bytes from the file to a ** struct OLE_directory_entry data structure **/ /** Flush the element name **/ memset(dir->element_name, '\0', OLE_DIRECTORY_ELEMENT_NAME_SIZE); /** The first 64 bytes of the structure are the element's name ** in 16-bite UNICODE, meaning a maximum of 31 characters when ** we account for the trailing zero byte **/ /** Copy the first 64 bytes of our *buf parameter into the element name **/ memcpy(dir->element_name, buf, OLE_DIRECTORY_ELEMENT_NAME_SIZE); /** how many bytes of the above 64 bytes are used for the name (NOT CHARACTERS!), ** ** example, for a 8 character string with a trailing zero we use ** ** (8+1)*2 = 18 bytes **/ dir->element_name_byte_count = get_2byte_value(buf + 0x40); /** Element type is of the following: ** 0x00 - empty ** 0x01 - user storage ** 0x02 - user stream ** 0x03 - lock bytes (we don't know what this is for) ** 0x04 - property (again, we don't know) ** 0x05 - root storage **/ dir->element_type = (char)get_1byte_value(buf + 0x42); /** Element colour for the red-black tree: ** 0x00 - Red ** 0x01 - Black **/ dir->element_colour = (char)get_1byte_value(buf + 0x43); /** Directory ID (DID) of the left child, -1 if no sibling **/ dir->left_child = get_4byte_value(buf + 0x44); /** Directory ID (DID) of the right child, -1 if no sibling **/ dir->right_child = get_4byte_value(buf + 0x48); /** Directory ID (DID) of the root node entry of the RB tree of all ** storage members (if this entry is a storage), else -1. **/ dir->root = get_4byte_value(buf + 0x4c); memcpy(dir->class, buf + 0x50, 16); dir->userflags = get_4byte_value(buf + 0x60); memcpy(dir->timestamps, buf + 0x64, 16); /** Actually consists of 2 8 byte stamps **/ /** Sector ID of the first sector or short-sector **/ dir->start_sector = get_4byte_value(buf + 0x74); /** Size of this stream **/ DOLE LOGGER_log("%s:%d:OLE_directory_entry:DEBUG: stream size = 0x%x %x %x %x", FL, *(buf + 0x78), *(buf + 0x79), *(buf + 0x7A), *(buf + 0x7B)); dir->stream_size = get_4byte_value(buf + 0x78); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_print_directory Returns Type : int ----Parameter List 1. struct OLE *ole, 2. struct OLE_directory_entry *dir , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_print_directory(struct OLE_object *ole, struct OLE_directory_entry *dir) { char element[64]; OLE_dbstosbs(dir->element_name, dir->element_name_byte_count, element, sizeof(element)); printf("Element Name = %s\n" "Element type = %d\n" "Element colour = %d\n" "Left Child = %d\n" "Right Child = %d\n" "Root = %d\n" "User flags = %d\n" "Start sector = %d\n" "Stream Size = %d\n", element, dir->element_type, dir->element_colour, dir->left_child, dir->right_child, dir->root, dir->userflags, dir->start_sector, dir->stream_size); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_load_FAT Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_load_FAT(struct OLE_object *ole) { unsigned int FAT_size; FAT_size = ole->header.fat_sector_count << ole->header.sector_shift; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG:Allocating for %d sectors (%d bytes)\n", FL, ole->header.fat_sector_count, FAT_size); ole->FAT = MALLOC(FAT_size * sizeof(unsigned char)); ole->FAT_limit = ole->FAT + FAT_size; if (ole->FAT != NULL) { unsigned int i; unsigned char *fat_position = ole->FAT; unsigned int sector_count = ole->header.fat_sector_count; if (sector_count > OLE_HEADER_FAT_SECTOR_COUNT_LIMIT) { sector_count = OLE_HEADER_FAT_SECTOR_COUNT_LIMIT; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: sector count greater than limit; set to %d", FL, sector_count); } /* Load in all our primary-FAT sectors from the OLE file */ for (i = 0; i < sector_count; i++) { int getblock_result = 0; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Loading sector %d", FL, i); getblock_result = OLE_get_block(ole, ole->header.FAT[i], fat_position); if (getblock_result != 0) { /* if the get block fails, return the error - but keep the FAT */ /* pointer alive - so that we can facilitate debugging */ /* otherwise the caller is always going to get a NULL pointer */ /* and have no idea to what extent the data was read. */ /**/ /* This behavior may be changed later - but for now (beta development) */ /* it'll be okay to leave it here - just make sure we know to */ /* free the FAT block later. */ return getblock_result; } fat_position += ole->header.sector_size; if (fat_position > ole->FAT_limit) { LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: FAT boundary limit exceeded %p > %p", FL, fat_position, ole->FAT_limit); return -1; } } /* If our DIF count is > 0, this means we have a pretty big */ /* file on hand (> 7Mb) and thus we now have to do some */ /* fancy double-dereferenced sector request - enough to */ /* twist your brain if you're not alert, you have been */ /* warned. */ if (ole->header.dif_sector_count > 0) { unsigned char *fat_block; unsigned char *fat_block_end; unsigned int current_sector = ole->header.dif_start_sector; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Allocating %d bytes to fat_block\n", FL, ole->header.sector_size); fat_block = MALLOC(ole->header.sector_size); if (fat_block == NULL) { LOGGER_log(_("%s:%d:OLE_load_FAT:ERROR: Unable to allocate %d bytes\n"), FL, ole->header.sector_size); return -1; /* exit(1); */ } /* We need to know where the end of this block is - because it's */ /* used to show us where the NEXT FAT block is going to come from */ /* NOTE - this only occurs if we do have another block, else */ /* we'll simply have to just realise that we don't need any more */ /* blocks and stop with this one. */ fat_block_end = fat_block + ole->header.sector_size - LEN_ULONG; /* We know we've got 'dif_sector_count' blocks to read, each of */ /* these blocks hold no more than 127 sector addresses which */ /* contain the actual FAT data we're after (this is the double */ /* dereference bit that twists your brain ) */ DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Loading DIF sectors (count = %d)", FL, ole->header.dif_sector_count); for (i = 0; i < ole->header.dif_sector_count; i++) { int import_sector; unsigned char *DIF = fat_block; int tick = 0; int getblock_result; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Reading DIF/XBAT index-data[%d] from sector 0x%x", FL, i, current_sector); getblock_result = OLE_get_block(ole, current_sector, fat_block); if (getblock_result != OLE_OK) { if (fat_block) { FREE(fat_block); } return getblock_result; } if (OLE_DPEDANTIC(ole->debug)) { OLE_print_sector(ole, fat_block, ole->header.sector_size); } /* Now, traverse this block until we hit a < 0 */ /* If we get what is a non-valid sector value */ /* we know we've reached the end of the valid */ /* sectors from which to read more extended FAT */ /* data. */ do { import_sector = get_4byte_value(DIF); DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: import sector = 0x%x", FL, import_sector); if (import_sector >= 0) { if (fat_position + ole->header.sector_size <= ole->FAT_limit) { DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Reading DIF/XBAT-data[%d] from sector 0x%x", FL, tick, import_sector); getblock_result = OLE_get_block(ole, import_sector, fat_position); if (getblock_result != OLE_OK) { LOGGER_log(_("%s:%d:OLE_load_FAT:ERROR: Not able to load block, import sector = 0x%x, fat position = 0x%x"), FL, import_sector, fat_position); if (fat_block) { FREE(fat_block); } return getblock_result; } fat_position += ole->header.sector_size; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: FAT position = 0x%x (start = 0x%x, end = 0x%x)", FL, fat_position, fat_block, ole->FAT_limit); /*if (fat_position +ole->header.sector_size > ole->FAT_limit) */ if (fat_position > ole->FAT_limit) { DOLE LOGGER_log(_("%s:%d:OLE_load_FAT:ERROR: FAT memory boundary limit exceeded %p >= %p"), FL, fat_position, ole->FAT_limit); if (fat_block) { FREE(fat_block); } return OLEER_MEMORY_OVERFLOW; } tick++; DIF += LEN_ULONG; } else { LOGGER_log(_("%s:%d:OLE_load_FAT:ERROR: FAT memory boundary limit exceeded %p >= %p"), FL, fat_position, ole->FAT_limit); if (fat_block) { FREE(fat_block); } return OLEER_MEMORY_OVERFLOW; } } else { VOLE LOGGER_log(_("%s:%d:OLE_load_FAT:ERROR: sector request was negative (%d)"), FL, import_sector); } DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: DIF = 0x%x", FL, DIF); } while ((import_sector >= 0) && (DIF < fat_block_end)); /* Get the next sector of DIF/XBAT data ... */ /**/ /* If we still have more sectors full of extended FAT */ /* sectors that we have to read, then we neet to */ /* obtain the address of the next FAT-sector filled */ /* sector */ if (i < ole->header.dif_sector_count - 1) { current_sector = get_4byte_value(fat_block_end); DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Next DIF/XBAT index sector located at 0x%x", FL, current_sector); if ((int)current_sector < 0) { break; } } } /* For every DIF/XBAT sector we're supposed to read */ if (fat_block) { FREE(fat_block); } } /* If we have DIF/XBAT sectors to read into the FAT */ } /* If we managed to allocate memory for our FAT table */ return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_follow_chain Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int FAT_sector_start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_follow_chain(struct OLE_object *ole, int FAT_sector_start) { int current_sector = FAT_sector_start; int chain_length = 0; int last_sector_of_file = ole->last_sector; int break_out = 0; struct bti_node *n; BTI_init(&n); if (FAT_sector_start < 0) { return 0; } DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: Starting chain follow at sector %d", FL, FAT_sector_start); do { int next_sector; unsigned char *next_sector_location; next_sector_location = ole->FAT + (LEN_ULONG * current_sector); if (next_sector_location > (ole->FAT_limit - 4)) { DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: ERROR: Next sector was outside of the limits of this file (%ld > %ld)", FL, next_sector_location, ole->FAT_limit); break; } /*next_sector = get_4byte_value( ole->FAT +(LEN_ULONG *current_sector)); */ next_sector = get_4byte_value(next_sector_location); if (BTI_add(&n, next_sector) != 0) { DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: Sector collision, terminating chain traversal", FL); chain_length = -1; break; } DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: 0x%0X:%d)->(0x%0X:%d)\n", FL, current_sector, current_sector, next_sector, next_sector); /* 20040729-10H37 Added this to prevent endless loop which sometimes occurs at sector 0 */ if (next_sector == current_sector) { break; } /* fflush(stdout); */ current_sector = next_sector; chain_length++; /** Test to see if we should terminate this chain traversal **/ switch (current_sector) { case OLE_SECTORID_MSAT: case OLE_SECTORID_SAT: case OLE_SECTORID_ENDOFCHAIN: case OLE_SECTORID_FREE: break_out = 1; break; default: break_out = 0; }; if (current_sector < 0) { break_out = 1; } } while ((break_out == 0) && (current_sector < last_sector_of_file)); BTI_done(&n); return chain_length; } /*-----------------------------------------------------------------\ Function Name : OLE_follow_minichain Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int FAT_sector_start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_follow_minichain(struct OLE_object *ole, int miniFAT_sector_start) { /*unsigned int current_sector = miniFAT_sector_start; */ int current_sector = miniFAT_sector_start; int chain_length = 0; int break_out = 0; DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Starting at sector %d", FL, miniFAT_sector_start); if (miniFAT_sector_start < 0) { return 0; } do { /*unsigned int next_sector; */ int next_sector; DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Requesting 4-byte value at '%d'", FL, ole->miniFAT + (LEN_ULONG * current_sector)); /* next text commented out because ole->miniFAT_limit is set to null ans vever change * if (ole->miniFAT +(LEN_ULONG *current_sector) > ole->miniFAT_limit) { * DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Requested location is out of bounds\n",FL); * return 0; * } */ next_sector = get_4byte_value(ole->miniFAT + (LEN_ULONG * current_sector)); DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Current Msector(0x%0X:%d)->next(0x%0X:%d)\n", FL, current_sector, current_sector, next_sector, next_sector); /** Check for conditions that indicate we should stop traversing this chain **/ /** 1. We cannot point to ourselves **/ if (current_sector == next_sector) { break; } chain_length++; current_sector = next_sector; /** Test for non-positive type sector ID's **/ switch (current_sector) { case OLE_SECTORID_MSAT: case OLE_SECTORID_SAT: case OLE_SECTORID_ENDOFCHAIN: case OLE_SECTORID_FREE: break_out = 1; break; default: break_out = 0; }; DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: current sector = %d", FL, current_sector); /* Test changed Serge Steer Scilab */ /* } while ((break_out==0) &&(current_sector <= ole->last_sector)); */ } while (break_out == 0); DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Done. Chainlength=%d", FL, chain_length); return chain_length; } /*-----------------------------------------------------------------\ Function Name : char Returns Type : unsigned ----Parameter List 1. *OLE_load_minichain( struct OLE_object *ole, 2. int FAT_sector_start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: PLD:2003-Aug-28: Added sanity checking on the miniFAT_sector_start value so that we didn't try to load up a miniFAT starting on a negative value \------------------------------------------------------------------*/ unsigned char *OLE_load_minichain(struct OLE_object *ole, int miniFAT_sector_start) { int chain_length = 0; int current_sector = miniFAT_sector_start; unsigned char *buffer; unsigned char *bp; int break_out = 0; DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Loading minichain starting at %d", FL, miniFAT_sector_start); /* Added this sanity checking 2003 Aug 28 */ if (miniFAT_sector_start < 0) { return NULL; } chain_length = OLE_follow_minichain(ole, miniFAT_sector_start); DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Found %d mini-sectors to load (%d bytes)\n", FL, chain_length, chain_length * ole->header.mini_sector_size); /* 20040911-21H59 */ /* If our chain is 0 length, then there's nothing to return */ if (chain_length == 0) { return NULL; } bp = buffer = MALLOC(chain_length * ole->header.mini_sector_size * sizeof(unsigned char)); if (buffer != NULL) { do { int next_sector; DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Loading sector %d", FL, current_sector); OLE_get_miniblock(ole, current_sector, bp); bp += ole->header.mini_sector_size; next_sector = get_4byte_value(ole->miniFAT + (LEN_ULONG * current_sector)); current_sector = next_sector; /* NEXT LINES ADDED TO BE COHERENT WITH OLE_follow_minichain ABOVE Serge Steer Scilab */ switch (current_sector) { case OLE_SECTORID_MSAT: case OLE_SECTORID_SAT: case OLE_SECTORID_ENDOFCHAIN: case OLE_SECTORID_FREE: break_out = 1; break; default: break_out = 0; }; /* Test changed Serge Steer Scilab */ /* } while ((current_sector != OLE_SECTORID_ENDOFCHAIN)&&(current_sector >= 0)&&(current_sector <= ole->last_sector)); */ } while (break_out == 0); } else { LOGGER_log(_("%s:%d:OLE_get_miniblock:ERROR: Failed to allocate enough memory for miniChain"), FL); } DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Done. buffer=%p", FL, buffer); return buffer; } /*-----------------------------------------------------------------\ Function Name : char Returns Type : unsigned ----Parameter List 1. *OLE_load_chain( struct OLE_object *ole, 2. int FAT_sector_start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: Make the loading aware of negative-value sectors so that it can make more intelligent exit strategies. \------------------------------------------------------------------*/ unsigned char *OLE_load_chain(struct OLE_object *ole, int FAT_sector_start) { int chain_length = 0; int current_sector = FAT_sector_start; unsigned char *buffer = NULL; unsigned char *bp = NULL; ole->last_chain_size = 0; if (FAT_sector_start < 0) { return NULL; } DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: Loading chain, starting at sector %d", FL, FAT_sector_start); chain_length = OLE_follow_chain(ole, FAT_sector_start); DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: %d sectors need to be loaded", FL, chain_length); if (chain_length > 0) { size_t offset; offset = ole->last_chain_size = chain_length << ole->header.sector_shift; bp = buffer = MALLOC((offset) * sizeof(unsigned char)); if (buffer == NULL) { LOGGER_log("%s:%d:OLE_load_chain:ERROR: Cannot allocate %d bytes for OLE chain", FL, offset); return NULL; } if (buffer != NULL) { int tick = 0; unsigned char *bp_limit; bp_limit = bp + offset; do { int next_sector; DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: Loading sector[%d] %d", FL, tick, current_sector); ole->error = OLE_get_block(ole, current_sector, bp); if (ole->error != OLE_OK) { /*FREE5 if (bp != NULL) FREE(bp); */ return NULL; } bp += ole->header.sector_size; if (bp > bp_limit) { if (buffer != NULL) { FREE(buffer); bp = buffer = NULL; } VOLE LOGGER_log(_("%s:%d:OLE_load_chain:ERROR: Load-chain went over memory boundary"), FL); return NULL; }; next_sector = get_4byte_value(ole->FAT + (LEN_ULONG * current_sector)); current_sector = next_sector; tick++; } while ((current_sector >= 0) && (current_sector <= ole->last_sector)); } } DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: Done loading chain", FL); return buffer; } /*-----------------------------------------------------------------\ Function Name : OLE_open_file Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. char *fullpath , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: 20041127-2033:PLD: Added ole->file_size setting so that we can use this in the sanity checking to see if the requested sectors are outside of the possible valid filesize range. \------------------------------------------------------------------*/ int OLE_open_file(struct OLE_object *ole, char *fullpath) { #ifdef _MSC_VER struct _stat st; #else struct stat st; #endif int stat_result; FILE *f; #ifdef _MSC_VER stat_result = wcstat(fullpath, &st); #else stat_result = stat(fullpath, &st); #endif if (stat_result != 0) { DOLE LOGGER_log(_("%s:%d:OLE_open_file:ERROR: Cannot locate file '%s' for opening (%s)"), FL, fullpath, strerror(errno)); return OLEER_BAD_INPUT_FILE; } DOLE LOGGER_log("%s:%d:OLE_open_file:DEBUG: File size of %s = %ld", FL, fullpath, st.st_size); if ((stat_result == 0) && (st.st_size < 512)) { return OLEER_NOT_OLE_FILE; } ole->file_size = st.st_size; wcfopen(f, fullpath, "rb"); if (f == NULL) { ole->f = NULL; if (ole->quiet == 0) { LOGGER_log(_("%s:%d:OLE_open_file:ERROR:Cannot open %s for reading (%s)\n"), FL, fullpath, strerror(errno)); } return -1; } else { ole->f = f; ole->file_size = st.st_size; ole->last_sector = -1; } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_open_directory Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. char *directory , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_open_directory(struct OLE_object *ole, char *directory) { int result = 0; #ifndef _MSC_VER result = mkdir(directory, S_IRWXU); #else { wchar_t *wdirectory = to_wide_string(directory); result = createdirectoryW(wdirectory); FREE(wdirectory); } /* If the function succeeds, the return value is nonzero. * If the function fails, the return value is zero. */ if (result) { result = 0; } #endif if ((result != 0) && (errno != EEXIST)) { LOGGER_log(_("%s:%d:OLE_open_directory:ERROR: %s"), FL, strerror(errno)); } else { result = OLE_OK; } return result; } /*-----------------------------------------------------------------\ Function Name : OLE_set_filename_report_fn Returns Type : int ----Parameter List 1. int (*ptr_to_fn)(char *) , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: This is merely a passthrough function to the OLEUW one, we do this in order to avoid having to force the calling parent from having to #include the OLEUW headers as well -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_filename_report_fn(struct OLE_object *ole, int (*ptr_to_fn) (char *)) { ole->filename_report_fn = ptr_to_fn; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_store_stream Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. char *stream_name, 3. char *directory, 4. unsigned char *stream , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_store_stream(struct OLE_object *ole, char *stream_name, char *directory, char *stream, size_t stream_size) { char *full_path = NULL; full_path = PLD_dprintf("%s/%s", directory, stream_name); if (full_path == NULL) { LOGGER_log(_("%s:%d:OLE_store_stream:ERROR: Cannot compose full filename string from '%s' and '%s'"), FL, directory, stream_name); return -1; } else { FILE *f; wcfopen(f, full_path, "wb"); if (f == NULL) { LOGGER_log(_("%s:%d:OLE_store_stream:ERROR: Cannot open %s for writing (%s)"), FL, full_path, strerror(errno)); if (full_path) { FREE(full_path); } return -1; } else { size_t written_bytes; written_bytes = fwrite(stream, 1, stream_size, f); if (written_bytes != stream_size) { LOGGER_log(_("%s:%d:OLE_store_stream:WARNING: Only wrote %d of %d bytes to file %s"), FL, written_bytes, stream_size, full_path); } fclose(f); if ((OLE_VNORMAL(ole->verbose)) && (ole->filename_report_fn != NULL)) { ole->filename_report_fn(stream_name); } } /* if file is valid */ } /* if full_path is valid */ if (full_path) { FREE(full_path); } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_decode_file_done Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_decode_file_done(struct OLE_object *ole) { if (ole->f) { fclose(ole->f); } /** Why weren't these active? (they were commented out ) **/ if (ole->FAT) { FREE(ole->FAT); } if (ole->miniFAT) { FREE(ole->miniFAT); } if (ole->ministream) { FREE(ole->ministream); } if (ole->properties) { FREE(ole->properties); } return 0; } /*-----------------------------------------------------------------\ Function Name : OLE_terminate_and_return Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int result , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_terminate_and_return(struct OLE_object *ole, int result) { OLE_decode_file_done(ole); return result; } #ifdef RIPOLE_WALK_TREE int OLE_walk_tree(struct OLE_object *ole, char *fname, char *decode_path, int depth) { /** Sanity check **/ if (depth > 100) { return 0; } if (ole->total_file_count > 10000) { return 0; } if (element_type < 0) { return 0; } switch (element_type) { case STGTY_ROOT: /** ROOT DIRECTORY ENTRY **/ /** ROOT DIRECTORY ENTRY **/ /** ROOT DIRECTORY ENTRY **/ DOLE LOGGER_log("%s:%d:OLE_walk_tree:DEBUG: Loading ministream/SmallBlockArray", FL); ole->ministream = OLE_load_chain(ole, adir->start_sector); if (ole->ministream == NULL) { return OLEER_MINISTREAM_READ_FAIL; } DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: ministream done", FL); } } else if (adir->element_type == STGTY_STORAGE) { /** STORAGE ELEMENT **/ /** STORAGE ELEMENT **/ /** STORAGE ELEMENT **/ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Item is directory, start child is at index %d\n", FL, i); ole->ministream = OLE_load_chain(ole, adir->start_sector); if (ole->ministream == NULL) { return OLEER_MINISTREAM_READ_FAIL; } DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: DIRECTORY ministream done", FL); } #endif int OLE_decode_stream(struct OLE_object *ole, struct OLE_directory_entry *adir, char *decode_path) { char *stream_data; struct OLEUNWRAP_object oleuw; int decode_result = OLEUW_STREAM_NOT_DECODED; char element_name[64]; int result = 0; memset(element_name, '\0', 64); OLE_dbstosbs(adir->element_name, adir->element_name_byte_count, element_name, 64); DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Decoding stream '%s'", FL, element_name); DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Initializing stream unwrapper", FL); OLEUNWRAP_init(&oleuw); OLEUNWRAP_set_debug(&oleuw, ole->debug); OLEUNWRAP_set_verbose(&oleuw, ole->verbose); OLEUNWRAP_set_filename_report_fn(&oleuw, ole->filename_report_fn); OLEUNWRAP_set_save_unknown_streams(&oleuw, ole->save_unknown_streams); DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Unwrap engine set.", FL); if (adir->stream_size >= ole->header.mini_cutoff_size) { /** Standard size sector stored stream **/ /** Standard size sector stored stream **/ /** Standard size sector stored stream **/ DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Loading normal sized chain starting at sector %d", FL, adir->start_sector); stream_data = (char *)OLE_load_chain(ole, adir->start_sector); if (stream_data == NULL) { DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Terminating from stream data being NULL ", FL); /*OLE_decode_file_done(ole); */ return OLEER_MINISTREAM_STREAM_READ_FAIL; } DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Normal decode START. element name ='%s' stream size = '%ld'", FL, element_name, adir->stream_size); decode_result = OLEUNWRAP_decodestream(&oleuw, element_name, stream_data, adir->stream_size, decode_path); DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Normal decode done.", FL); } else { /** Minichain/Minisector stored stream **/ /** Minichain/Minisector stored stream **/ /** Minichain/Minisector stored stream **/ DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Minichain loader, starting at sector %d", FL, adir->start_sector); stream_data = (char *)OLE_load_minichain(ole, adir->start_sector); if (stream_data == NULL) { DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Ministream was non-existant, terminating", FL); /*OLE_decode_file_done(ole); */ return OLEER_NORMALSTREAM_STREAM_READ_FAIL; } DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Mini decode START.", FL); decode_result = OLEUNWRAP_decodestream(&oleuw, element_name, stream_data, adir->stream_size, decode_path); DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Mini decode done.", FL); } /* Added for Scilab */ if ((stream_data != NULL) && (decode_result == OLEUW_STREAM_NOT_DECODED) && (ole->save_unknown_streams == 2) && ((strcmp(element_name, "Workbook") == 0) || (strcmp(element_name, "Book") == 0))) { strcpy(element_name, "Workbook"); OLE_store_stream(ole, element_name, decode_path, stream_data, adir->stream_size); } /* If we needed to save an unknown stream */ else /* end Scilab addition */ if ((stream_data != NULL) && (decode_result == OLEUW_STREAM_NOT_DECODED) && (ole->save_unknown_streams)) { char *lfname; lfname = PLD_dprintf("ole-stream.%d", adir->start_sector); if (lfname != NULL) { DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Saving stream to %s", FL, lfname); OLE_store_stream(ole, lfname, decode_path, stream_data, adir->stream_size); FREE(lfname); } } /* If we needed to save an unknown stream */ /* Clean up an stream_data which we may have */ /* read in from the chain-loader. */ if (stream_data) { FREE(stream_data); } return result; } /*-----------------------------------------------------------------\ Function Name : OLE_decode_file Returns Type : int ----Parameter List 1. char *fname, 2. char *decode_path , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_decode_file(struct OLE_object *ole, char *fname, char *decode_path) { unsigned char *current_property, *property_limit; int result = 0; int i; /* Reject any bad paramters. */ if (ole == NULL) { return OLEER_DECODE_NULL_OBJECT; } if (fname == NULL) { return OLEER_DECODE_NULL_FILENAME; } if (decode_path == NULL) { return OLEER_DECODE_NULL_PATH; } /* We need to gain access to the OLE2 data file, without */ /* this pretty much everything is pointless. */ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: opening %s", FL, fname); result = OLE_open_file(ole, fname); if (result != 0) { return result; } /* Try create the output directory which we're using */ /* to write the decoded files out to. */ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: opening output directory %s", FL, decode_path); result = OLE_open_directory(ole, decode_path); if (result != 0) { return result; } /* In order to successfully decode an OLE2 stream, we have to read */ /* and understand the first 512 bytes of the file, this is the */ /* OLE2 header. */ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Getting main header", FL); result = OLE_get_header(ole); if (result != 0) { return result; } DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Converting main header", FL); result = OLE_convert_header(ole); if (result != 0) { return result; } result = OLE_header_sanity_check(ole); if (result > 0) { return OLEER_INSANE_OLE_FILE; } DOLE OLE_print_header(ole); DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading FAT", FL); result = OLE_load_FAT(ole); if (result != 0) { return result; } DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading miniFAT chain", FL); ole->miniFAT = OLE_load_chain(ole, ole->header.mini_fat_start); /* commented out by Serge Steer for Scilab */ /* if (ole->miniFAT == NULL) return OLEER_MINIFAT_READ_FAIL; */ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading Directory stream chain", FL); ole->properties = OLE_load_chain(ole, ole->header.directory_stream_start_sector); if (ole->properties == NULL) { return OLEER_PROPERTIES_READ_FAIL; } i = 0; current_property = ole->properties; property_limit = current_property + ole->last_chain_size; /* while(1) */ while (current_property < property_limit) { struct OLE_directory_entry a_dir_object, *adir; int property_value = 0; adir = &a_dir_object; OLE_dir_init(adir); property_value = get_1byte_value(current_property); if (property_value < 1) { break; } DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG:--------- DIRECTORY INDEX: %d", FL, i); OLE_convert_directory(ole, current_property, adir); DOLE { LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Printing directory details...", FL); OLE_print_directory(ole, adir); LOGGER_log("%s:%d:OLE_decode_file:DEBUG: End of directory details", FL); } if (adir->element_colour > 1) { break; } if ((adir->element_type == STGTY_INVALID) || (adir->element_type > STGTY_ROOT)) { DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: breaking out due to element type %d", FL, adir->element_type); break; } else if (adir->element_type == STGTY_ROOT) { /** ROOT DIRECTORY ENTRY **/ /** ROOT DIRECTORY ENTRY **/ /** ROOT DIRECTORY ENTRY **/ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading ministream/SmallBlockArray", FL); ole->ministream = OLE_load_chain(ole, adir->start_sector); /* commented out by Serge Steer for Scilab */ /*if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL; */ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: ministream done", FL); } else if (adir->element_type == STGTY_STORAGE) { /** STORAGE ELEMENT **/ /** STORAGE ELEMENT **/ /** STORAGE ELEMENT **/ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Item is directory, start child is at index %d\n", FL, i); ole->ministream = OLE_load_chain(ole, adir->start_sector); /* commented out by Serge Steer for Scilab */ /*if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL; */ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: DIRECTORY ministream done", FL); } else if (adir->element_type == STGTY_STREAM) { /** STREAM ELEMENT **/ /** STREAM ELEMENT **/ /** STREAM ELEMENT **/ /* due to ole.c bugs we restrict here steams to decode to Workbooks (Excel) */ char element_name[64]; memset(element_name, '\0', 64); OLE_dbstosbs(adir->element_name, adir->element_name_byte_count, element_name, 64); if ((strcmp(element_name, "Workbook") == 0) || (strcmp(element_name, "Book") == 0)) { OLE_decode_stream(ole, adir, decode_path); } /*end of replacment code */ /* Original code */ /* OLE_decode_stream( ole, adir, decode_path ); */ } else { /** If the element isn't of the above types then it's possibly ** an empty element or just one used for the MSAT/SAT ** either way we just step over it and carry on **/ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Element type %d does not need to be handled", FL, adir->element_type); } /* Jump to the next property record, which */ /* is always 128 bytes ahead. */ current_property += 128; i++; } /* While there are still more directory entries to read in. */ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Finished", FL); /* * if (ole->f) fclose(ole->f); * fclose(ole->f); * if (ole->FAT) FREE(ole->FAT); * if (ole->miniFAT) FREE(ole->miniFAT); * if (ole->ministream) FREE(ole->ministream); * if (ole->properties) FREE(ole->properties); */ return OLE_OK; }