ole.c

Go to the documentation of this file.
00001 #ifdef _MSC_VER
00002 #include <Windows.h>
00003 #endif
00004 #include <stdio.h>
00005 #include <stdlib.h>
00006 #include <ctype.h>
00007 #include <string.h>
00008 #include <errno.h>
00009 #include <sys/stat.h>
00010 #include <sys/types.h>
00011 
00012 #include "logger.h"
00013 #include "pldstr.h"
00014 #include "bt-int.h"
00015 #include "bytedecoders.h"
00016 #include "olestream-unwrap.h"
00017 #include "ole.h"
00018 
00020 #define OLE_SECTORID_FREE       -1 
00021 #define OLE_SECTORID_ENDOFCHAIN -2 
00022 #define OLE_SECTORID_SAT        -3 
00023 #define OLE_SECTORID_MSAT       -4 
00025 #include "MALLOC.h" /* MALLOC */
00026 
00027 
00028 /* Main header accessors*/
00029 #define header_id(x)                                            ((x) +0)
00030 #define header_clid(x)                                  ((x) +0x08)
00031 #define header_minor_version(x)         ((x) +0x18)
00032 #define header_dll_version(x)                   ((x) +0x1a)
00033 #define header_byte_order(x)                    ((x) +0x1c)
00034 #define header_sector_shift(x)          ((x) +0x1e)
00035 #define header_mini_sector_shift(x)     ((x) +0x20)
00036 #define header_fat_sector_count(x)      ((x) +0x2c)
00037 #define header_directory_stream_start_sector(x) ((x) +0x30)
00038 #define header_mini_cutoff_size(x)      ((x) +0x38)
00039 #define header_mini_fat_start(x)                ((x) +0x3c)
00040 #define header_mini_fat_sector_count(x) ((x) +0x40)
00041 #define header_dif_start_sector(x)      ((x) +0x44)
00042 #define header_dif_sector_count(x)      ((x) +0x48)
00043 #define header_fat_sectors(x)                   ((x) +0x4c)
00044 
00045 /*Property Storage accessor macros*/
00046 #define pps_rawname(x)                          ((x) +0)
00047 #define pps_sizeofname(x)                       ((x) +0x40)
00048 #define pps_type(x)                                     ((x) +0x42)
00049 #define pps_previouspps(x)                      ((x) +0x44)
00050 #define pps_nextpps(x)                          ((x) +0x48)
00051 #define pps_directorypps(x)             ((x) +0x4c)
00052 #define pps_time1seconds(x)             ((x) +0x64)
00053 #define pps_time1days(x)                        ((x) +0x68)
00054 #define pps_time2seconds(x)             ((x) +0x6c)
00055 #define pps_time2days(x)                        ((x) +0x70)
00056 #define pps_propertystart(x)            ((x) +0x74)
00057 #define pps_sizeofproperty(x)           ((x) +0x78)
00058 
00059 /* Type lenghts*/
00060 #define LEN_BYTE        1
00061 #define LEN_USHORT 2
00062 #define LEN_ULONG       4
00063 
00064 /* Directory types*/
00065 #define STGTY_INVALID 0
00066 #define STGTY_STORAGE 1
00067 #define STGTY_STREAM 2
00068 #define STGTY_LOCKBYTES 3
00069 #define STGTY_PROPERTY 4
00070 #define STGTY_ROOT 5
00071 
00072 /* Directory tag colours*/
00073 #define DE_RED 0
00074 #define DE_BLACK 1
00075 
00076 #define DOLE    if (OLE_DNORMAL(ole->debug))
00077 #define VOLE    if (ole->verbose)
00078 
00079 
00080 unsigned char OLE_id_v2[]={ 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
00081 unsigned char OLE_id_v1[]={ 0x0e, 0x11, 0xfc, 0x0d, 0xd0, 0xcf, 0x11, 0xe0 };
00082 
00083 /*-----------------------------------------------------------------\
00084   Function Name : OLE_version
00085   Returns Type  : int
00086   ----Parameter List
00087   1. void , 
00088   ------------------
00089   Exit Codes    : 
00090   Side Effects  : 
00091   --------------------------------------------------------------------
00092   Comments:
00093 
00094   --------------------------------------------------------------------
00095   Changes:
00096 
00097   \------------------------------------------------------------------*/
00098 int OLE_version( void )
00099 {
00100   fprintf(stderr,"ripOLE: %s\n", LIBOLE_VERSION);
00101 
00102   return 0;
00103 }
00104 
00105 
00106 /*-----------------------------------------------------------------\
00107   Function Name : OLE_init
00108   Returns Type  : int
00109   ----Parameter List
00110   1. struct OLE_object *ole , 
00111   ------------------
00112   Exit Codes    : 
00113   Side Effects  : 
00114   --------------------------------------------------------------------
00115   Comments:
00116 
00117   --------------------------------------------------------------------
00118   Changes:
00119   20041127-2029:PLD: Added file_size initialization
00120   \------------------------------------------------------------------*/
00121 int OLE_init( struct OLE_object *ole )
00122 {
00123   ole->debug = 0;
00124   ole->verbose = 0;
00125   ole->quiet = 0;
00126   ole->filename_report_fn = NULL;
00127   ole->f = NULL;
00128   ole->file_size = 0;
00129 
00130   ole->FAT = NULL;
00131   ole->FAT_limit = NULL;
00132   ole->miniFAT = NULL;
00133   ole->miniFAT_limit = NULL;
00134 
00135   ole->header_block[0] = '\0';
00136   ole->ministream = NULL;
00137   ole->properties = NULL;
00138 
00139   ole->header.sector_shift = 0;
00140   ole->header.mini_sector_shift = 0;
00141 
00142   return OLE_OK;
00143 }
00144 
00145 /*-----------------------------------------------------------------\
00146   Function Name : OLE_dir_init
00147   Returns Type  : int
00148   ----Parameter List
00149   1. struct OLE_directory_entry *dir , 
00150   ------------------
00151   Exit Codes    : 
00152   Side Effects  : 
00153   --------------------------------------------------------------------
00154   Comments:
00155 
00156   --------------------------------------------------------------------
00157   Changes:
00158 
00159   \------------------------------------------------------------------*/
00160 int OLE_dir_init(struct OLE_directory_entry *dir )
00161 {
00162   memset(dir->element_name,'\0', OLE_DIRECTORY_ELEMENT_NAME_SIZE);
00163   dir->element_name_byte_count = 0;
00164 
00165   dir->element_type = 0;
00166   dir->element_colour = 0;
00167 
00168   dir->left_child = 0;
00169   dir->right_child = 0;
00170   dir->root = 0;
00171 
00172   dir->class[0] = '\0';
00173   dir->userflags = 0;
00174   dir->timestamps[0] = '\0';
00175   dir->start_sector = 0;
00176   dir->stream_size = 0;
00177 
00178   return 0;
00179 };
00180 
00181 /*-----------------------------------------------------------------\
00182   Function Name : OLE_set_verbose
00183   Returns Type  : int
00184   ----Parameter List
00185   1. struct OLE_object *ole, 
00186   2.  int level , 
00187   ------------------
00188   Exit Codes    : 
00189   Side Effects  : 
00190   --------------------------------------------------------------------
00191   Comments:
00192 
00193   --------------------------------------------------------------------
00194   Changes:
00195 
00196   \------------------------------------------------------------------*/
00197 int OLE_set_verbose( struct OLE_object *ole, int level )
00198 {
00199   ole->verbose = level;
00200   return OLE_OK;
00201 }
00202 
00203 
00204 
00205 /*-----------------------------------------------------------------\
00206   Function Name : OLE_set_quiet
00207   Returns Type  : int
00208   ----Parameter List
00209   1. struct OLE_object *ole, 
00210   2.  int level , 
00211   ------------------
00212   Exit Codes    : 
00213   Side Effects  : 
00214   --------------------------------------------------------------------
00215   Comments:
00216 
00217   --------------------------------------------------------------------
00218   Changes:
00219 
00220   \------------------------------------------------------------------*/
00221 int OLE_set_quiet( struct OLE_object *ole, int level )
00222 {
00223   ole->quiet = level;
00224   ole->verbose = 0;
00225   ole->debug = 0;
00226 
00227   return OLE_OK;
00228 }
00229 
00230 
00231 /*-----------------------------------------------------------------\
00232   Function Name : OLE_set_debug
00233   Returns Type  : int
00234   ----Parameter List
00235   1. struct OLE_object *ole, 
00236   2.  int level , 
00237   ------------------
00238   Exit Codes    : 
00239   Side Effects  : 
00240   --------------------------------------------------------------------
00241   Comments:
00242 
00243   --------------------------------------------------------------------
00244   Changes:
00245 
00246   \------------------------------------------------------------------*/
00247 int OLE_set_debug( struct OLE_object *ole, int level )
00248 {
00249   ole->debug = level;
00250   if (ole->debug > 0) LOGGER_log("%s:%d:OLE_set_debug: Debug level set to %d",FL, ole->debug);
00251 
00252   return OLE_OK;
00253 }
00254 
00255 
00256 /*-----------------------------------------------------------------\
00257   Function Name : OLE_set_save_unknown_streams
00258   Returns Type  : int
00259   ----Parameter List
00260   1. struct OLE_object  *ole, 
00261   2.  int level , 
00262   ------------------
00263   Exit Codes    : 
00264   Side Effects  : 
00265   --------------------------------------------------------------------
00266   Comments:
00267 
00268   --------------------------------------------------------------------
00269   Changes:
00270 
00271   \------------------------------------------------------------------*/
00272 int OLE_set_save_unknown_streams( struct OLE_object  *ole, int level )
00273 {
00274   ole->save_unknown_streams = level;
00275 
00276   return OLE_OK;
00277 }
00278 
00279 
00280 /*-----------------------------------------------------------------\
00281   Function Name : OLE_sectorpos
00282   Returns Type  : int
00283   ----Parameter List
00284   1. struct OLE_object *ole, 
00285   2.  int SID , 
00286   ------------------
00287   Exit Codes    : 
00288   Side Effects  : 
00289   --------------------------------------------------------------------
00290   Comments:
00291   Given a sector ID, this function will return the file position
00292   offset.
00293 
00294   Assumes that the offset for the file starts at 512 bytes (which
00295   is the size of the OLE header)
00296 
00297   --------------------------------------------------------------------
00298   Changes:
00299 
00300   \------------------------------------------------------------------*/
00301 int OLE_sectorpos( struct OLE_object *ole, int SID )
00302 {
00303   int pos = 0;
00304 
00305   pos = 512 +(SID *ole->header.sector_size);
00306 
00307   return pos;
00308 }
00309 
00310 
00311 /*-----------------------------------------------------------------\
00312   Function Name : OLE_get_block
00313   Returns Type  : int
00314   ----Parameter List
00315   1. struct OLE_object *ole, 
00316   2.  int block_index,  Block indexes / Sector ID's are signed ints.
00317   3.  unsigned char *block_buffer , 
00318   ------------------
00319   Exit Codes    : 
00320   Side Effects  : 
00321   --------------------------------------------------------------------
00322   Comments:
00323 
00324   --------------------------------------------------------------------
00325   Changes:
00326 
00327   \------------------------------------------------------------------*/
00328 int OLE_get_block( struct OLE_object *ole, int block_index, unsigned char *block_buffer )
00329 {
00330   if (block_buffer == NULL)
00331     {
00332       LOGGER_log("%s:%d:OLE_get_block:ERROR: Block buffer is NULL",FL);
00333       return -1;
00334     }
00335 
00336   if (ole->f != NULL)
00337     {
00338       int read_count = 0;
00339       int fseek_result = 0;
00340       size_t offset = 0;
00341       unsigned char *bb = NULL;
00342 
00343       bb = MALLOC(sizeof(unsigned char) *ole->header.sector_size);
00344       if (bb == NULL)
00345         {
00346           LOGGER_log("%s:%d:OLE_get_block:ERROR: Cannot allocate %d bytes for OLE block",FL, ole->header.sector_size);
00347           return -1;
00348         }
00349 
00350       DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: BlockIndex=%d, Buffer=0x%x",FL, block_index, block_buffer);
00351 
00352       /*20051211-2343:PLD: offset = (block_index +1) << ole->header.sector_shift;*/
00353       offset = OLE_sectorpos(ole, block_index);
00354 
00355       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);
00356 
00357       fseek_result = fseek(ole->f, offset, SEEK_SET);
00358       if (fseek_result != 0)
00359         {
00360           if (bb != NULL) { FREE(bb); bb = NULL; }
00361           LOGGER_log("%s:%d:OLE_get_block:ERROR: Seek failure (block=%d:%d)",FL, block_index,offset, strerror(errno));
00362           return OLEER_GET_BLOCK_SEEK;
00363         }
00364 
00365       /*read_count = fread(block_buffer, sizeof(unsigned char), ole->header.sector_size, ole->f);*/
00366       read_count = fread(bb, sizeof(unsigned char), ole->header.sector_size, ole->f);
00367       DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Read %d byte of data",FL,read_count);
00368       if (read_count != (int)ole->header.sector_size)
00369         {
00370           if (bb != NULL){ FREE(bb); bb = NULL; }
00371           VOLE LOGGER_log("%s:%d:Mismatch in bytes read. Requested %d, got %d\n", FL, ole->header.sector_size, read_count);
00372           return OLEER_GET_BLOCK_READ;
00373         }
00374 
00375       DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Copying over memory read from file",FL);
00376 
00377       memcpy(block_buffer, bb, ole->header.sector_size);
00378 
00379       DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: memory block copied to block_buffer",FL);
00380 
00381       /* We're now done with BB, dispose of it */
00382       if (bb) { FREE(bb); bb = NULL; }
00383 
00384       DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Disposed of temporary bb block",FL);
00385 
00386     } else {
00387       LOGGER_log("%s:%d:OLE_get_block:ERROR: OLE file is closed\n",FL);
00388       return -1;
00389     }
00390 
00391   DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Done",FL);
00392 
00393   return OLE_OK;
00394 }
00395 
00396 
00397 /*-----------------------------------------------------------------\
00398   Function Name : OLE_get_miniblock
00399   Returns Type  : int
00400   ----Parameter List
00401   1. struct OLE_object *ole, 
00402   2.  unsigned int block_index, 
00403   3.  unsigned char *block_buffer , 
00404   ------------------
00405   Exit Codes    : 
00406   Side Effects  : 
00407   --------------------------------------------------------------------
00408   Comments:
00409 
00410   --------------------------------------------------------------------
00411   Changes:
00412 
00413   \------------------------------------------------------------------*/
00414 int OLE_get_miniblock( struct OLE_object *ole, int block_index, unsigned char *block_buffer )
00415 {
00416   /* This code may refer memory outside of the allocated one for  ole->ministream *
00417      in case of VBA Streams Serge Steer 26/01/2007*/
00418   if (ole->ministream)
00419     {
00420       int offset = block_index << ole->header.mini_sector_shift;
00421       memcpy( block_buffer, ole->ministream +offset, ole->header.mini_sector_size);
00422     }
00423 
00424   return OLE_OK;
00425 }
00426 
00427 
00428 /*-----------------------------------------------------------------\
00429   Function Name : OLE_dbstosbs
00430   Returns Type  : int
00431   ----Parameter List
00432   1. char *raw_string, 
00433   2.  size_t char_count, 
00434   3.  char *clean_string , 
00435   ------------------
00436   Exit Codes    : 
00437   Side Effects  : 
00438   --------------------------------------------------------------------
00439   Comments:
00440 
00441   --------------------------------------------------------------------
00442   Changes:
00443 
00444   \------------------------------------------------------------------*/
00445 int OLE_dbstosbs( char *raw_string, size_t byte_count, char *clean_string, int clean_string_len )
00446 {
00447   char *limit = raw_string +byte_count -1;
00448 
00449   clean_string_len--;
00450 
00451   while ((raw_string < limit)&&(byte_count >0)&&(byte_count--)&&(clean_string_len--))
00452     {
00453       int v = (char)*raw_string;
00454 
00455       if (isprint(v))
00456         {
00457           *clean_string = v;
00458           clean_string++;
00459         }
00460 
00461       raw_string += 2;
00462     }
00463   *clean_string = '\0';
00464 
00465   return OLE_OK;
00466 }
00467 
00468 /*-----------------------------------------------------------------\
00469   Function Name : OLE_print_string
00470   Returns Type  : int
00471   ----Parameter List
00472   1. char *string, 
00473   2.  size_t length , 
00474   ------------------
00475   Exit Codes    : 
00476   Side Effects  : 
00477   --------------------------------------------------------------------
00478   Comments:
00479 
00480   --------------------------------------------------------------------
00481   Changes:
00482 
00483   \------------------------------------------------------------------*/
00484 int OLE_print_string( char *string, size_t char_count)
00485 {
00486   while (char_count--)
00487     {
00488       printf("%c",*string);
00489       string += 2;
00490     }
00491   return OLE_OK;
00492 }
00493 /*-----------------------------------------------------------------\
00494   Function Name : OLE_print_sector
00495   Returns Type  : int
00496   ----Parameter List
00497   1. struct OLE_object *ole, 
00498   2.  unsigned char *sector , 
00499   ------------------
00500   Exit Codes    : 
00501   Side Effects  : 
00502   --------------------------------------------------------------------
00503   Comments:
00504 
00505   --------------------------------------------------------------------
00506   Changes:
00507 
00508   \------------------------------------------------------------------*/
00509 int OLE_print_sector( struct OLE_object *ole, char *sector, unsigned int bytes)
00510 {
00511   int current_byte;
00512   int ubytes = bytes;
00513 
00514   printf("\n");
00515   for (current_byte = 0; current_byte < ubytes; current_byte++ )
00516     {
00517       printf("%02X ", *(sector +current_byte));
00518       if (((current_byte+1) %32)==0) {
00519         int j;
00520         for (j = current_byte -31; j <=current_byte; j++)
00521           {
00522             if (isalnum(*(sector +j))) printf("%c",*(sector+j));
00523             else printf(".");
00524           }
00525         printf("\n");
00526       }
00527     }
00528   printf("\n");
00529 
00530   return OLE_OK;
00531 }
00532 
00533 /*-----------------------------------------------------------------\
00534   Function Name : OLE_is_OLE_file
00535   Returns Type  : int
00536   ----Parameter List
00537   1. struct OLE_object *ole , 
00538   ------------------
00539   Exit Codes    : 
00540   Side Effects  : 
00541   --------------------------------------------------------------------
00542   Comments:
00543 
00544   --------------------------------------------------------------------
00545   Changes:
00546 
00547   \------------------------------------------------------------------*/
00548 int OLE_is_file_OLE( struct OLE_object *ole )
00549 {
00550 
00551   if (memcmp(OLE_id_v1, ole->header_block, sizeof(OLE_id_v1))==0) return 1;
00552   if (memcmp(OLE_id_v2, ole->header_block, sizeof(OLE_id_v2))==0) return 1;
00553 
00554   return 0;
00555 
00556 }
00557 
00558 /*-----------------------------------------------------------------\
00559   Function Name : OLE_get_header
00560   Returns Type  : int
00561   ----Parameter List
00562   1. struct OLE_object *ole , 
00563   ------------------
00564   Exit Codes    : 
00565   Side Effects  : 
00566   --------------------------------------------------------------------
00567   Comments:
00568 
00569   --------------------------------------------------------------------
00570   Changes:
00571 
00572   \------------------------------------------------------------------*/
00573 int OLE_get_header( struct OLE_object *ole )
00574 {
00575   int result = 0;
00576   ole->header.sector_size = OLE_HEADER_BLOCK_SIZE;
00577   result = OLE_get_block( ole, -1, ole->header_block );
00578 
00579   if (OLE_is_file_OLE( ole ) == 0)
00580     {
00581       return OLEER_NOT_OLE_FILE;
00582     }
00583 
00584   return OLE_OK;
00585 }
00586 
00587 /*-----------------------------------------------------------------\
00588   Function Name : OLE_convert_header
00589   Returns Type  : int
00590   ----Parameter List
00591   1. struct OLE_object *ole , 
00592   ------------------
00593   Exit Codes    : 
00594   Side Effects  : 
00595   --------------------------------------------------------------------
00596   Comments:
00597 
00598   --------------------------------------------------------------------
00599   Changes:
00600 
00601   \------------------------------------------------------------------*/
00602 int OLE_convert_header( struct OLE_object *ole )
00603 {
00604   struct OLE_header *h;
00605   unsigned char *hb; 
00606   unsigned char *fat_start;
00607   unsigned int i;
00608 
00609   h = &(ole->header);
00610   hb = ole->header_block;
00611 
00618   h->minor_version = get_2byte_value(header_minor_version(hb));
00619   h->dll_version = get_2byte_value(header_dll_version(hb));
00620   h->byte_order = get_2byte_value(header_byte_order(hb)); 
00621   h->sector_shift = get_2byte_value(header_sector_shift(hb));
00622   h->sector_size = 1 << h->sector_shift;
00623 
00624   h->mini_sector_shift = get_2byte_value(header_mini_sector_shift(hb));
00625   h->mini_sector_size = 1 << h->mini_sector_shift;
00626 
00627   h->fat_sector_count = get_4byte_value(header_fat_sector_count(hb)); 
00628   h->directory_stream_start_sector = get_4byte_value(header_directory_stream_start_sector(hb)); 
00629   h->mini_cutoff_size = get_4byte_value(header_mini_cutoff_size(hb)); 
00630   h->mini_fat_start = get_4byte_value(header_mini_fat_start(hb));
00631   h->mini_fat_sector_count = get_4byte_value(header_mini_fat_sector_count(hb));
00632   h->dif_start_sector = get_4byte_value(header_dif_start_sector(hb));
00633   h->dif_sector_count = get_4byte_value(header_dif_sector_count(hb));
00634 
00639   ole->last_sector = ole->file_size  >> h->sector_shift;
00640 
00642   fat_start = header_fat_sectors(hb);
00643   for (i = 0; i < h->fat_sector_count; i++)
00644     {
00645       if (i >= OLE_HEADER_FAT_SECTOR_COUNT_LIMIT) break;
00646       h->FAT[i] = get_4byte_value( fat_start +(LEN_ULONG *i));
00647     }
00648 
00649   return OLE_OK;
00650 }
00651 
00652 
00653 /*-----------------------------------------------------------------\
00654   Function Name : OLE_header_sanity_check
00655   Returns Type  : int
00656   ----Parameter List
00657   1. struct OLE_object *ole , 
00658   ------------------
00659   Exit Codes    : 
00660   Side Effects  : 
00661   --------------------------------------------------------------------
00662   Comments:
00663   Determines the degree of insanity in the header, returning it
00664   as an integer, 1 per degree of insanity.
00665 
00666   --------------------------------------------------------------------
00667   Changes:
00668   20041127-2027:PLD: Initial version
00669 
00670   \------------------------------------------------------------------*/
00671 int OLE_header_sanity_check( struct OLE_object *ole )
00672 {
00673   int insanity=0;
00674   int max_sectors;
00675   struct OLE_header *h;
00676 
00677   h = &(ole->header);
00678 
00679   max_sectors = ole->file_size / h->sector_size;
00680 
00681   if (h->sector_shift > 20) insanity++;
00682   if (h->mini_sector_shift > 10) insanity++;
00683   if (h->fat_sector_count < 0) insanity++;
00684   if (h->fat_sector_count > (unsigned int)max_sectors) insanity++;
00685   if (h->directory_stream_start_sector > (unsigned int) max_sectors) insanity++;
00686 
00687   return insanity;
00688 }
00689 
00690 
00691 /*-----------------------------------------------------------------\
00692   Function Name : OLE_print_header
00693   Returns Type  : int
00694   ----Parameter List
00695   1. struct OLE_object *ole , 
00696   ------------------
00697   Exit Codes    : 
00698   Side Effects  : 
00699   --------------------------------------------------------------------
00700   Comments:
00701 
00702   --------------------------------------------------------------------
00703   Changes:
00704 
00705   \------------------------------------------------------------------*/
00706 int OLE_print_header( struct OLE_object *ole )
00707 {
00708   unsigned int i;
00709   struct OLE_header *h;
00710 
00711   h = &(ole->header);
00712 
00713   printf( "Minor version = %d\n"
00714           "DLL version = %d\n"
00715           "Byte order = %d\n\n"
00716 
00717           "Sector shift = %d\n"
00718           "Sector size  = %d\n"
00719           "Mini Sector shift = %d\n"
00720           "Mini sector size  = %d\n\n"
00721 
00722           "FAT sector count = %d\n"
00723           "First FAT sector = %d\n\n"
00724 
00725           "Maximum ministream size = %d\n\n"
00726 
00727           "First MiniFAT sector = %d\n"
00728           "MiniFAT sector count = %d\n\n"
00729 
00730           "First DIF sector = %d\n"
00731           "DIF sector count = %d\n"
00732           "--------------------------------\n"
00733           ,h->minor_version
00734           ,h->dll_version
00735           ,h->byte_order
00736           ,h->sector_shift
00737           ,h->sector_size
00738           ,h->mini_sector_shift
00739           ,h->mini_sector_size
00740           ,h->fat_sector_count
00741           ,h->directory_stream_start_sector
00742           ,h->mini_cutoff_size
00743           ,h->mini_fat_start
00744           ,h->mini_fat_sector_count
00745           ,h->dif_start_sector
00746           ,h->dif_sector_count
00747           );
00748 
00749   /* Print out the FAT chain*/
00750   for (i = 0; i < h->fat_sector_count; i++)
00751     {
00752       if (i >= OLE_HEADER_FAT_SECTOR_COUNT_LIMIT) break; /* We can't read beyond the 109th sector location*/
00753       printf("FAT[%d] = %d\n", i, h->FAT[i]);
00754     }
00755 
00756   return OLE_OK;
00757 }
00758 
00759 
00760 /*-----------------------------------------------------------------\
00761   Function Name : OLE_convert_directory
00762   Returns Type  : int
00763   ----Parameter List
00764   1. unsigned char *buf, 
00765   2.  struct OLE_directory_entry *dir , 
00766   ------------------
00767   Exit Codes    : 
00768   Side Effects  : 
00769   --------------------------------------------------------------------
00770   Comments:
00771 
00772   --------------------------------------------------------------------
00773   Changes:
00774 
00775   \------------------------------------------------------------------*/
00776 int OLE_convert_directory( struct OLE_object *ole, unsigned char *buf, struct OLE_directory_entry *dir )
00777 {
00783   memset( dir->element_name, '\0', OLE_DIRECTORY_ELEMENT_NAME_SIZE);
00784 
00791   memcpy( dir->element_name, buf, OLE_DIRECTORY_ELEMENT_NAME_SIZE );
00792 
00797   dir->element_name_byte_count = get_2byte_value( buf + 0x40 );
00798 
00807   dir->element_type = get_1byte_value( buf +0x42 );
00808 
00813   dir->element_colour = get_1byte_value( buf +0x43 );
00814 
00816   dir->left_child = get_4byte_value( buf +0x44 );
00817 
00819   dir->right_child = get_4byte_value( buf +0x48 );
00820 
00821 
00825   dir->root = get_4byte_value( buf +0x4c );
00826 
00827   memcpy( dir->class, buf +0x50, 16 );
00828   dir->userflags = get_4byte_value( buf +0x60 );
00829   memcpy( dir->timestamps, buf +0x64, 16 ); 
00832   dir->start_sector = get_4byte_value( buf +0x74 );
00833 
00835   DOLE LOGGER_log("%s:%d:OLE_directory_entry:DEBUG: stream size = 0x%x %x %x %x"
00836                   ,FL
00837                   ,*(buf +0x78)
00838                   ,*(buf +0x79)
00839                   ,*(buf +0x7A)
00840                   ,*(buf +0x7B)
00841                   );
00842   dir->stream_size = get_4byte_value( buf +0x78 );
00843 
00844   return OLE_OK;
00845 }
00846 
00847 /*-----------------------------------------------------------------\
00848   Function Name : OLE_print_directory
00849   Returns Type  : int
00850   ----Parameter List
00851   1. struct OLE *ole, 
00852   2.  struct OLE_directory_entry *dir , 
00853   ------------------
00854   Exit Codes    : 
00855   Side Effects  : 
00856   --------------------------------------------------------------------
00857   Comments:
00858 
00859   --------------------------------------------------------------------
00860   Changes:
00861 
00862   \------------------------------------------------------------------*/
00863 int OLE_print_directory( struct OLE_object *ole, struct OLE_directory_entry *dir )
00864 {
00865   char element[64];
00866   OLE_dbstosbs( dir->element_name, dir->element_name_byte_count, element, sizeof(element) );
00867 
00868   printf(
00869          "Element Name = %s\n"
00870          "Element type = %d\n"
00871          "Element colour = %d\n"
00872          "Left Child = %d\n"
00873          "Right Child = %d\n"
00874          "Root = %d\n"
00875          "User flags = %d\n"
00876          "Start sector = %d\n"
00877          "Stream Size = %d\n"
00878          ,element
00879          ,dir->element_type
00880          ,dir->element_colour
00881          ,dir->left_child
00882          ,dir->right_child
00883          ,dir->root
00884          ,dir->userflags
00885          ,dir->start_sector
00886          ,dir->stream_size
00887          );
00888 
00889   return OLE_OK;
00890 }
00891 
00892 
00893 /*-----------------------------------------------------------------\
00894   Function Name : OLE_load_FAT
00895   Returns Type  : int
00896   ----Parameter List
00897   1. struct OLE_object *ole , 
00898   ------------------
00899   Exit Codes    : 
00900   Side Effects  : 
00901   --------------------------------------------------------------------
00902   Comments:
00903 
00904   --------------------------------------------------------------------
00905   Changes:
00906 
00907   \------------------------------------------------------------------*/
00908 int OLE_load_FAT( struct OLE_object *ole )
00909 {
00910   unsigned int FAT_size;
00911 
00912   FAT_size = ole->header.fat_sector_count << ole->header.sector_shift;
00913   DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG:Allocating for %d sectors (%d bytes) \n"
00914                   ,FL,ole->header.fat_sector_count, FAT_size);
00915 
00916   ole->FAT = MALLOC( FAT_size *sizeof(unsigned char));
00917   ole->FAT_limit = ole->FAT +FAT_size;
00918   if (ole->FAT != NULL)
00919     {
00920       unsigned int i;
00921       unsigned char *fat_position = ole->FAT;
00922       unsigned int sector_count = ole->header.fat_sector_count;
00923 
00924       if (sector_count > OLE_HEADER_FAT_SECTOR_COUNT_LIMIT)
00925         {
00926           sector_count = OLE_HEADER_FAT_SECTOR_COUNT_LIMIT;
00927           DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: sector count greater than limit; set to %d",FL, sector_count);
00928         }
00929 
00930       /* Load in all our primary-FAT sectors from the OLE file*/
00931       for (i = 0; i < sector_count; i++)
00932         {
00933           int getblock_result = 0;
00934 
00935           DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Loading sector %d",FL, i);
00936           getblock_result = OLE_get_block(ole, ole->header.FAT[i], fat_position);
00937           if (getblock_result != 0)
00938             {
00939               /* if the get block fails, return the error - but keep the FAT*/
00940               /*                pointer alive - so that we can facilitate debugging*/
00941               /*                otherwise the caller is always going to get a NULL pointer*/
00942               /*                and have no idea to what extent the data was read.*/
00943               
00944               /* This behavior may be changed later - but for now (beta development)*/
00945               /*                it'll be okay to leave it here - just make sure we know to*/
00946               /*                free the FAT block later.*/
00947 
00948               return getblock_result;
00949             }
00950 
00951           fat_position += ole->header.sector_size;
00952           if (fat_position > ole->FAT_limit)
00953             { 
00954               LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: FAT boundary limit exceeded %p > %p", FL, fat_position, ole->FAT_limit); 
00955               return -1;
00956             }
00957         }
00958 
00959       /* If our DIF count is > 0, this means we have a pretty big*/
00960       /*                file on hand (> 7Mb) and thus we now have to do some*/
00961       /*                fancy double-dereferenced sector request - enough to */
00962       /*                twist your brain if you're not alert, you have been*/
00963       /*                warned.*/
00964 
00965       if (ole->header.dif_sector_count > 0)
00966         {
00967           unsigned char *fat_block;
00968           unsigned char *fat_block_end;
00969           unsigned int current_sector = ole->header.dif_start_sector;
00970 
00971           DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Allocating %d bytes to fat_block\n",FL, ole->header.sector_size);
00972 
00973           fat_block = MALLOC( ole->header.sector_size );
00974 
00975           if (fat_block == NULL) 
00976             {
00977               LOGGER_log("%s:%d:OLE_load_FAT:ERROR: Unable to allocate %d bytes\n", FL, ole->header.sector_size);
00978               return -1;
00979               /*                        exit(1);*/
00980             }
00981 
00982           /* We need to know where the end of this block is - because it's*/
00983           /*            used to show us where the NEXT FAT block is going to come from*/
00984           /*            NOTE - this only occurs if we do have another block, else */
00985           /*            we'll simply have to just realise that we don't need any more*/
00986           /*            blocks and stop with this one.*/
00987 
00988           fat_block_end = fat_block +ole->header.sector_size -LEN_ULONG;
00989 
00990           /* We know we've got 'dif_sector_count' blocks to read, each of*/
00991           /*            these blocks hold no more than 127 sector addresses which*/
00992           /*            contain the actual FAT data we're after (this is the double*/
00993           /*            dereference bit that twists your brain )*/
00994 
00995           DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Loading DIF sectors (count = %d)",FL,ole->header.dif_sector_count);
00996 
00997           for (i = 0; i < ole->header.dif_sector_count; i++)
00998             {
00999               int import_sector;
01000               unsigned char *DIF = fat_block;
01001               int tick = 0;
01002               int getblock_result;
01003 
01004               DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Reading DIF/XBAT index-data[%d] from sector 0x%x",FL,i,current_sector);
01005               getblock_result = OLE_get_block(ole, current_sector, fat_block);
01006               if (getblock_result != OLE_OK)
01007                 {
01008                   if (fat_block) FREE(fat_block);
01009                   return getblock_result;
01010                 }
01011 
01012               if (OLE_DPEDANTIC(ole->debug)) OLE_print_sector(ole, fat_block, ole->header.sector_size);
01013 
01014               /* Now, traverse this block until we hit a < 0*/
01015               /*                If we get what is a non-valid sector value*/
01016               /*                we know we've reached the end of the valid*/
01017               /*                sectors from which to read more extended FAT*/
01018               /*                data.*/
01019 
01020               do {
01021                 import_sector = get_4byte_value( DIF );
01022                 DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: import sector = 0x%x",FL,import_sector);
01023                 if (import_sector >= 0)
01024                   {
01025                     if (fat_position +ole->header.sector_size <= ole->FAT_limit)
01026                       {
01027                         DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Reading DIF/XBAT-data[%d] from sector 0x%x",FL,tick,import_sector);
01028                         getblock_result = OLE_get_block(ole, import_sector, fat_position);
01029                         if (getblock_result != OLE_OK)
01030                           {
01031                             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);
01032                             if (fat_block) FREE(fat_block);
01033                             return getblock_result;
01034                           }
01035 
01036                         fat_position += ole->header.sector_size;
01037                         DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: FAT position = 0x%x (start = 0x%x, end = 0x%x)"
01038                                         ,FL
01039                                         ,fat_position
01040                                         ,fat_block
01041                                         ,ole->FAT_limit
01042                                         );
01043 
01044                         /*if (fat_position +ole->header.sector_size > ole->FAT_limit)*/
01045                         if (fat_position > ole->FAT_limit)
01046                           { 
01047                             DOLE LOGGER_log("%s:%d:OLE_load_FAT:ERROR: FAT memory boundary limit exceeded %p >= %p",FL,fat_position,ole->FAT_limit); 
01048                             if (fat_block) FREE(fat_block);
01049                             return OLEER_MEMORY_OVERFLOW;
01050                           }
01051                         tick++;
01052                         DIF += LEN_ULONG;
01053                       }  else {
01054                         LOGGER_log("%s:%d:OLE_load_FAT:ERROR: FAT memory boundary limit exceeded %p >= %p",FL,fat_position,ole->FAT_limit); 
01055                         if (fat_block) FREE(fat_block);
01056                         return OLEER_MEMORY_OVERFLOW;
01057                       }
01058                   } else {
01059                     VOLE LOGGER_log("%s:%d:OLE_load_FAT:ERROR: sector request was negative (%d)",FL, import_sector);
01060                   }
01061 
01062                 DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: DIF = 0x%x",FL,DIF);
01063               } while ((import_sector >= 0)&&(DIF < fat_block_end));
01064 
01065               /* Get the next sector of DIF/XBAT data ...*/
01066               
01067               /* If we still have more sectors full of extended FAT*/
01068               /*                sectors that we have to read, then we neet to*/
01069               /*                obtain the address of the next FAT-sector filled*/
01070               /*                sector*/
01071 
01072               if ( i < ole->header.dif_sector_count -1 )
01073                 {
01074                   current_sector = get_4byte_value( fat_block_end );
01075                   DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Next DIF/XBAT index sector located at 0x%x",FL,current_sector);
01076                   if (current_sector < 0) break;
01077                 }
01078             } /* For every DIF/XBAT sector we're supposed to read*/
01079 
01080           if (fat_block) FREE(fat_block);
01081         } /* If we have DIF/XBAT sectors to read into the FAT*/
01082 
01083     } /* If we managed to allocate memory for our FAT table*/
01084 
01085   return OLE_OK;
01086 }
01087 
01088 
01089 
01090 /*-----------------------------------------------------------------\
01091   Function Name : OLE_follow_chain
01092   Returns Type  : int
01093   ----Parameter List
01094   1. struct OLE_object *ole, 
01095   2.  int FAT_sector_start , 
01096   ------------------
01097   Exit Codes    : 
01098   Side Effects  : 
01099   --------------------------------------------------------------------
01100   Comments:
01101 
01102   --------------------------------------------------------------------
01103   Changes:
01104 
01105   \------------------------------------------------------------------*/
01106 int OLE_follow_chain( struct OLE_object *ole, int FAT_sector_start )
01107 {
01108   int current_sector = FAT_sector_start;
01109   int chain_length=0;
01110   int last_sector_of_file = ole->last_sector;
01111   int break_out = 0;
01112   struct bti_node *n;
01113 
01114   BTI_init(&n);
01115 
01116   if (FAT_sector_start < 0) return 0;
01117 
01118   DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: Starting chain follow at sector %d",FL, FAT_sector_start );
01119 
01120   do {
01121     int next_sector;
01122     unsigned char *next_sector_location;
01123 
01124     next_sector_location = ole->FAT +(LEN_ULONG *current_sector);
01125     if (next_sector_location > (ole->FAT_limit -4)) {
01126       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);
01127       break;
01128     }
01129 
01130     /*next_sector = get_4byte_value( ole->FAT +(LEN_ULONG *current_sector));*/
01131     next_sector = get_4byte_value( next_sector_location );
01132 
01133     if (BTI_add(&n, next_sector) != 0)
01134       {
01135         DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: Sector collision, terminating chain traversal",FL);
01136         chain_length=-1;
01137 
01138         break;
01139       }
01140 
01141     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);
01142 
01143     /* 20040729-10H37 Added this to prevent endless loop which sometimes occurs at sector 0*/
01144 
01145     if (next_sector == current_sector) break;
01146 
01147     /*          fflush(stdout);*/
01148     current_sector = next_sector;
01149     chain_length++;
01150 
01152     switch (current_sector) {
01153     case OLE_SECTORID_MSAT:
01154     case OLE_SECTORID_SAT:
01155     case OLE_SECTORID_ENDOFCHAIN:
01156     case OLE_SECTORID_FREE:
01157       break_out=1;
01158       break;
01159     default:
01160       break_out=0;
01161     };
01162                  
01163     if (current_sector < 0) break_out = 1;
01164 
01165   } while ((break_out==0)&&(current_sector < last_sector_of_file));
01166 
01167   BTI_done(&n);
01168 
01169   return chain_length;
01170 }
01171 
01172 /*-----------------------------------------------------------------\
01173   Function Name : OLE_follow_minichain
01174   Returns Type  : int
01175   ----Parameter List
01176   1. struct OLE_object *ole, 
01177   2.  int FAT_sector_start , 
01178   ------------------
01179   Exit Codes    : 
01180   Side Effects  : 
01181   --------------------------------------------------------------------
01182   Comments:
01183 
01184   --------------------------------------------------------------------
01185   Changes:
01186 
01187   \------------------------------------------------------------------*/
01188 int OLE_follow_minichain( struct OLE_object *ole, int miniFAT_sector_start )
01189 {
01190   /*unsigned int current_sector = miniFAT_sector_start;*/
01191   int current_sector = miniFAT_sector_start;
01192   int chain_length=0;
01193   int break_out = 0;
01194 
01195   DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Starting at sector %d",FL, miniFAT_sector_start);
01196 
01197   if (miniFAT_sector_start < 0) return 0;
01198 
01199   do {
01200     /*unsigned int next_sector;*/
01201     int next_sector;
01202 
01203     DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Requesting 4-byte value at '%d'",FL, ole->miniFAT +(LEN_ULONG *current_sector));
01204     /* next text commented out because ole->miniFAT_limit is set to null ans vever change
01205        if (ole->miniFAT +(LEN_ULONG *current_sector) > ole->miniFAT_limit) {
01206        DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Requested location is out of bounds\n",FL);
01207        return 0;
01208        }
01209     */
01210 
01211     next_sector = get_4byte_value( ole->miniFAT +(LEN_ULONG *current_sector));
01212 
01213     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);
01214 
01218     if (current_sector == next_sector) break;
01219 
01220     chain_length++;
01221     current_sector = next_sector;
01222 
01224     switch (current_sector) {
01225     case OLE_SECTORID_MSAT:
01226     case OLE_SECTORID_SAT:
01227     case OLE_SECTORID_ENDOFCHAIN:
01228     case OLE_SECTORID_FREE:
01229       break_out=1;
01230       break;
01231     default:
01232       break_out=0;
01233     };
01234 
01235     DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: current sector = %d",FL,current_sector);
01236     /* Test changed  Serge Steer Scilab */
01237     /*  } while ((break_out==0) &&(current_sector <= ole->last_sector));*/
01238   } while ((break_out==0));
01239   DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Done.  Chainlength=%d",FL, chain_length);
01240 
01241   return chain_length;
01242 }
01243 
01244 /*-----------------------------------------------------------------\
01245   Function Name : char
01246   Returns Type  : unsigned
01247   ----Parameter List
01248   1. *OLE_load_minichain( struct OLE_object *ole, 
01249   2.  int FAT_sector_start , 
01250   ------------------
01251   Exit Codes    : 
01252   Side Effects  : 
01253   --------------------------------------------------------------------
01254   Comments:
01255 
01256   --------------------------------------------------------------------
01257   Changes:
01258   PLD:2003-Aug-28: Added sanity checking on the miniFAT_sector_start 
01259   value so that we didn't try to load up a miniFAT starting on a 
01260   negative value
01261 
01262   \------------------------------------------------------------------*/
01263 unsigned char *OLE_load_minichain( struct OLE_object *ole, int miniFAT_sector_start )
01264 {
01265 
01266   int chain_length = 0;
01267   int current_sector = miniFAT_sector_start;
01268   unsigned char *buffer;
01269   unsigned char *bp;
01270   int break_out = 0;
01271 
01272   DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Loading minichain starting at %d",FL, miniFAT_sector_start);
01273 
01274   /* Added this sanity checking 2003 Aug 28*/
01275   if (miniFAT_sector_start < 0) return NULL;
01276 
01277   chain_length = OLE_follow_minichain( ole, miniFAT_sector_start );
01278   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);
01279 
01280   /* 20040911-21H59*/
01281   /* If our chain is 0 length, then there's nothing to return*/
01282   if (chain_length == 0) return NULL;
01283 
01284   bp = buffer = MALLOC( chain_length *ole->header.mini_sector_size *sizeof(unsigned char));
01285   if (buffer != NULL)
01286     {
01287       do {
01288         int next_sector;
01289 
01290         DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Loading sector %d",FL, current_sector);
01291         OLE_get_miniblock( ole, current_sector, bp );
01292         bp += ole->header.mini_sector_size;
01293 
01294         next_sector = get_4byte_value( ole->miniFAT +(LEN_ULONG *current_sector));
01295         current_sector = next_sector;
01296         /* NEXT LINES ADDED TO BE COHERENT WITH  OLE_follow_minichain ABOVE Serge Steer Scilab */
01297         switch (current_sector) {
01298         case OLE_SECTORID_MSAT:
01299         case OLE_SECTORID_SAT:
01300         case OLE_SECTORID_ENDOFCHAIN:
01301         case OLE_SECTORID_FREE:
01302           break_out=1;
01303           break;
01304         default:
01305           break_out=0;
01306         };
01307         /* Test changed  Serge Steer Scilab */
01308         /* } while ((current_sector != OLE_SECTORID_ENDOFCHAIN)&&(current_sector >= 0)&&(current_sector <= ole->last_sector));*/
01309 
01310       } while ((break_out==0));
01311 
01312     } else {
01313       LOGGER_log("%s:%d:OLE_get_miniblock:ERROR: Failed to allocate enough memory for miniChain",FL);
01314     }
01315 
01316   DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Done. buffer=%p",FL, buffer);
01317 
01318   return buffer;
01319 }
01320 
01321 
01322 /*-----------------------------------------------------------------\
01323   Function Name : char
01324   Returns Type  : unsigned
01325   ----Parameter List
01326   1. *OLE_load_chain( struct OLE_object *ole, 
01327   2.  int FAT_sector_start , 
01328   ------------------
01329   Exit Codes    : 
01330   Side Effects  : 
01331   --------------------------------------------------------------------
01332   Comments:
01333 
01334   --------------------------------------------------------------------
01335   Changes:
01336   Make the loading aware of negative-value sectors so that it can
01337   make more intelligent exit strategies.
01338 
01339   \------------------------------------------------------------------*/
01340 unsigned char *OLE_load_chain( struct OLE_object *ole, int FAT_sector_start )
01341 {
01342 
01343   int chain_length = 0;
01344   int current_sector = FAT_sector_start;
01345   unsigned char *buffer = NULL;
01346   unsigned char *bp = NULL;
01347 
01348 
01349   ole->last_chain_size = 0;
01350 
01351   if (FAT_sector_start < 0) return NULL;
01352 
01353   DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: Loading chain, starting at sector %d",FL,FAT_sector_start);
01354 
01355   chain_length = OLE_follow_chain( ole, FAT_sector_start );
01356   DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: %d sectors need to be loaded",FL,chain_length);
01357 
01358   if (chain_length > 0)
01359     {
01360       size_t offset;
01361 
01362       offset = ole->last_chain_size = chain_length << ole->header.sector_shift;
01363       bp = buffer = MALLOC( (offset) *sizeof(unsigned char));
01364       if (buffer == NULL)
01365         {
01366           LOGGER_log("%s:%d:OLE_load_chain:ERROR: Cannot allocate %d bytes for OLE chain",FL,offset);
01367           return NULL;
01368         }
01369 
01370       if (buffer != NULL)
01371         {
01372           int tick = 0;
01373           unsigned char *bp_limit;
01374           bp_limit = bp +offset;
01375 
01376           do {
01377             int next_sector;
01378 
01379             DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: Loading sector[%d] %d",FL, tick, current_sector );
01380 
01381             ole->error = OLE_get_block( ole, current_sector, bp );
01382             if (ole->error != OLE_OK)
01383               {
01384                 /*FREE5                                 if (bp != NULL) FREE(bp);*/
01385                 return NULL;
01386               }
01387 
01388             bp += ole->header.sector_size;
01389             if (bp > bp_limit) {  
01390               if (buffer != NULL) { FREE(buffer); bp = buffer = NULL; }
01391               VOLE LOGGER_log("%s:%d:OLE_load_chain:ERROR: Load-chain went over memory boundary",FL); 
01392               return NULL;
01393             };
01394 
01395             next_sector = get_4byte_value( ole->FAT +(LEN_ULONG *current_sector));
01396             current_sector = next_sector;
01397             tick++;
01398           } while ((current_sector >= 0)&&(current_sector <= ole->last_sector));
01399         }
01400     }
01401   DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: Done loading chain",FL);
01402 
01403   return buffer;
01404 }
01405 
01406 /*-----------------------------------------------------------------\
01407   Function Name : OLE_open_file
01408   Returns Type  : int
01409   ----Parameter List
01410   1. struct OLE_object *ole, 
01411   2.  char *fullpath , 
01412   ------------------
01413   Exit Codes    : 
01414   Side Effects  : 
01415   --------------------------------------------------------------------
01416   Comments:
01417 
01418   --------------------------------------------------------------------
01419   Changes:
01420   20041127-2033:PLD: Added ole->file_size setting so that we 
01421   can use this in the sanity checking to see if the 
01422   requested sectors are outside of the possible valid
01423   filesize range.
01424 
01425   \------------------------------------------------------------------*/
01426 int OLE_open_file( struct OLE_object *ole, char *fullpath )
01427 {
01428   struct stat st;
01429   int stat_result;
01430   FILE *f;
01431 
01432   stat_result = stat(fullpath, &st);
01433   if (stat_result != 0) {
01434     DOLE LOGGER_log("%s:%d:OLE_open_file:ERROR: Cannot locate file '%s' for opening (%s)",FL, fullpath, strerror(errno));
01435     return OLEER_BAD_INPUT_FILE;
01436   }
01437 
01438   DOLE LOGGER_log("%s:%d:OLE_open_file:DEBUG: File size of %s = %ld",FL, fullpath, st.st_size);
01439   if ((stat_result == 0) && (st.st_size < 512)) return OLEER_NOT_OLE_FILE;
01440 
01441   ole->file_size = st.st_size;
01442 
01443   f = fopen(fullpath,"rb");
01444   if (f == NULL)
01445     {
01446       ole->f = NULL;
01447       if (ole->quiet == 0)
01448         {
01449           LOGGER_log("%s:%d:OLE_open_file:ERROR:Cannot open %s for reading (%s)\n",FL,fullpath, strerror(errno));
01450         }
01451       return -1;
01452     } else {
01453       ole->f = f;
01454       ole->file_size = st.st_size;
01455       ole->last_sector = -1;
01456     }
01457   return OLE_OK;
01458 }
01459 
01460 
01461 /*-----------------------------------------------------------------\
01462   Function Name : OLE_open_directory
01463   Returns Type  : int
01464   ----Parameter List
01465   1. struct OLE_object *ole, 
01466   2.  char *directory , 
01467   ------------------
01468   Exit Codes    : 
01469   Side Effects  : 
01470   --------------------------------------------------------------------
01471   Comments:
01472 
01473   --------------------------------------------------------------------
01474   Changes:
01475 
01476   \------------------------------------------------------------------*/
01477 int OLE_open_directory( struct OLE_object *ole, char *directory )
01478 {
01479   int result=0;
01480 
01481 #ifndef _MSC_VER
01482   result = mkdir( directory, S_IRWXU );
01483 #else
01484     result = CreateDirectory( directory,NULL);
01485       /* If the function succeeds, the return value is nonzero.
01486          If the function fails, the return value is zero. */
01487       if (result) result=0;
01488 #endif
01489                     if ((result != 0)&&(errno != EEXIST))
01490                       {
01491                         LOGGER_log("%s:%d:OLE_open_directory:ERROR: %s",FL,strerror(errno));
01492                       } else result = OLE_OK;
01493 
01494                     return result;
01495 }
01496 
01497 
01498 /*-----------------------------------------------------------------\
01499   Function Name : OLE_set_filename_report_fn
01500   Returns Type  : int
01501   ----Parameter List
01502   1. int (*ptr_to_fn)(char *) , 
01503   ------------------
01504   Exit Codes    : 
01505   Side Effects  : 
01506   --------------------------------------------------------------------
01507   Comments:
01508   This is merely a passthrough function to the OLEUW one, we do
01509   this in order to avoid having to force the calling parent from
01510   having to #include the OLEUW headers as well
01511 
01512   --------------------------------------------------------------------
01513   Changes:
01514 
01515   \------------------------------------------------------------------*/
01516 int OLE_set_filename_report_fn( struct OLE_object *ole, int (*ptr_to_fn)(char *) )
01517 {
01518   ole->filename_report_fn = ptr_to_fn;
01519   return OLE_OK;
01520 }
01521 
01522 
01523 /*-----------------------------------------------------------------\
01524   Function Name : OLE_store_stream
01525   Returns Type  : int
01526   ----Parameter List
01527   1. struct OLE_object *ole, 
01528   2.  char *stream_name, 
01529   3.  char *directory, 
01530   4.  unsigned char *stream , 
01531   ------------------
01532   Exit Codes    : 
01533   Side Effects  : 
01534   --------------------------------------------------------------------
01535   Comments:
01536 
01537   --------------------------------------------------------------------
01538   Changes:
01539 
01540   \------------------------------------------------------------------*/
01541 int OLE_store_stream( struct OLE_object *ole, char *stream_name, char *directory, char *stream, size_t stream_size )
01542 {
01543   char *full_path = NULL;
01544 
01545   full_path = PLD_dprintf("%s/%s", directory, stream_name);
01546   if (full_path == NULL)
01547     {
01548       LOGGER_log("%s:%d:OLE_store_stream:ERROR: Cannot compose full filename string from '%s' and '%s'", FL, directory, stream_name);
01549       return -1;
01550     } else {
01551       FILE *f;
01552 
01553       f = fopen(full_path,"wb");
01554       if (f == NULL)
01555         {
01556           LOGGER_log("%s:%d:OLE_store_stream:ERROR: Cannot open %s for writing (%s)",FL, full_path, strerror(errno));
01557           if (full_path) FREE(full_path);
01558           return -1;
01559         } else {
01560           size_t written_bytes;
01561 
01562           written_bytes = fwrite( stream, 1, stream_size, f );
01563           if (written_bytes != stream_size)
01564             {
01565               LOGGER_log("%s:%d:OLE_store_stream:WARNING: Only wrote %d of %d bytes to file %s",FL,written_bytes,stream_size,full_path);
01566             }
01567           fclose(f);
01568 
01569           if ((OLE_VNORMAL(ole->verbose))&&(ole->filename_report_fn != NULL))
01570             {
01571               ole->filename_report_fn( stream_name );
01572             }
01573         } /* if file is valid*/
01574     } /* if full_path is valid*/
01575 
01576   if (full_path) FREE(full_path);
01577 
01578   return OLE_OK;
01579 }
01580 
01581 
01582 /*-----------------------------------------------------------------\
01583   Function Name : OLE_decode_file_done
01584   Returns Type  : int
01585   ----Parameter List
01586   1. struct OLE_object *ole , 
01587   ------------------
01588   Exit Codes    : 
01589   Side Effects  : 
01590   --------------------------------------------------------------------
01591   Comments:
01592 
01593   --------------------------------------------------------------------
01594   Changes:
01595 
01596   \------------------------------------------------------------------*/
01597 int OLE_decode_file_done( struct OLE_object *ole )
01598 {
01599   if (ole->f) fclose(ole->f);
01601   if (ole->FAT) FREE(ole->FAT);
01602   if (ole->miniFAT) FREE(ole->miniFAT);
01603   if (ole->ministream) FREE(ole->ministream);
01604   if (ole->properties) FREE(ole->properties);
01605 
01606   return 0;
01607 }
01608 
01609 
01610 /*-----------------------------------------------------------------\
01611   Function Name : OLE_terminate_and_return
01612   Returns Type  : int
01613   ----Parameter List
01614   1. struct OLE_object *ole, 
01615   2.  int result , 
01616   ------------------
01617   Exit Codes    : 
01618   Side Effects  : 
01619   --------------------------------------------------------------------
01620   Comments:
01621 
01622   --------------------------------------------------------------------
01623   Changes:
01624 
01625   \------------------------------------------------------------------*/
01626 int OLE_terminate_and_return( struct OLE_object *ole, int result )
01627 {
01628   OLE_decode_file_done(ole);
01629   return result;
01630 }
01631 
01632 
01633 #ifdef RIPOLE_WALK_TREE
01634 int OLE_walk_tree( struct OLE_object *ole, char *fname, char *decode_path, int depth ) 
01635 {
01636 
01639   if (depth > 100) return 0;
01640   if (ole->total_file_count > 10000) return 0;
01641   if (element_type < 0) return 0;
01642 
01643   switch (element_type) {
01644 
01645   case STGTY_ROOT:
01649     DOLE LOGGER_log("%s:%d:OLE_walk_tree:DEBUG: Loading ministream/SmallBlockArray",FL);
01650     ole->ministream = OLE_load_chain( ole, adir->start_sector );
01651     if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL;
01652     DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: ministream done",FL);
01653   }
01654 
01655 } else if (adir->element_type == STGTY_STORAGE) {
01659   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Item is directory, start child is at index %d\n",FL,i);
01660   ole->ministream = OLE_load_chain( ole, adir->start_sector );
01661   if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL;
01662   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: DIRECTORY ministream done",FL);
01663 
01664 
01665 }
01666 #endif
01667 
01668 
01669 
01670 int OLE_decode_stream( struct OLE_object *ole,  struct OLE_directory_entry *adir, char *decode_path )
01671 {
01672   char *stream_data;
01673   struct OLEUNWRAP_object oleuw;
01674   int decode_result = OLEUW_STREAM_NOT_DECODED;
01675   char element_name[64];
01676   int result = 0;
01677 
01678   memset(element_name, '\0', 64);
01679   OLE_dbstosbs( adir->element_name, adir->element_name_byte_count, element_name, 64 );
01680 
01681   DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Decoding stream '%s'",FL, element_name);
01682 
01683   DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Initializing stream unwrapper",FL);
01684   OLEUNWRAP_init(&oleuw);
01685   OLEUNWRAP_set_debug(&oleuw,ole->debug);
01686   OLEUNWRAP_set_verbose(&oleuw,ole->verbose);
01687   OLEUNWRAP_set_filename_report_fn(&oleuw, ole->filename_report_fn);
01688   OLEUNWRAP_set_save_unknown_streams(&oleuw, ole->save_unknown_streams);
01689   DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Unwrap engine set.",FL);
01690 
01691   if (adir->stream_size >= ole->header.mini_cutoff_size)
01692     {
01696       DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG:  Loading normal sized chain starting at sector %d",FL, adir->start_sector);
01697       stream_data = OLE_load_chain( ole, adir->start_sector );
01698       if (stream_data == NULL)
01699         {
01700           DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Terminating from stream data being NULL  ",FL);
01701           /*OLE_decode_file_done(ole);*/
01702           return OLEER_MINISTREAM_STREAM_READ_FAIL;
01703         }
01704       DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Normal decode START. element name ='%s' stream size = '%ld'",FL, element_name, adir->stream_size);
01705       decode_result = OLEUNWRAP_decodestream( &oleuw, element_name, stream_data, adir->stream_size, decode_path );
01706       DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Normal decode done.",FL);
01707     } else {
01708 
01709 
01713       DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Minichain loader, starting at sector %d"
01714                       ,FL
01715                       ,adir->start_sector
01716                       );
01717       stream_data = OLE_load_minichain( ole, adir->start_sector );
01718       if (stream_data == NULL)
01719         {
01720           DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Ministream was non-existant, terminating",FL);
01721           /*OLE_decode_file_done(ole);*/
01722           return OLEER_NORMALSTREAM_STREAM_READ_FAIL;
01723         }
01724       DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Mini decode START.",FL);
01725       decode_result = OLEUNWRAP_decodestream( &oleuw, element_name, stream_data, adir->stream_size, decode_path );
01726       DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Mini decode done.",FL);
01727     }
01728 
01729   /* Added for Scilab */
01730   if ((stream_data != NULL)&&(decode_result == OLEUW_STREAM_NOT_DECODED)&&
01731       (ole->save_unknown_streams==2)&&((strcmp(element_name,"Workbook")==0)||(strcmp(element_name,"Book")==0)))
01732     {
01733       strcpy(element_name,"Workbook");
01734       OLE_store_stream( ole, element_name, decode_path, stream_data, adir->stream_size );
01735 
01736     } /* If we needed to save an unknown stream*/
01737 
01738   else /* end Scilab addition */if ((stream_data != NULL)&&(decode_result == OLEUW_STREAM_NOT_DECODED)&&(ole->save_unknown_streams))
01739     {
01740       char *lfname;
01741 
01742       lfname = PLD_dprintf("ole-stream.%d",adir->start_sector);
01743       if (lfname != NULL)
01744         {
01745           DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Saving stream to %s",FL,lfname);
01746           OLE_store_stream( ole, lfname, decode_path, stream_data, adir->stream_size );
01747           FREE(lfname);
01748         } 
01749     } /* If we needed to save an unknown stream*/
01750 
01751   /* Clean up an stream_data which we may have */
01752   /* read in from the chain-loader.*/
01753   if (stream_data) FREE(stream_data);
01754 
01755   return result;
01756 }
01757 
01758 /*-----------------------------------------------------------------\
01759   Function Name : OLE_decode_file
01760   Returns Type  : int
01761   ----Parameter List
01762   1. char *fname, 
01763   2.  char *decode_path , 
01764   ------------------
01765   Exit Codes    : 
01766   Side Effects  : 
01767   --------------------------------------------------------------------
01768   Comments:
01769 
01770   --------------------------------------------------------------------
01771   Changes:
01772 
01773   \------------------------------------------------------------------*/
01774 int OLE_decode_file( struct OLE_object *ole, char *fname, char *decode_path )
01775 {
01776   unsigned char *current_property, *property_limit;
01777   int result = 0;
01778   int i;
01779 
01780   /* Reject any bad paramters.*/
01781   if (ole == NULL) return OLEER_DECODE_NULL_OBJECT;
01782   if (fname == NULL) return OLEER_DECODE_NULL_FILENAME;
01783   if (decode_path == NULL) return OLEER_DECODE_NULL_PATH;
01784 
01785   /* We need to gain access to the OLE2 data file, without*/
01786   /*            this pretty much everything is pointless.*/
01787   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: opening %s", FL, fname );
01788   result = OLE_open_file( ole, fname );
01789   if (result != 0) return result;
01790 
01791   /* Try create the output directory which we're using*/
01792   /*            to write the decoded files out to.*/
01793   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: opening output directory %s", FL, decode_path);
01794   result = OLE_open_directory( ole, decode_path );
01795   if (result != 0) return result;
01796 
01797   /* In order to successfully decode an OLE2 stream, we have to read*/
01798   /*            and understand the first 512 bytes of the file, this is the */
01799   /*            OLE2 header. */
01800   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Getting main header", FL);
01801   result = OLE_get_header( ole );
01802   if (result != 0) return result;
01803 
01804   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Converting main header", FL);
01805   result = OLE_convert_header( ole );
01806   if (result != 0) return result;
01807 
01808   result = OLE_header_sanity_check( ole );
01809   if (result > 0) return OLEER_INSANE_OLE_FILE;
01810 
01811   DOLE OLE_print_header( ole );
01812 
01813   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading FAT", FL);
01814   result = OLE_load_FAT( ole );
01815   if (result != 0) return result;
01816 
01817   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading miniFAT chain", FL);
01818   ole->miniFAT = OLE_load_chain( ole, ole->header.mini_fat_start );
01819   /* commented out by Serge Steer for Scilab*/
01820   /* if (ole->miniFAT == NULL) return OLEER_MINIFAT_READ_FAIL;*/
01821 
01822   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading Directory stream chain", FL);
01823   ole->properties = OLE_load_chain( ole, ole->header.directory_stream_start_sector );
01824   if (ole->properties == NULL) return OLEER_PROPERTIES_READ_FAIL;
01825 
01826   i=0;
01827   current_property = ole->properties;
01828   property_limit = current_property +ole->last_chain_size ;
01829   /* while(1)*/
01830   while (current_property < property_limit)
01831     {
01832       struct OLE_directory_entry a_dir_object, *adir;
01833       int property_value=0;
01834 
01835       adir = &a_dir_object;
01836 
01837       OLE_dir_init(adir);
01838 
01839       property_value = get_1byte_value(current_property);
01840       if (property_value < 1) break;
01841 
01842       DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG:--------- DIRECTORY INDEX: %d",FL,i);
01843 
01844       OLE_convert_directory( ole, current_property, adir );
01845 
01846       DOLE {
01847         LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Printing directory details...",FL);
01848         OLE_print_directory( ole, adir);
01849         LOGGER_log("%s:%d:OLE_decode_file:DEBUG: End of directory details",FL);
01850       }
01851 
01852       if (adir->element_colour > 1) break;
01853 
01854       if ((adir->element_type == STGTY_INVALID)||(adir->element_type > STGTY_ROOT))
01855         {
01856           DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: breaking out due to element type %d",FL, adir->element_type);
01857           break;
01858 
01859         } else if (adir->element_type == STGTY_ROOT){
01863           DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading ministream/SmallBlockArray",FL);
01864           ole->ministream = OLE_load_chain( ole, adir->start_sector );
01865           /* commented out by Serge Steer for Scilab*/
01866           /*if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL;*/
01867           DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: ministream done",FL);
01868 
01869         } else if (adir->element_type == STGTY_STORAGE) {
01873           DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Item is directory, start child is at index %d\n",FL,i);
01874           ole->ministream = OLE_load_chain( ole, adir->start_sector );
01875           /* commented out by Serge Steer for Scilab*/
01876           /*if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL;*/
01877           DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: DIRECTORY ministream done",FL);
01878 
01879         } else if (adir->element_type == STGTY_STREAM) {
01883           /* due to ole.c bugs we restrict here steams to decode to Workbooks (Excel) */
01884           char element_name[64];
01885           memset(element_name, '\0', 64);
01886           OLE_dbstosbs( adir->element_name, adir->element_name_byte_count, element_name, 64 );
01887           
01888           if ((strcmp(element_name,"Workbook")==0)||(strcmp(element_name,"Book")==0)) {
01889             OLE_decode_stream( ole, adir, decode_path );
01890           }
01891           /*end of replacment code */
01892           /* Original code */
01893           /*  OLE_decode_stream( ole, adir, decode_path );*/
01894         } else {
01898           DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Element type %d does not need to be handled",FL,adir->element_type);
01899         }
01900 
01901       /* Jump to the next property record, which*/
01902       /*                is always 128 bytes ahead.*/
01903       current_property += 128;
01904       i++;
01905 
01906     } /* While there are still more directory entries to read in.*/
01907 
01908   DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Finished",FL);
01909 
01910   /*
01911     if (ole->f) fclose(ole->f);
01912     fclose(ole->f);
01913     if (ole->FAT) FREE(ole->FAT);
01914     if (ole->miniFAT) FREE(ole->miniFAT);
01915     if (ole->ministream) FREE(ole->ministream);
01916     if (ole->properties) FREE(ole->properties);
01917   */
01918 
01919   return OLE_OK;
01920 }

Generated on Sun Mar 4 15:03:49 2007 for Scilab [trunk] by  doxygen 1.5.1