📄 olecod.c
字号:
/* OLEcode - Generate a Microsoft OLE 2 file from given streams. Copyright 1998, 1999 Roberto Arturo Tena Sanchez This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* Arturo Tena <arturo@directmail.org> */#include <string.h>#include <stdlib.h>#include <assert.h>#if !(defined( __BORLANDC__ ) || defined( __WIN32__ ))#include "cole.h"#else#include "cole.h.in"#endif#include "support.h"#include "internal.h"#ifdef COLE_VERBOSE#define VERBOSE#else#undef VERBOSE#endif/* warning: some lines are longer than 80 characters */struct str_MY_FILE{ enum { real, MY_FILE_list, block_list, root_list } type; U32 size; /* size of list _itself_ */ U32 *blocks; /* size in big blocks (0x0200) of the information that contains this file */ union union_file { struct str_real { char *name; /* file name */ U32 ppsnumber; /* ppsnumber of pps property in stream_list */ } real; struct str_MY_FILE *MY_FILE_list; U32 *block_list; U8 *root_list; } file;};typedef struct str_MY_FILE MY_FILE;static MY_FILE Input;static MY_FILE *sbfile;static MY_FILE *SDepot;static MY_FILE *BDepot;static MY_FILE *bbd_list;static MY_FILE *Root;/* starting and sizing blocks (calculated in calculate_blocks()) */static U32 header_blocks; /* how many blocks takes header */static U32 big_streams_blocks; /* how many blocks takes big streams */static U32 sbfile_blocks; /* how many blocks takes sbfile (small streams) */static U32 SDepot_blocks; /* how many blocks takes SDepot */static U32 BDepot_blocks; /* how many blocks takes BDepot */static U32 Root_blocks; /* how many blocks takes Root */static U32 sbfile_start_block; /* where sbfile starts */static U32 SDepot_start_block; /* where SDepot starts */static U32 Root_start_block; /* where Root starts */static U32 BDepot_start_block; /* where BDepot starts */static FILE *output_file;/* the output file OLE2 file */static U8 output_block[0x0200];/* used as buffer to write later to output_file */static U16 pos_block;/* position inside output_block from where the next write will happen, when it cames 0x0200 must write the block to output_file and make pos_block = 0x00 */static U32 next_block;/* number of the next block to be written in output_file. the first block is -1, the second 0, the third 1 and so on *//* process stage functions */static int process_Root (pps_entry * pps_list, U32 root);static U32 max_pps_referenced (pps_entry * pps_list, U32 node);static U32 max3 (U32 a, U32 b, U32 c, U32 d);static int process_streams (pps_entry * pps_list, pps_entry * root);static int add_stream_to_sbfile_and_SDepot (U32 size, char *name, U32 ppsnumber);static int add_stream_to_Input_and_BDepot (U32 size, char *name, U32 ppsnumber);static int add_entry_to_Root (pps_entry * node, U32 start_block);static U32 add_MY_FILE_entry (MY_FILE * list, U32 size);static int pps2root (U8 pps[0x80], pps_entry * node, U32 start_block);static void reset_links_in_Input (void);static void reset_links_in_BDepot (void);static void reset_links_in_SDepot (void);/* generate starge functions */static int generate_ole2_file (const char *filename, int trunc);static int generate_header (void);static int generate_recursive (MY_FILE * list);static int generate_SDepot (void);static int generate_Root (void);static int generate_BDepot (void);static int generate_real_file (MY_FILE * MY_FILE_file);static int write_block_list (U32 start_count, MY_FILE *list, int write_end_chain);static int write_root_list (MY_FILE * list);static void calculate_blocks (void);/* support functions for both stages */static U32 sum_block_list (MY_FILE * list);/* useless function by now, may be later *//* static U32 sum_MY_FILE_list (MY_FILE * list); */static U32 sum_blocks_MY_FILE_list (MY_FILE * list);static void ends (void);#define size2blocks(s,b) (!(s) ? 1 : (1+((s)-1)/(b)))#define size2blocks_preserve_zero(s,b) (!(s) ? 0 : (1+((s)-1)/(b)))#define clean_block(b,s) memset((b),0xff,(s))#define init_MY_FILE(n, t, s, b, f) { \ (n)->type = t; \ (n)->size = (s); \ (n)->blocks = (b); \ (n)->file.t = (f); \ }#define init_MY_FILE_real(n, t, s, b, f, p) { \ n->type = t; \ n->size = s; \ n->blocks = b; \ n->file.real.name = f; \ n->file.real.ppsnumber = p; \ }#define reset_links() { reset_links_in_Input(); reset_links_in_BDepot(); reset_links_in_SDepot(); }/* if this block is full, write it to output_file and restart using this block */#define check_output_block_boundary() { \ if (pos_block == 0x0200) { \ test_exitf (fwrite (output_block, 0x0200, 1, output_file) == 1, 1, dummy()); \ next_block++; \ pos_block = 0x00; \ } \ }#define write_until_output_block_boundary(clean) { \ if (pos_block != 0x00) { \ if (clean && pos_block%0x0200) \ clean_block (output_block + pos_block, (pos_block/0x0200 + 1)*0x0200 - pos_block); \ test_exitf (fwrite (output_block, 1, 0x0200, output_file) == 0x0200, 1, dummy ()); \ next_block++; \ pos_block = 0x00; \ } \}#define write_until_output_block_small_boundary(clean) { \ if (pos_block % 0x40) { \ if (clean) \ clean_block (output_block + pos_block, (pos_block/0x40 + 1)*0x40 - pos_block); \ assert (pos_block+(pos_block/0x40 + 1)*0x40 - pos_block == (pos_block/0x40 + 1)*0x40); \ pos_block += (U16)((pos_block/0x40 + 1)*0x40 - pos_block); \ } \}#define write_rest_of_output_block_with_null_pps() { \ if (pos_block != 0x00) { \ int zzzi; \ U16 U16zero = 0x0000U; \ clean_block (output_block + pos_block, 0x0200 - pos_block); \ for (zzzi = 0; zzzi < 4; zzzi++) \ if (zzzi*0x80 >= pos_block) \ fil_swriteU16 (output_block + zzzi*0x80 + 0x40, &U16zero); \ } \ }#define dummy()/* may be should be (means no op, do nothing):#define dummy() {1;}or may be:#define dummy() {;}*//* Exit codes: 0 = All goes OK. 1 = error writting in OLEfilename, can use perror 2 = trunc == 0 and file exist 3 = can't create OLEfilename, can use perror 10 = Error allocating memory, there's no more memory 11 = Error reading streams files 12 = Error reading stream_list, it's broken*/int__OLEcode (const char *OLEfilename, int trunc, pps_entry * stream_list, U32 root){ verbose ("calling: OLEcode ()"); assert (OLEfilename != NULL); assert (stream_list != NULL); /* -- init static things -- */ output_file = NULL; clean_block (output_block, 0x0200); /* just needed clean up once, for security reasons */ pos_block = 0x00; next_block = 0xffffffffUL; /* it need to be 0xffffffffUL, because next time we make next_block++ it must be zero (bad hack? next_block is always 32 bits) */ BDepot = SDepot = bbd_list = NULL; Root = NULL; sbfile = NULL; /* -- allocate initial memory needed for my files (Structure called at HACKING) -- */ /* Input: 5 entries in Input: for sbfile, for SDepot, for BDepot, for bbd_list and for Root */ init_MY_FILE ((&Input), MY_FILE_list, 5 * sizeof (MY_FILE), NULL, malloc (Input.size)); /* Input->blocks is not needed */ test_exitf (Input.file.MY_FILE_list != NULL, 10, ends ()); reset_links_in_Input (); /* bbd_list */ init_MY_FILE (bbd_list, block_list, sizeof (U32), NULL, malloc (bbd_list->size)); /* bbd_list is not needed */ /* bbd_list->blocks is not needed */ test_exitf (bbd_list->file.block_list != NULL, 10, ends ()); bbd_list->file.block_list[0] = 1; /* because BDepot starts with 3 entries */ /* BDepot */ init_MY_FILE (BDepot, block_list, 3 * sizeof (U32), bbd_list->file.block_list, malloc (BDepot->size)); test_exitf (BDepot->file.block_list != NULL, 10, ends ()); BDepot->file.block_list[0] = BDepot->file.block_list[1] = BDepot->file.block_list[2] = 0; /* sbfile, SDepot and Root are size 0 by now */ /* sbfile */ init_MY_FILE (sbfile, MY_FILE_list, 0, BDepot->file.block_list, NULL); /* SDepot */ init_MY_FILE (SDepot, block_list, 0, BDepot->file.block_list + 1, NULL); /* Root */ init_MY_FILE (Root, root_list, 0, BDepot->file.block_list + 2, NULL); /* -- process streams -- */ test_call (process_Root (stream_list, root), int); test_call (process_streams (stream_list, &stream_list[root]), int); /* how can I call ends() if process_streams fails? */ /* -- actually generate ole2 file -- */ test_call (generate_ole2_file (OLEfilename, trunc), int); return 0;}/* reviewed when coding ole2 file */static intprocess_Root (pps_entry * pps_list, U32 root){ U32 pps_list_entries; U32 i; verbose ("calling: process_Root ()"); pps_list_entries = (1 + max_pps_referenced (pps_list, root)); verboseU32 (pps_list_entries); for (i = 0; i < pps_list_entries; i++) test_call (add_entry_to_Root (pps_list + i, 0x00000000UL), int); /* start_block = 0x00000000UL is a dummy value. The real start block: for files in SDepot is written in Root in generate_real_file(), for files in BDepot is written in Root in generate_real_file(), and for sbfile: the default is written in process_streams() and the real, if any, is written when generating the first small stream in generate_real_file(). But 0x00000000UL is a perfect value to directory entries (type=1) About sizes: every pps have its size, incluiding sbfile, that value will be comparated later in generate_real_file(). */ return 0;}#define MAX(a,b) ((a) > (b) ? (a) : (b))static U32 max3 (U32 a, U32 b, U32 c, U32 d){ U32 m = 0; /*verbose ("calling: max3 ()");*/ m = MAX (m, a); m = MAX (m, b); m = MAX (m, c); m = MAX (m, d); return m;}static U32 max_pps_referenced (pps_entry * pps_list, U32 node){ U32 max_pps; /*verbose ("calling: max_pps_referenced ()");*/ max_pps = max3 (node, pps_list[node].previous != 0xffffffffUL ? pps_list[node].previous : 0, pps_list[node].next != 0xffffffffUL ? pps_list[node].next : 0, pps_list[node].dir != 0xffffffffUL ? pps_list[node].dir : 0); if (pps_list[node].previous != 0xffffffffUL) max_pps = MAX (max_pps, max_pps_referenced (pps_list, pps_list[node].previous)); if (pps_list[node].next != 0xffffffffUL) max_pps = MAX (max_pps, max_pps_referenced (pps_list, pps_list[node].next)); if (pps_list[node].dir != 0xffffffffUL) max_pps = MAX (max_pps, max_pps_referenced (pps_list, pps_list[node].dir)); return max_pps;}/* reviewed when coding ole2 file */static int process_streams (pps_entry * pps_list, pps_entry * node){ U32 U32end_chain = 0xfffffffeUL; verbose ("calling: process_streams ()"); test_exitf (node->name[0], 12, dummy()); switch (node->type) { case 1: /* dir */ warning (node->size == 0); if (node->dir != 0xffffffffUL) test_call (process_streams (pps_list, &pps_list[node->dir]), int); if (node->next != 0xffffffffUL) test_call (process_streams (pps_list, &pps_list[node->next]), int); break; case 5: /* root dir */ assert (*(Root->file.root_list + 0x42) == 5); /* write the default start block of SDepot: empty if there are no sbfile at all */ fil_swriteU32 (Root->file.root_list + 0x74, &U32end_chain); if (node->dir != 0xffffffffUL) test_call (process_streams (pps_list, &pps_list[node->dir]), int); if (node->next != 0xffffffffUL) test_call (process_streams (pps_list, &pps_list[node->next]), int); break; case 2: /* file */ test_exitf (node->dir == 0xffffffffUL, 12, dummy()); if (node->size < 0x1000) /* must be in sbfile, and its block list in SDepot */ test_call (add_stream_to_sbfile_and_SDepot ( node->size, node->filename, node->ppsnumber), int) else /* node->size >= 0x1000 */ /* must be in Input, and its block list in BDepot */ test_call (add_stream_to_Input_and_BDepot ( node->size, node->filename, node->ppsnumber), int); if (node->next != 0xffffffffUL) test_call (process_streams (pps_list, &pps_list[node->next]), int); break; default: return 12; } return 0;}/* reviewed when processing Root */static int add_entry_to_Root (pps_entry * node, U32 start_block){ U32 entry_number; U8 * new_entry_Root; verbose ("calling: add_entry_to_Root ()"); /* 1. add entry in Root */ entry_number = add_MY_FILE_entry (Root, 0 /*dummy value, not used*/); test_exitf (entry_number != 0xffffffffUL, 10, dummy ()); new_entry_Root = Root->file.root_list + entry_number * 0x80; /* 2. write info about the new stream in the new entry in Root */ pps2root (new_entry_Root, node, start_block);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -