| | 1 | /* $Header: d:/cvsroot/tads/tads3/vmwrtimg.h,v 1.4 1999/07/11 00:46:59 MJRoberts Exp $ */ |
| | 2 | |
| | 3 | /* |
| | 4 | * Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved. |
| | 5 | * |
| | 6 | * Please see the accompanying license file, LICENSE.TXT, for information |
| | 7 | * on using and copying this software. |
| | 8 | */ |
| | 9 | /* |
| | 10 | Name |
| | 11 | vmwrtimg.h - T3 Image File Writer utility functions |
| | 12 | Function |
| | 13 | |
| | 14 | Notes |
| | 15 | |
| | 16 | Modified |
| | 17 | 04/04/99 MJRoberts - Creation |
| | 18 | */ |
| | 19 | |
| | 20 | #ifndef VMWRTIMG_H |
| | 21 | #define VMWRTIMG_H |
| | 22 | |
| | 23 | #include "t3std.h" |
| | 24 | #include "vmtype.h" |
| | 25 | |
| | 26 | |
| | 27 | class CVmImageWriter |
| | 28 | { |
| | 29 | public: |
| | 30 | /* create an image writer with a given output file */ |
| | 31 | CVmImageWriter(class CVmFile *fp); |
| | 32 | |
| | 33 | /* delete the image writer */ |
| | 34 | ~CVmImageWriter(); |
| | 35 | |
| | 36 | /* get the current seek location in the underlying file */ |
| | 37 | long get_pos() const; |
| | 38 | |
| | 39 | /* |
| | 40 | * Prepare the file: write out the fixed header information. This |
| | 41 | * should be called once, before doing any other writing. 'vsn' is |
| | 42 | * the image file version number to store in the file. |
| | 43 | */ |
| | 44 | void prepare(uint vsn, const char tool_data[4]); |
| | 45 | |
| | 46 | /* |
| | 47 | * Begin a block with the specified ID (a four-byte string). Writes |
| | 48 | * the block header, and remembers where the block starts so that |
| | 49 | * the size prefix can be stored when the block is finished. Blocks |
| | 50 | * cannot be nested; starting a new block automatically ends the |
| | 51 | * previous block. |
| | 52 | */ |
| | 53 | void begin_block(const char *block_id, int mandatory); |
| | 54 | |
| | 55 | /* |
| | 56 | * End the current block. |
| | 57 | */ |
| | 58 | void end_block(); |
| | 59 | |
| | 60 | /* write raw bytes to the image file */ |
| | 61 | void write_bytes(const char *ptr, uint32 siz); |
| | 62 | |
| | 63 | /* |
| | 64 | * Write a complete entrypoint block, given the code offset of the |
| | 65 | * entrypoint and the various table entry sizes. If a block is in |
| | 66 | * progress, this will terminate it. |
| | 67 | */ |
| | 68 | void write_entrypt(uint32 entry_ofs, size_t method_header_size, |
| | 69 | size_t exc_entry_size, size_t line_entry_size, |
| | 70 | size_t dbg_hdr_size, size_t dbg_lclsym_hdr_size, |
| | 71 | int dbg_vsn_id); |
| | 72 | |
| | 73 | /* |
| | 74 | * Write a complete function set dependency block, given an array of |
| | 75 | * function set names. If a block is in progress, this will |
| | 76 | * terminate it. |
| | 77 | */ |
| | 78 | void write_func_dep(const char **funcset_names, int count); |
| | 79 | |
| | 80 | /* |
| | 81 | * Write a complete metaclass dependency block, given an array of |
| | 82 | * metaclass names. If a block is in progress, this will terminate |
| | 83 | * it. |
| | 84 | */ |
| | 85 | void write_meta_dep(const char **metaclass_names, int count); |
| | 86 | |
| | 87 | /* |
| | 88 | * Write a metaclass dependency block in pieces. Call |
| | 89 | * begin_meta_dep() with the number of metaclasses, then call |
| | 90 | * write_meta_dep_item() to write each item, and finally call |
| | 91 | * end_meta_dep() to finish the block. |
| | 92 | */ |
| | 93 | void begin_meta_dep(int count); |
| | 94 | void write_meta_dep_item(const char *metaclass_name); |
| | 95 | void write_meta_item_prop(uint prop_id); |
| | 96 | void end_meta_prop_list(); |
| | 97 | void end_meta_dep(); |
| | 98 | |
| | 99 | /* |
| | 100 | * Write a function set dependency block in pieces |
| | 101 | */ |
| | 102 | void begin_func_dep(int count) |
| | 103 | { begin_dep_block("FNSD", count); } |
| | 104 | void write_func_dep_item(const char *funcset_name) |
| | 105 | { write_dep_block_item(funcset_name); } |
| | 106 | void end_func_dep() |
| | 107 | { end_dep_block(); } |
| | 108 | |
| | 109 | /* |
| | 110 | * Write a constant pool definition block. |
| | 111 | */ |
| | 112 | void write_pool_def(uint pool_id, uint32 page_count, uint32 page_size, |
| | 113 | int mandatory); |
| | 114 | |
| | 115 | /* |
| | 116 | * Fix up a constant pool definition block with the actual number of |
| | 117 | * pages. This can be used, if desired, to wait to determine the |
| | 118 | * actual number of pages in a given constant pool until after |
| | 119 | * writing the pages. Since the pool definition block must precede |
| | 120 | * the pool's first page block in the image file, it's impossible to |
| | 121 | * wait until after writing all of the pages to write the definition |
| | 122 | * block. Instead, the caller must write the pool definition block |
| | 123 | * first, using a temporary placeholder value for the page_count (0 |
| | 124 | * will suffice), then write the pool pages, then use this to fix up |
| | 125 | * the pool definition block with the actual number of pages. The |
| | 126 | * caller must note the seek position prior to writing the pool |
| | 127 | * definition block, so that we can seek back to that position to |
| | 128 | * fix up the definition block. |
| | 129 | * |
| | 130 | * Callers need not use this function if they know the actual number |
| | 131 | * of pages in the pool when writing the original pool definition |
| | 132 | * block. |
| | 133 | */ |
| | 134 | void fix_pool_def(long def_seek_ofs, uint32 page_count); |
| | 135 | |
| | 136 | /* |
| | 137 | * Write a constant/code pool page. This writes the entire page |
| | 138 | * with its header and data in a single operation; this is the |
| | 139 | * easiest way to write a page when the page has been fully |
| | 140 | * constructed in a single memory block in advance. |
| | 141 | */ |
| | 142 | void write_pool_page(uint pool_id, uint32 page_index, |
| | 143 | const char *page_data, uint32 page_data_size, |
| | 144 | int mandatory, uchar xor_mask); |
| | 145 | |
| | 146 | /* |
| | 147 | * Write a constant/code pool page in pieces. These routines can be |
| | 148 | * used when the data in the page are not contiguous in memory and |
| | 149 | * must be written in pieces. Start by calling begin_pool_page(), |
| | 150 | * then call write_pool_page_bytes() for each item; the items are |
| | 151 | * written contiguously to the page. Finish by calling |
| | 152 | * end_pool_page(). |
| | 153 | */ |
| | 154 | void begin_pool_page(uint pool_id, uint32 page_index, int mandatory, |
| | 155 | uchar xor_mask); |
| | 156 | void write_pool_page_bytes(const char *buf, uint32 siz, uchar xor_mask); |
| | 157 | void end_pool_page(); |
| | 158 | |
| | 159 | /* |
| | 160 | * Write items in the symbolic names block. Start with |
| | 161 | * begin_sym_block(), then call the write_sym_item_xxx() functions |
| | 162 | * to write the names. Finally, call end_sym_block() when done. |
| | 163 | */ |
| | 164 | void begin_sym_block(); |
| | 165 | |
| | 166 | void write_sym_item_objid(const char *nm, size_t len, ulong obj_id); |
| | 167 | void write_sym_item_propid(const char *nm, size_t len, uint prop_id); |
| | 168 | void write_sym_item_func(const char *nm, size_t len, ulong code_ofs); |
| | 169 | void write_sym_item(const char *nm, size_t nmlen, |
| | 170 | const struct vm_val_t *val); |
| | 171 | |
| | 172 | void write_sym_item_objid(const char *nm, ulong obj_id) |
| | 173 | { write_sym_item_objid(nm, get_strlen(nm), obj_id); } |
| | 174 | void write_sym_item_propid(const char *nm, uint prop_id) |
| | 175 | { write_sym_item_propid(nm, get_strlen(nm), prop_id); } |
| | 176 | void write_sym_item(const char *nm, const struct vm_val_t *val) |
| | 177 | { write_sym_item(nm, get_strlen(nm), val); } |
| | 178 | |
| | 179 | void end_sym_block(); |
| | 180 | |
| | 181 | |
| | 182 | /* |
| | 183 | * Write items in an OBJS (static object data) block. Start with |
| | 184 | * begin_objs_block(), then call write_objs_bytes() repeatedly to |
| | 185 | * write the bytes. Finally, call end_objs_block() when done. |
| | 186 | * |
| | 187 | * If the 'large_objects' field is set, the objects in the block use |
| | 188 | * 32-bit size fields; otherwise the objects use 16-bit size fields. |
| | 189 | * |
| | 190 | * If 'trans' is true, the objects in this block are transient; |
| | 191 | * otherwise, the objects are non-transient (i.e., persistent). |
| | 192 | */ |
| | 193 | void begin_objs_block(uint metaclass_idx, int large_objects, int trans); |
| | 194 | void write_objs_bytes(const char *buf, uint32 siz); |
| | 195 | void end_objs_block(uint object_count); |
| | 196 | |
| | 197 | /* |
| | 198 | * Write the items in a SRCF (source file descriptor) block. Start |
| | 199 | * with begin_srcf_block(), then write the file entries. For each |
| | 200 | * entry, call begin_src_entry(), then call write_src_line_entry() |
| | 201 | * for each source line debug record, then call end_srcf_entry(). |
| | 202 | * Call end_srcf_block() when done with all file entries. |
| | 203 | */ |
| | 204 | void begin_srcf_block(int count); |
| | 205 | void begin_srcf_entry(int orig_index, const char *fname); |
| | 206 | void write_srcf_line_entry(ulong linenum, ulong addr); |
| | 207 | void end_srcf_entry(); |
| | 208 | void end_srcf_block(); |
| | 209 | |
| | 210 | /* |
| | 211 | * Write the items in a GSYM (global symbol table) block. Start |
| | 212 | * with begin_gsym_block(), then call write_gsym_entry() repeatedly |
| | 213 | * to write the entries. Call end_gsym_block() when done. |
| | 214 | */ |
| | 215 | void begin_gsym_block(); |
| | 216 | void write_gsym_entry(const char *sym, size_t sym_len, |
| | 217 | int type_id, const char *dat, size_t dat_len); |
| | 218 | void end_gsym_block(ulong count); |
| | 219 | |
| | 220 | /* |
| | 221 | * Begin MHLS block, write an item, and end the block |
| | 222 | */ |
| | 223 | void begin_mhls_block(); |
| | 224 | void write_mhls_entry(ulong code_addr); |
| | 225 | void end_mhls_block(); |
| | 226 | |
| | 227 | /* |
| | 228 | * Begin/end SINI block. static_cs_ofs is the offset in the code |
| | 229 | * segment of the first static initializer; this is useful in the |
| | 230 | * image file because we can delete all of the code pages starting |
| | 231 | * at this point after pre-initialization is complete. |
| | 232 | */ |
| | 233 | void begin_sini_block(ulong static_cs_ofs, ulong init_cnt); |
| | 234 | void end_sini_block(); |
| | 235 | |
| | 236 | /* begin/end a MACR (macro symbols) block */ |
| | 237 | void begin_macr_block(); |
| | 238 | void end_macr_block(); |
| | 239 | |
| | 240 | /* |
| | 241 | * Finish the file. Automatically ends the current block if a block |
| | 242 | * is open, and writes the end-of-file marker. |
| | 243 | */ |
| | 244 | void finish(); |
| | 245 | |
| | 246 | /* |
| | 247 | * get the underlying file object; for some types of blocks, it's |
| | 248 | * simplest for the caller to write the data directly to the underlying |
| | 249 | * file stream without any help from us |
| | 250 | */ |
| | 251 | class CVmFile *get_fp() const { return fp_; } |
| | 252 | |
| | 253 | private: |
| | 254 | /* write a generic dependency (function set, metaclass) block */ |
| | 255 | void write_dep_block(const char *block_id, const char **names, int count); |
| | 256 | |
| | 257 | /* write a dependency block in pieces */ |
| | 258 | void begin_dep_block(const char *block_id, int count); |
| | 259 | void write_dep_block_item(const char *nm); |
| | 260 | void end_dep_block(); |
| | 261 | |
| | 262 | /* XOR a block of bytes with a mask and write the results to the file */ |
| | 263 | void xor_and_write_bytes(const char *p, uint32 len, uchar xor_mask); |
| | 264 | |
| | 265 | /* underlying file */ |
| | 266 | class CVmFile *fp_; |
| | 267 | |
| | 268 | /* |
| | 269 | * Seek position of start of current block. If this is zero, no |
| | 270 | * block is currently open. |
| | 271 | */ |
| | 272 | long block_start_; |
| | 273 | |
| | 274 | /* count of symbolic names written so far (for writing SYMD block) */ |
| | 275 | int symd_cnt_; |
| | 276 | |
| | 277 | /* location of metaclass entry next-record offset */ |
| | 278 | long mcld_ofs_pos_; |
| | 279 | |
| | 280 | /* location of metaclass property list count prefix */ |
| | 281 | long mcld_propcnt_pos_; |
| | 282 | |
| | 283 | /* count of properties writeen in a metaclass prop list so far */ |
| | 284 | int mcld_prop_cnt_; |
| | 285 | |
| | 286 | /* seek location of SYMD count prefix, for fixing up at end of block */ |
| | 287 | long symd_prefix_; |
| | 288 | |
| | 289 | /* seek location of OBJS count prefix, for fixup up at end of block */ |
| | 290 | long objs_prefix_; |
| | 291 | |
| | 292 | /* seek location of GSYM count prefix, for fixup at end of block */ |
| | 293 | long gsym_prefix_; |
| | 294 | |
| | 295 | /* start of current SRCF file entry */ |
| | 296 | long srcf_entry_pos_; |
| | 297 | |
| | 298 | /* count of SRCF line entries */ |
| | 299 | long srcf_line_cnt_; |
| | 300 | |
| | 301 | /* position of SRCF line entry for the current file */ |
| | 302 | long srcf_line_pos_; |
| | 303 | |
| | 304 | /* position of MHLS block count entry, and MHLS entry count so far */ |
| | 305 | long mhls_cnt_pos_; |
| | 306 | ulong mhls_cnt_; |
| | 307 | }; |
| | 308 | |
| | 309 | #endif /* VMWRTIMG_H */ |
| | 310 | |