3
"$Header: d:/cvsroot/tads/tads3/vmwrtimg.cpp,v 1.4 1999/07/11 00:46:59 MJRoberts Exp $";
7
* Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved.
9
* Please see the accompanying license file, LICENSE.TXT, for information
10
* on using and copying this software.
14
vmwrtimg.cpp - T3 Image File Writer utility functions
16
Provides functions to write an image file
20
04/04/99 MJRoberts - Creation
32
/* ------------------------------------------------------------------------ */
36
CVmImageWriter::CVmImageWriter(CVmFile *fp)
38
/* remember the underlying file */
41
/* no block is currently open */
48
CVmImageWriter::~CVmImageWriter()
52
/* ------------------------------------------------------------------------ */
54
* get the current seek position in the underlying file
56
long CVmImageWriter::get_pos() const
58
return fp_->get_pos();
61
/* ------------------------------------------------------------------------ */
63
* Prepare the file - write the header.
65
void CVmImageWriter::prepare(uint vsn, const char tool_data[4])
71
/* write the signature */
72
fp_->write_bytes(VMIMAGE_SIG, sizeof(VMIMAGE_SIG)-1);
74
/* write the version number */
77
/* write the 28 reserved bytes, setting all to zero */
79
fp_->write_bytes(buf, 28);
81
/* write the additional 4 bytes reserved for tool use */
82
fp_->write_bytes(tool_data, 4);
84
/* write the compilation timestamp */
86
tblock = localtime(&timer);
87
fp_->write_bytes(asctime(tblock), 24);
90
/* ------------------------------------------------------------------------ */
94
void CVmImageWriter::begin_block(const char *block_id, int mandatory)
99
/* if there's a block currently open, close it */
102
/* remember the seek location of the start of the block */
103
block_start_ = fp_->get_pos();
105
/* store the type string */
106
memcpy(buf, block_id, 4);
108
/* store four bytes of zeroes as a placeholder for the size */
111
/* compute the flags */
114
flags |= VMIMAGE_DBF_MANDATORY;
116
/* store the flags */
119
/* write the header */
120
fp_->write_bytes(buf, 10);
123
/* ------------------------------------------------------------------------ */
125
* End the current block. If no block is open, this does nothing.
127
void CVmImageWriter::end_block()
132
/* if there's no block open, there's nothing we need to do */
133
if (block_start_ == 0)
137
* note the current file position - this will let us compute the
138
* size of the block, and we'll need to seek back here when we're
139
* done updating the block header
141
end_pos = fp_->get_pos();
144
* Since the block is finished, we can now compute its size. The
145
* size of the data block is the end seek position minus the
146
* starting seek position. 'block_start_' contains the seek
147
* position of the block header, which takes up ten bytes; we want
148
* to store the size of the block's data, excluding the header,
149
* which is (end_pos - block_header_pos - 10).
151
siz = (uint32)(end_pos - block_start_ - 10);
154
* Seek back to the location of the size field in the block header;
155
* this is four bytes into the block header. Then, update the size
156
* field with the size of the block's data.
158
fp_->set_pos(block_start_ + 4);
159
fp_->write_int4(siz);
162
* seek back to the end of the block, so we can resume writing data
163
* following the block
165
fp_->set_pos(end_pos);
167
/* the block is now closed, so forget about it */
171
/* ------------------------------------------------------------------------ */
173
* Write raw bytes to the file
175
void CVmImageWriter::write_bytes(const char *ptr, uint32 siz)
177
/* write in 64k chunks, to accommodate 16-bit platforms */
182
/* get the next 64k, or the remainder if less than 64k is left */
187
/* write this chunk */
188
fp_->write_bytes(ptr, cur);
190
/* advance past this chunk */
196
/* ------------------------------------------------------------------------ */
198
* Finish the file. Closes the current block if one is open, and writes
199
* the end-of-file marker to the file.
201
void CVmImageWriter::finish()
203
/* if there's a block open, close it */
207
* write the EOF block - the block contains no data, so simply begin
210
begin_block("EOF ", TRUE);
214
/* ------------------------------------------------------------------------ */
216
* Write an entrypoint (ENTP) block
218
void CVmImageWriter::write_entrypt(uint32 entry_ofs, size_t method_hdr_size,
219
size_t exc_entry_size,
220
size_t line_entry_size,
222
size_t dbg_lclsym_hdr_size,
227
/* prepare the block's contents */
228
oswp4(buf, entry_ofs);
229
oswp2(buf+4, method_hdr_size);
230
oswp2(buf+6, exc_entry_size);
231
oswp2(buf+8, line_entry_size);
232
oswp2(buf+10, dbg_hdr_size);
233
oswp2(buf+12, dbg_lclsym_hdr_size);
234
oswp2(buf+14, dbg_vsn_id);
236
/* open the block, write the data, and close the block */
237
begin_block("ENTP", TRUE);
238
fp_->write_bytes(buf, 16);
242
/* ------------------------------------------------------------------------ */
244
* Write a function set dependency block
246
void CVmImageWriter::write_func_dep(const char **funcset_names, int count)
248
/* write a FNSD block */
249
write_dep_block("FNSD", funcset_names, count);
252
/* ------------------------------------------------------------------------ */
254
* begin a metaclass dependency block
256
void CVmImageWriter::begin_meta_dep(int count)
258
/* begin the dependency block */
259
begin_dep_block("MCLD", count);
261
/* we're not in a property list yet */
262
mcld_propcnt_pos_ = 0;
266
* Write a metaclass dependency block
268
void CVmImageWriter::write_meta_dep(const char **meta_names, int count)
270
/* write a MCLD block */
271
write_dep_block("MCLD", meta_names, count);
275
* write a metaclass dependency block item
277
void CVmImageWriter::write_meta_dep_item(const char *metaclass_name)
279
/* if we didn't end the previous item's property list, end it now */
280
end_meta_prop_list();
282
/* write a placeholder next record offset */
283
mcld_ofs_pos_ = fp_->get_pos();
286
/* write the metaclass name */
287
write_dep_block_item(metaclass_name);
289
/* write a placeholder property vector count */
290
mcld_propcnt_pos_ = fp_->get_pos();
293
/* write the property record size (2 bytes) */
296
/* no properties yet */
301
* write a metaclass dependency property list item
303
void CVmImageWriter::write_meta_item_prop(uint prop_id)
305
/* write the property ID */
306
fp_->write_int2(prop_id);
313
* end a metaclass prop list
315
void CVmImageWriter::end_meta_prop_list()
317
/* if we have a count pending, go write it */
318
if (mcld_propcnt_pos_ != 0)
322
/* remember the current position */
323
pos = fp_->get_pos();
325
/* go back and write the property count */
326
fp_->set_pos(mcld_propcnt_pos_);
327
fp_->write_int2(mcld_prop_cnt_);
329
/* we no longer have a property count fixup to apply */
330
mcld_propcnt_pos_ = 0;
332
/* go back and write the next-record offset */
333
fp_->set_pos(mcld_ofs_pos_);
334
fp_->write_int2((int)(pos - mcld_ofs_pos_));
336
/* go back to the end of the record */
342
* end a metaclass dependency block
344
void CVmImageWriter::end_meta_dep()
346
/* end the last metaclass item */
347
end_meta_prop_list();
349
/* end the dependency block */
353
/* ------------------------------------------------------------------------ */
355
* Begin a dependency block
357
void CVmImageWriter::begin_dep_block(const char *block_id, int count)
362
begin_block(block_id, TRUE);
364
/* write the number of entries */
366
fp_->write_bytes(buf, 2);
370
* Write a dependency block item
372
void CVmImageWriter::write_dep_block_item(const char *nm)
377
/* get the length of this name, and truncate to 255 bytes */
382
/* write the length, followed by the name */
383
buf[0] = (char)(uchar)len;
384
fp_->write_bytes(buf, 1);
385
fp_->write_bytes(nm, len);
389
* End a dependency block
391
void CVmImageWriter::end_dep_block()
397
/* ------------------------------------------------------------------------ */
399
* Write a generic dependency list block
401
void CVmImageWriter::write_dep_block(const char *block_id,
402
const char **names, int count)
405
begin_dep_block(block_id, count);
407
/* write each entry */
408
for ( ; count > 0 ; ++names, --count)
409
write_dep_block_item(*names);
415
/* ------------------------------------------------------------------------ */
417
* Write a constant pool definition block
419
void CVmImageWriter::write_pool_def(uint pool_id, uint32 page_count,
420
uint32 page_size, int mandatory)
424
/* prepare the block's data */
426
oswp4(buf+2, page_count);
427
oswp4(buf+6, page_size);
429
/* open the block, write the data, and end the block */
430
begin_block("CPDF", mandatory);
431
fp_->write_bytes(buf, 10);
436
* Fix up a pool definition block with the actual page count
438
void CVmImageWriter::fix_pool_def(long def_seek_ofs, uint32 page_count)
443
/* note the file position at entry */
444
old_pos = fp_->get_pos();
447
* seek to the original definition block location, plus the size of
448
* the block header (10 bytes), plus the offset within the block of
449
* the pool page count (it starts 2 bytes into the block data)
451
fp_->set_pos(def_seek_ofs + 10 + 2);
453
/* write the page count */
454
oswp4(buf, page_count);
455
fp_->write_bytes(buf, 4);
457
/* seek back to our location at entry */
458
fp_->set_pos(old_pos);
462
/* ------------------------------------------------------------------------ */
464
* Write a constant pool page
466
void CVmImageWriter::write_pool_page(uint pool_id, uint32 page_index,
467
const char *page_data,
468
uint32 page_data_size, int mandatory,
473
/* begin the block */
474
begin_block("CPPG", mandatory);
476
/* prepare the prefix */
478
oswp4(buf+2, page_index);
481
/* write the prefix */
482
fp_->write_bytes(buf, 7);
484
/* write the page data, XOR'ing the data with the mask byte */
485
xor_and_write_bytes(page_data, page_data_size, xor_mask);
491
/* ------------------------------------------------------------------------ */
493
* Begin writing a constant pool page. This constructs the header and
494
* prepares for writing the bytes making up the page.
496
void CVmImageWriter::begin_pool_page(uint pool_id, uint32 page_index,
497
int mandatory, uchar xor_mask)
501
/* begin the block */
502
begin_block("CPPG", mandatory);
504
/* prepare the prefix */
506
oswp4(buf+2, page_index);
509
/* write the prefix */
510
fp_->write_bytes(buf, 7);
514
* write bytes to a pool page under construction
516
void CVmImageWriter::write_pool_page_bytes(const char *buf, uint32 siz,
519
/* write the page data, XOR'ing the data with the mask byte */
520
xor_and_write_bytes(buf, siz, xor_mask);
524
* XOR and write a block of data - we will XOR each byte of the data
525
* with the given mask byte before writing it to the file
527
void CVmImageWriter::xor_and_write_bytes(const char *mem, uint32 siz,
531
* if there's no mask, simply write the data directly - anything XOR
532
* zero equals the original value
536
/* write the data to the page */
537
fp_->write_bytes(mem, siz);
542
* copy the data in chunks into our buffer, XOR it with the
543
* mask, and write the results
553
* limit this chunk to the buffer size or the remainder of
554
* the input, whichever is smaller
560
/* copy this chunk, xor'ing each byte with the mask */
561
for (dst = buf, rem = cur ; rem != 0 ; --rem, ++dst, ++mem)
562
*dst = *mem ^ xor_mask;
564
/* write out this chunk */
565
fp_->write_bytes(buf, cur);
567
/* subtract this chunk from the length remaining */
574
* finish writing a pool page
576
void CVmImageWriter::end_pool_page()
582
/* ------------------------------------------------------------------------ */
584
* Begin a symbolic names block
586
void CVmImageWriter::begin_sym_block()
590
/* begin the block */
591
begin_block("SYMD", FALSE);
593
/* remember where our placeholder goes */
594
symd_prefix_ = fp_->get_pos();
596
/* prepare the placeholder prefix, using a zero count for now */
599
/* write the prefix */
600
fp_->write_bytes(buf, 2);
602
/* we haven't written any symbolic name items yet */
607
* write a symbolic name for an object ID
609
void CVmImageWriter::write_sym_item_objid(const char *nm, size_t len,
614
/* set up the object ID value */
615
val.set_obj((vm_obj_id_t)obj_id);
618
write_sym_item(nm, len, &val);
622
* write a symbolic name for a property ID
624
void CVmImageWriter::write_sym_item_propid(const char *nm, size_t len,
629
/* set up the property ID value */
630
val.set_propid((vm_prop_id_t)prop_id);
633
write_sym_item(nm, len, &val);
637
* write a symbolic name for a function
639
void CVmImageWriter::write_sym_item_func(const char *nm, size_t len,
644
/* set up the property ID value */
645
val.set_fnptr((pool_ofs_t)code_ofs);
648
write_sym_item(nm, len, &val);
652
* write a symbolic name item
654
void CVmImageWriter::write_sym_item(const char *nm, size_t len,
657
char buf[VMB_DATAHOLDER + 1];
659
/* prepare the data holder in the prefix */
660
vmb_put_dh(buf, val);
662
/* limit the length to 255 bytes */
666
/* add the length to the prefix */
667
buf[VMB_DATAHOLDER] = (char)len;
669
/* write the prefix */
670
fp_->write_bytes(buf, VMB_DATAHOLDER + 1);
672
/* write the string */
673
fp_->write_bytes(nm, len);
680
* end a symbolic names block
682
void CVmImageWriter::end_sym_block()
691
* Go back and fix the header with the number of items we wrote.
692
* First, remember our current position, then seek back to the count
695
old_pos = fp_->get_pos();
696
fp_->set_pos(symd_prefix_);
698
/* prepare the prefix, and write it out */
699
oswp2(buf, symd_cnt_);
700
fp_->write_bytes(buf, 2);
702
/* restore the file position */
703
fp_->set_pos(old_pos);
706
/* ------------------------------------------------------------------------ */
708
* Begin an object static data block
710
void CVmImageWriter::begin_objs_block(uint metaclass_idx, int large_objects,
716
/* begin the block */
717
begin_block("OBJS", TRUE);
719
/* prepare the flags */
726
/* remember where the prefix goes so we can fix it up later */
727
objs_prefix_ = fp_->get_pos();
730
* write a placeholder object count, the metaclass dependency table
731
* index, and the OBJS flags
734
oswp2(buf + 2, metaclass_idx);
735
oswp2(buf + 4, flags);
737
/* write the prefix */
738
fp_->write_bytes(buf, 6);
742
* Write bytes to an OBJS (object static data) block
744
void CVmImageWriter::write_objs_bytes(const char *buf, uint32 siz)
746
/* write the buffer */
747
fp_->write_bytes(buf, siz);
751
* end an object static data block
753
void CVmImageWriter::end_objs_block(uint object_count)
757
/* remember the current file write position for a moment */
758
pos = fp_->get_pos();
760
/* go back and fix up the object count in the header */
761
fp_->set_pos(objs_prefix_);
762
fp_->write_int2(object_count);
764
/* seek back to the original position */
771
/* ------------------------------------------------------------------------ */
773
* SRCF blocks - source file descriptors
779
void CVmImageWriter::begin_srcf_block(int count)
782
* begin the block - SRCF blocks are always optional, since they're
783
* purely for debugging purposes
785
begin_block("SRCF", FALSE);
787
/* write the number of entries */
788
fp_->write_int2(count);
790
/* each source line record is 8 bytes in the current format */
795
* begin a SRCF file entry
797
void CVmImageWriter::begin_srcf_entry(int orig_index, const char *fname)
801
/* remember where this entry starts, so we can fix up the size later */
802
srcf_entry_pos_ = fp_->get_pos();
804
/* write a placeholder size entry */
807
/* write the original index */
808
fp_->write_int2(orig_index);
810
/* write the length of the name */
811
len = get_strlen(fname);
812
fp_->write_int2(len);
814
/* write the filename */
815
fp_->write_bytes(fname, len);
817
/* we have no line record yet, so write a placeholder count */
818
srcf_line_pos_ = fp_->get_pos();
824
* write a SRCF line record entry
826
void CVmImageWriter::write_srcf_line_entry(ulong linenum, ulong addr)
828
/* write the line number and address */
829
fp_->write_int4(linenum);
830
fp_->write_int4(addr);
837
* end a SRCF file entry
839
void CVmImageWriter::end_srcf_entry()
843
/* go back and fix up the line record count */
844
pos = fp_->get_pos();
845
fp_->set_pos(srcf_line_pos_);
846
fp_->write_int4(srcf_line_cnt_);
848
/* go back and fix up the total entry size record */
849
fp_->set_pos(srcf_entry_pos_);
850
fp_->write_int4(pos - srcf_entry_pos_);
852
/* seek back to the end of the block */
860
void CVmImageWriter::end_srcf_block()
862
/* end the block using the generic mechanism */
866
/* ------------------------------------------------------------------------ */
868
* MACR blocks - global preprocess macro symbol table
874
void CVmImageWriter::begin_macr_block()
877
* write the header - it's an optional block since it's for the
878
* debugger's use only
880
begin_block("MACR", FALSE);
886
void CVmImageWriter::end_macr_block()
888
/* end the block using the generic mechanism */
892
/* ------------------------------------------------------------------------ */
894
* GSYM blocks - global symbol table
900
void CVmImageWriter::begin_gsym_block()
903
* begin the block - GSYM blocks are always optional, since they're
904
* purely for debugging purposes
906
begin_block("GSYM", FALSE);
908
/* remember where the prefix goes so we can fix it up later */
909
gsym_prefix_ = fp_->get_pos();
911
/* write a placehodler object count and the metaclass index */
918
void CVmImageWriter::write_gsym_entry(const char *sym, size_t sym_len,
920
const char *dat, size_t dat_len)
923
* write the length of the symbol, length of the extra data, and the
926
fp_->write_int2(sym_len);
927
fp_->write_int2(dat_len);
928
fp_->write_int2(type_id);
930
/* write the symbol name */
931
fp_->write_bytes(sym, sym_len);
933
/* write the extra data */
934
fp_->write_bytes(dat, dat_len);
940
void CVmImageWriter::end_gsym_block(ulong cnt)
944
/* remember the current file write position for a moment */
945
pos = fp_->get_pos();
947
/* go back and fix up the count in the header */
948
fp_->set_pos(gsym_prefix_);
949
fp_->write_int4(cnt);
951
/* seek back to the original position */
954
/* end the block using the generic mechanism */
958
/* ------------------------------------------------------------------------ */
960
* MHLS blocks - method header list
964
* begin an MHLS block
966
void CVmImageWriter::begin_mhls_block()
969
* begin the block - MHLS blocks are always optional, since they're
970
* purely for debugging purposes
972
begin_block("MHLS", FALSE);
974
/* remember where the count goes so we can fix it up later */
975
mhls_cnt_pos_ = fp_->get_pos();
977
/* write a placehodler count */
980
/* there are no entries yet */
985
* write an MHLS entry
987
void CVmImageWriter::write_mhls_entry(ulong addr)
989
/* write the address */
990
fp_->write_int4(addr);
992
/* count the entry */
999
void CVmImageWriter::end_mhls_block()
1003
/* remember the current file write position for a moment */
1004
pos = fp_->get_pos();
1006
/* go back and fix up the count in the header */
1007
fp_->set_pos(mhls_cnt_pos_);
1008
fp_->write_int4(mhls_cnt_);
1010
/* seek back to the original position */
1013
/* end the block using the generic mechanism */
1017
/* ------------------------------------------------------------------------ */
1019
* SINI block - static initializer list
1023
* begin an SINI block
1025
void CVmImageWriter::begin_sini_block(ulong static_cs_ofs, ulong init_cnt)
1028
* begin the block - SINI blocks are mandatory, since the program
1029
* depends upon static initializers being evaluated immediately
1032
begin_block("SINI", TRUE);
1035
* write the size of our header (including the size prefix); this
1036
* serves as a simple versioning flag so we can tell if fields added
1037
* at a later date are part of a given image file's data or not (if
1038
* the header is too small to contain them, they're not present)
1040
fp_->write_int4(12);
1042
/* write the starting static code segment offset */
1043
fp_->write_int4(static_cs_ofs);
1045
/* write the initializer count */
1046
fp_->write_int4(init_cnt);
1052
void CVmImageWriter::end_sini_block()
1054
/* end the block using the generic mechanism */