1066 lines
39 KiB
C++
1066 lines
39 KiB
C++
|
/**************************** omf.cpp *********************************
|
||
|
* Author: Agner Fog
|
||
|
* Date created: 2007-01-29
|
||
|
* Last modified: 2018-05-26
|
||
|
* Project: objconv
|
||
|
* Module: omf.cpp
|
||
|
* Description:
|
||
|
* Module for reading OMF files
|
||
|
*
|
||
|
* Class COMF is used for reading, interpreting and dumping OMF files.
|
||
|
*
|
||
|
* Copyright 2007-2018 GNU General Public License http://www.gnu.org/licenses
|
||
|
*****************************************************************************/
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
// OMF Record type names
|
||
|
SIntTxt OMFRecordTypeNames[] = {
|
||
|
{OMF_THEADR, "Translator Header"},
|
||
|
{OMF_LHEADR, "Library Module Header"},
|
||
|
{OMF_COMENT, "Comment"},
|
||
|
{OMF_MODEND, "Module End"},
|
||
|
{OMF_EXTDEF, "External Names Definition"},
|
||
|
{OMF_PUBDEF, "Public Names Definition"},
|
||
|
{OMF_LINNUM, "Line Numbers"},
|
||
|
{OMF_LNAMES, "List of Names"},
|
||
|
{OMF_SEGDEF, "Segment Definition"},
|
||
|
{OMF_GRPDEF, "Group Definition"},
|
||
|
{OMF_FIXUPP, "Fixup"},
|
||
|
{OMF_LEDATA, "Enumerated Data"},
|
||
|
{OMF_LIDATA, "Iterated Data"},
|
||
|
{OMF_COMDEF, "Communal Names Definition"},
|
||
|
{OMF_BAKPAT, "Backpatch"},
|
||
|
{OMF_LEXTDEF, "Local External Names"},
|
||
|
{OMF_LPUBDEF, "Local Public Names"},
|
||
|
{OMF_LCOMDEF, "Local Communal Names"},
|
||
|
{OMF_CEXTDEF, "COMDAT External Names"},
|
||
|
{OMF_COMDAT, "Initialized Communal Data"},
|
||
|
{OMF_LINSYM, "Symbol Line Numbers"},
|
||
|
{OMF_ALIAS, "Alias Definition"},
|
||
|
{OMF_NBKPAT, "Named Backpatch"},
|
||
|
{OMF_LLNAMES, "Local Logical Names"},
|
||
|
{OMF_VERNUM, "OMF Version Number"},
|
||
|
{OMF_VENDEXT, "Vendor-specific OMF Extension"},
|
||
|
{OMF_LIBHEAD, "Library Header"},
|
||
|
{OMF_LIBEND, "Library End"}
|
||
|
};
|
||
|
|
||
|
// Segment combination names
|
||
|
SIntTxt OMFSegmentCombinationNames[] = {
|
||
|
{0, "Private"},
|
||
|
{1, "Invalid"},
|
||
|
{2, "Public"},
|
||
|
{3, "Invalid"},
|
||
|
{4, "Public 4"},
|
||
|
{5, "Stack"},
|
||
|
{6, "Common"},
|
||
|
{7, "Public 7"}
|
||
|
};
|
||
|
|
||
|
// Relocation mode names
|
||
|
static SIntTxt OMFRelocationModeNames[] = {
|
||
|
{0, "Relatv"},
|
||
|
{1, "Direct"}
|
||
|
};
|
||
|
|
||
|
|
||
|
// Fixup location names
|
||
|
static SIntTxt OMFFixupLocationNames[] = {
|
||
|
{OMF_Fixup_8bit, "8 bit"}, // 0
|
||
|
{OMF_Fixup_16bit, "16 bit"}, // 1
|
||
|
{OMF_Fixup_Segment, "segment selector, 16 bit"}, // 2
|
||
|
{OMF_Fixup_Far, "far pointer 16+16 bit"}, // 3
|
||
|
{OMF_Fixup_Hi8bit, "high 8 bit of 16 bits"}, // 4
|
||
|
{OMF_Fixup_16bitLoader, "16 bit loader resolved"}, // 5
|
||
|
{OMF_Fixup_Pharlab48, "farword 48 bit, Pharlab only"},// 6
|
||
|
{OMF_Fixup_32bit, "32 bit"}, // 9
|
||
|
{OMF_Fixup_Farword, "farword 32+16 bit"}, // 11
|
||
|
{OMF_Fixup_32bitLoader, "32 bit loader resolved"} // 13
|
||
|
};
|
||
|
|
||
|
// Alignment value translation table
|
||
|
static const uint32 OMFAlignTranslate[8] = {0,1,2,16,256,4,0,0};
|
||
|
|
||
|
|
||
|
// Class COMF members:
|
||
|
// Constructor
|
||
|
|
||
|
COMF::COMF() {
|
||
|
// Default constructor
|
||
|
memset(this, 0, sizeof(*this)); // reset everything
|
||
|
}
|
||
|
|
||
|
|
||
|
void COMF::ParseFile() {
|
||
|
// Parse file buffer
|
||
|
//uint8 RecordType; // Type of current record
|
||
|
uint32 Checksum; // Record checksum
|
||
|
uint32 ChecksumZero = 0; // Count number of records with zero checksum
|
||
|
SOMFRecordPointer rec; // Current record pointer
|
||
|
|
||
|
// Make first entry zero in name lists
|
||
|
LocalNameOffset.PushZero();
|
||
|
SegmentNameOffset.PushZero();
|
||
|
GroupNameOffset.PushZero();
|
||
|
SymbolNameOffset.PushZero();
|
||
|
|
||
|
// Initialize record pointer
|
||
|
rec.Start(Buf(), 0, GetDataSize());
|
||
|
|
||
|
// Loop through records to set record pointers and store names
|
||
|
do {
|
||
|
// Read record
|
||
|
//RecordType = rec.Type2; // First byte of record = type
|
||
|
|
||
|
// Compute checksum
|
||
|
Checksum = 0; rec.Index = 0;
|
||
|
while (rec.Index < rec.End) Checksum += rec.GetByte();
|
||
|
uint32 CheckByte = rec.GetByte();
|
||
|
if ((Checksum + CheckByte) & 0xFF) {
|
||
|
// Checksum failed
|
||
|
if (CheckByte == 0) {
|
||
|
ChecksumZero++;
|
||
|
}
|
||
|
else err.submit(1202); // Checksum error
|
||
|
}
|
||
|
|
||
|
// Store record pointer
|
||
|
rec.Index = 3; // Offset to current byte while parsing
|
||
|
Records.Push(rec); // Store record pointer in list
|
||
|
|
||
|
if (rec.Type2 == OMF_LNAMES) {
|
||
|
// LNAMES record. Store local names by name index
|
||
|
// Loop through strings in record
|
||
|
while (rec.Index < rec.End) {
|
||
|
char * LocalName = rec.GetString();
|
||
|
uint32 LocalNameIndex = NameBuffer.PushString(LocalName); // Store local name
|
||
|
LocalNameOffset.Push(LocalNameIndex);// Store local name index
|
||
|
}
|
||
|
if (rec.Index != rec.End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
|
||
|
if (rec.Type2 == OMF_SEGDEF) {
|
||
|
// SEGDEF record. Store segment names by segment index
|
||
|
OMF_SAttrib Attributes;
|
||
|
if (rec.Type2 == OMF_SEGDEF) {
|
||
|
Attributes.b = rec.GetByte(); // Read attributes
|
||
|
if (Attributes.u.A == 0) {
|
||
|
// Frame and Offset only included if A = 0
|
||
|
rec.GetWord(); rec.GetByte();
|
||
|
}
|
||
|
rec.GetNumeric(); // Length
|
||
|
}
|
||
|
uint32 NameIndex = rec.GetIndex();
|
||
|
if (NameIndex < LocalNameOffset.GetNumEntries()) {
|
||
|
SegmentNameOffset.Push(LocalNameOffset[NameIndex]); // List by segment index
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (rec.Type2 == OMF_GRPDEF) {
|
||
|
// GRPDEF record. Store group name
|
||
|
uint32 NameIndex = rec.GetIndex();
|
||
|
if (NameIndex < LocalNameOffset.GetNumEntries()) {
|
||
|
GroupNameOffset.Push(LocalNameOffset[NameIndex]); // List by group index
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (rec.Type2 == OMF_EXTDEF) {
|
||
|
// EXTDEF record. Store external symbol names
|
||
|
// Loop through strings in record
|
||
|
while (rec.Index < rec.End) {
|
||
|
char * symbolname = rec.GetString();
|
||
|
rec.GetIndex();
|
||
|
uint32 SymbolNameIndex = NameBuffer.PushString(symbolname); // Store external name
|
||
|
SymbolNameOffset.Push(SymbolNameIndex); // Save in name index table
|
||
|
}
|
||
|
if (rec.Index != rec.End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
|
||
|
if (rec.Type2 == OMF_CEXTDEF) {
|
||
|
// CEXTDEF record. Store communal symbol names
|
||
|
// Loop through entries in record
|
||
|
uint32 SymbolNameIndex; // Index into NameBuffer
|
||
|
while (rec.Index < rec.End) {
|
||
|
uint32 LIndex = rec.GetIndex(); // Index into preceding LNAMES
|
||
|
rec.GetIndex(); // Type index. Ignore
|
||
|
// Get name from LocalNameOffset and put into SymbolNameOffset.
|
||
|
if (LIndex < LocalNameOffset.GetNumEntries()) {
|
||
|
SymbolNameIndex = LocalNameOffset[LIndex];
|
||
|
}
|
||
|
else SymbolNameIndex = 0;
|
||
|
SymbolNameOffset.Push(SymbolNameIndex); // Save in name index table
|
||
|
}
|
||
|
if (rec.Index != rec.End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
} // Point to next record
|
||
|
while (rec.GetNext()); // End of loop through records
|
||
|
|
||
|
NumRecords = Records.GetNumEntries(); // Number of records
|
||
|
|
||
|
if (ChecksumZero) printf("\nChecksums are zero"); // This is taken out of the loop to report it only once
|
||
|
}
|
||
|
|
||
|
|
||
|
void COMF::Dump(int options) {
|
||
|
// Dump file
|
||
|
if (options & DUMP_FILEHDR) DumpRecordTypes(); // Dump summary of record types
|
||
|
|
||
|
if (options & DUMP_STRINGTB) DumpNames(); // Dump names records
|
||
|
|
||
|
if (options & DUMP_SYMTAB) DumpSymbols(); // Dump public/external name records
|
||
|
|
||
|
if (options & DUMP_SECTHDR) DumpSegments(); // Dump segment records
|
||
|
|
||
|
if (options & DUMP_RELTAB) DumpRelocations(); // Dump fixup records
|
||
|
|
||
|
if (options & DUMP_COMMENT) DumpComments(); // Dump coment records
|
||
|
}
|
||
|
|
||
|
void COMF::DumpRecordTypes() {
|
||
|
// Dump summary of records
|
||
|
printf("\nSummary of records:");
|
||
|
for (uint32 i = 0; i < NumRecords; i++) {
|
||
|
// Print record type
|
||
|
printf("\n Record %02X, %s%s, total length %i", Records[i].Type,
|
||
|
Lookup(OMFRecordTypeNames, Records[i].Type2),
|
||
|
(Records[i].Type & 1) ? ".32" : "",
|
||
|
Records[i].End+1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void COMF::DumpNames() {
|
||
|
// Dump local names records
|
||
|
uint32 i; // Record index
|
||
|
uint32 ln = 0; // Local name index
|
||
|
printf("\n\nLocal names:");
|
||
|
for (i = 0; i < NumRecords; i++) {
|
||
|
if (Records[i].Type2 == OMF_LNAMES) {
|
||
|
// LNAMES record. There should be only one
|
||
|
// Loop through strings in record
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
printf("\n %2i %s", ++ln, Records[i].GetString());
|
||
|
}
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
|
||
|
if (Records[i].Type2 == OMF_THEADR || Records[i].Type2 == OMF_LHEADR) {
|
||
|
// Module header record
|
||
|
// Loop through strings in record
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
printf("\n Module: %s\n", Records[i].GetString());
|
||
|
}
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
if (Records[i].Type2 == OMF_COMDEF) {
|
||
|
// COMDEF record. Communal names
|
||
|
uint32 DType, DSize, DNum;
|
||
|
printf("\n\n Communal names:");
|
||
|
|
||
|
// Loop through strings in record
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
printf("\n \"%s\":", Records[i].GetString());
|
||
|
printf(" %i", Records[i].GetByte()); // Type index, should be 0
|
||
|
DType = Records[i].GetByte(); // Data type
|
||
|
switch (DType) {
|
||
|
case 0x61:
|
||
|
DNum = Records[i].GetLength();
|
||
|
DSize = Records[i].GetLength();
|
||
|
printf(" FAR: %i*%i bytes", DNum, DSize);
|
||
|
break;
|
||
|
case 0x62:
|
||
|
DSize = Records[i].GetLength();
|
||
|
printf(" NEAR: 0x%X bytes", DSize);
|
||
|
break;
|
||
|
default:
|
||
|
DSize = Records[i].GetLength();
|
||
|
if (DType < 0x60) { // Borland segment index
|
||
|
printf(" segment %i, size 0x%X", DType, DSize);
|
||
|
break;
|
||
|
}
|
||
|
printf(" unknown type %i, size 0x%X", DType, DSize);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void COMF::DumpSymbols() {
|
||
|
// Dump public, external and communal names records
|
||
|
uint32 i; // Record index
|
||
|
uint32 xn = 0; // External name index
|
||
|
char * string;
|
||
|
uint32 TypeIndex;
|
||
|
uint32 Group;
|
||
|
uint32 Segment;
|
||
|
uint32 BaseFrame;
|
||
|
uint32 Offset;
|
||
|
|
||
|
for (i = 0; i < NumRecords; i++) {
|
||
|
if (Records[i].Type2 == OMF_EXTDEF) {
|
||
|
// EXTDEF record.
|
||
|
Records[i].Index = 3;
|
||
|
printf("\n\nExternal names:");
|
||
|
|
||
|
// Loop through strings in record
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
string = Records[i].GetString();
|
||
|
TypeIndex = Records[i].GetIndex();
|
||
|
printf("\n %2i %s, Type %i", ++xn, string, TypeIndex);
|
||
|
}
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
|
||
|
if (Records[i].Type2 == OMF_PUBDEF) {
|
||
|
// PUBDEF record.
|
||
|
printf("\n\nPublic names:");
|
||
|
Records[i].Index = 3;
|
||
|
Group = Records[i].GetIndex();
|
||
|
Segment = Records[i].GetIndex();
|
||
|
BaseFrame = 0;
|
||
|
if (Segment == 0) BaseFrame = Records[i].GetWord();
|
||
|
// Loop through strings in record
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
string = Records[i].GetString();
|
||
|
Offset = Records[i].GetNumeric();
|
||
|
TypeIndex = Records[i].GetIndex();
|
||
|
printf("\n %s, Segment %s, Group %s, Offset 0x%X, Type %i",
|
||
|
string, GetSegmentName(Segment), GetGroupName(Group), Offset, TypeIndex);
|
||
|
if (BaseFrame) printf(", Frame %i", BaseFrame);
|
||
|
}
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
|
||
|
if (Records[i].Type2 == OMF_CEXTDEF) {
|
||
|
// CEXTDEF record.
|
||
|
printf("\n\nCommunal names:");
|
||
|
Records[i].Index = 3;
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
uint32 LIndex = Records[i].GetIndex(); // Index into preceding LNAMES
|
||
|
uint32 Type = Records[i].GetIndex(); // Type index. Ignored
|
||
|
printf("\n %2i %s, Type %i", ++xn, GetLocalName(LIndex), Type);
|
||
|
}
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void COMF::DumpSegments() {
|
||
|
// Dump all segment records
|
||
|
|
||
|
// Define structure of attributes
|
||
|
OMF_SAttrib Attributes;
|
||
|
|
||
|
// Record values
|
||
|
uint32 Frame, Offset, SegLength, NameIndex, ClassIndex, OverlayIndex;
|
||
|
|
||
|
uint32 i; // Record number
|
||
|
uint32 SegNum = 0; // Segment number
|
||
|
|
||
|
printf("\n\nSegment records:");
|
||
|
for (i = 0; i < NumRecords; i++) {
|
||
|
if (Records[i].Type2 == OMF_SEGDEF) {
|
||
|
// SEGDEF record
|
||
|
Records[i].Index = 3;
|
||
|
// Loop through entries in record. There should be only 1
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
Attributes.b = Records[i].GetByte(); // Read attributes
|
||
|
if (Attributes.u.A == 0) {
|
||
|
// Frame and Offset only included if A = 0
|
||
|
Frame = Records[i].GetWord(); Offset = Records[i].GetByte();
|
||
|
}
|
||
|
else Frame = Offset = 0;
|
||
|
SegLength = Records[i].GetNumeric();
|
||
|
NameIndex = Records[i].GetIndex();
|
||
|
ClassIndex = Records[i].GetIndex();
|
||
|
OverlayIndex = Records[i].GetIndex();
|
||
|
|
||
|
printf("\n Segment %2i, Name %s, Class %s, Align %i, %s, %i bit",
|
||
|
++SegNum, GetLocalName(NameIndex), GetLocalName(ClassIndex),
|
||
|
OMFAlignTranslate[Attributes.u.A],
|
||
|
Lookup(OMFSegmentCombinationNames, Attributes.u.C),
|
||
|
Attributes.u.P ? 32 : 16);
|
||
|
if (Attributes.u.B) printf(", big");
|
||
|
if (Attributes.u.A == 0) printf(", Frame %i, Offset 0x%X", Frame, Offset);
|
||
|
printf(", Length %i", SegLength);
|
||
|
if (OverlayIndex) printf("\n Overlay %i", OverlayIndex);
|
||
|
}
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
}
|
||
|
printf("\n\nGroup records:");
|
||
|
for (i = 0; i < NumRecords; i++) {
|
||
|
if (Records[i].Type2 == OMF_GRPDEF) {
|
||
|
// GRPDEF record
|
||
|
Records[i].Index = 3;
|
||
|
ClassIndex = Records[i].GetIndex();
|
||
|
printf("\n Group: %s\n Segments:", GetLocalName(ClassIndex));
|
||
|
|
||
|
// Loop through remaining entries in record
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
uint8 Type = Records[i].GetByte();
|
||
|
if (Type != 0xFF) printf(" Type=%X:", Type);
|
||
|
NameIndex = Records[i].GetIndex();
|
||
|
printf(" %s", GetSegmentName(NameIndex));
|
||
|
}
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void COMF::DumpRelocations() {
|
||
|
// Dump all LEDATA, LIDATA, COMDAT and FIXUPP records
|
||
|
//uint32 LastDataRecord = 0; // Index to the data record that relocations refer to
|
||
|
uint32 LastDataRecordSize = 0; // Size of the data record that relocations refer to
|
||
|
int8 * LastDataRecordPointer = 0; // Pointer to data in the data record that relocations refer to
|
||
|
uint32 i; // Loop counter
|
||
|
uint32 Segment, Offset, Size; // Contents of LEDATA or LIDATA record
|
||
|
uint32 LastOffset = 0; // Offset of last LEDATA or LIDATA record
|
||
|
uint32 Frame, Target, TargetDisplacement; // Contents of FIXUPP record
|
||
|
uint8 byte1, byte2; // First two bytes of subrecord
|
||
|
|
||
|
// Bitfields in subrecords
|
||
|
OMF_SLocat Locat; // Structure of first two bytes of FIXUP subrecord swapped = Locat field
|
||
|
OMF_SFixData FixData; // Structure of FixData field in FIXUP subrecord of FIXUPP record
|
||
|
OMF_STrdDat TrdDat; // Structure of Thread Data field in THREAD subrecord of FIXUPP record
|
||
|
|
||
|
printf("\n\nLEDATA, LIDATA, COMDAT and FIXUPP records:");
|
||
|
for (i = 0; i < NumRecords; i++) {
|
||
|
if (Records[i].Type2 == OMF_LEDATA) {
|
||
|
// LEDATA record
|
||
|
Segment = Records[i].GetIndex(); // Read segment and offset
|
||
|
Offset = Records[i].GetNumeric();
|
||
|
Size = Records[i].End - Records[i].Index; // Calculate size of data
|
||
|
//LastDataRecord = i; // Save for later FIXUPP that refers to this record
|
||
|
LastDataRecordSize = Size;
|
||
|
LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index;
|
||
|
if (Segment < 0x4000) {
|
||
|
printf("\n LEDATA: segment %s, Offset 0x%X, Size 0x%X", // Dump segment, offset, size
|
||
|
GetSegmentName(Segment), Offset, Size);
|
||
|
LastOffset = Offset;
|
||
|
}
|
||
|
else { // Undocumented Borland communal section
|
||
|
printf("\n LEDATA communal section %i, Offset 0x%X, Size 0x%X", // Dump segment, offset, size
|
||
|
(Segment & ~0x4000), Offset, Size);
|
||
|
LastOffset = Offset;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Records[i].Type2 == OMF_LIDATA) {
|
||
|
// LIDATA record
|
||
|
Segment = Records[i].GetIndex();
|
||
|
Offset = Records[i].GetNumeric();
|
||
|
//LastDataRecord = i;
|
||
|
LastDataRecordSize = Records[i].End - Records[i].Index; // Size before expansion of repeat blocks
|
||
|
LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index;
|
||
|
printf("\n LIDATA: segment %s, Offset 0x%X, Size ",
|
||
|
GetSegmentName(Segment), Offset);
|
||
|
// Call recursive function to interpret repeat data block
|
||
|
Size = Records[i].InterpretLIDATABlock();
|
||
|
printf(" = 0x%X", Size);
|
||
|
LastOffset = Offset;
|
||
|
}
|
||
|
|
||
|
if (Records[i].Type2 == OMF_COMDAT) {
|
||
|
// COMDAT record
|
||
|
//uint32 Flags = Records[i].GetByte(); // 1 = continuation, 2 = iterated, 4 = local, 8 = data in code segment
|
||
|
uint32 Attributes = Records[i].GetByte();
|
||
|
uint32 Base = 0;
|
||
|
// 0 = explicit, 1 = far code, 2 = far data, 3 = code32, 4 = data32
|
||
|
// 0x00 = no match, 0x10 = pick any, 0x20 = same size, 0x30 = exact match
|
||
|
uint32 Align = Records[i].GetByte(); // Alignment
|
||
|
Offset = Records[i].GetNumeric(); // Offset
|
||
|
uint32 TypeIndex = Records[i].GetIndex(); // Type index
|
||
|
if ((Attributes & 0x0F) == 0) {
|
||
|
Base = Records[i].GetIndex(); // Public base
|
||
|
}
|
||
|
uint32 NameIndex = Records[i].GetIndex(); // LNAMES index
|
||
|
Size = Records[i].End - Records[i].Index; // Calculate size of data
|
||
|
|
||
|
printf("\n COMDAT: name %s, Offset 0x%X, Size 0x%X, Attrib 0x%02X, Align %i, Type %i, Base %i",
|
||
|
GetLocalName(NameIndex), Offset, Size, Attributes, Align, TypeIndex, Base);
|
||
|
LastOffset = Offset;
|
||
|
}
|
||
|
|
||
|
if (Records[i].Type2 == OMF_FIXUPP) {
|
||
|
// FIXUPP record
|
||
|
printf("\n FIXUPP:");
|
||
|
Records[i].Index = 3;
|
||
|
|
||
|
// Loop through entries in record
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
|
||
|
// Read first byte
|
||
|
byte1 = Records[i].GetByte();
|
||
|
if (byte1 & 0x80) {
|
||
|
// This is a FIXUP subrecord
|
||
|
Frame = 0; Target = 0; TargetDisplacement = 0;
|
||
|
|
||
|
// read second byte
|
||
|
byte2 = Records[i].GetByte();
|
||
|
// swap bytes and put into byte12 bitfield
|
||
|
Locat.bytes[1] = byte1;
|
||
|
Locat.bytes[0] = byte2;
|
||
|
// Read FixData
|
||
|
FixData.b = Records[i].GetByte();
|
||
|
|
||
|
// print mode and location
|
||
|
printf("\n %s %s, Offset 0x%X",
|
||
|
Lookup(OMFRelocationModeNames, Locat.s.M),
|
||
|
Lookup(OMFFixupLocationNames, Locat.s.Location),
|
||
|
Locat.s.Offset + LastOffset);
|
||
|
|
||
|
// Read conditional fields
|
||
|
if (FixData.s.F == 0) {
|
||
|
if (FixData.s.Frame < 4) {
|
||
|
Frame = Records[i].GetIndex();
|
||
|
}
|
||
|
else Frame = 0;
|
||
|
|
||
|
switch (FixData.s.Frame) { // Frame method
|
||
|
case 0: // F0: segment
|
||
|
printf(", segment %s", GetSegmentName(Frame)); break;
|
||
|
|
||
|
case 1: // F1: group
|
||
|
printf(", group %s", GetGroupName(Frame)); break;
|
||
|
|
||
|
case 2: // F2: external symbol
|
||
|
printf(", external frame %s", GetSymbolName(Frame)); break;
|
||
|
|
||
|
case 4: // F4: frame = source,
|
||
|
// or Borland floating point emulation record (undocumented?)
|
||
|
printf(", frame = source; or Borland f.p. emulation record");
|
||
|
break;
|
||
|
|
||
|
case 5: // F5: frame = target
|
||
|
printf(", frame = target"); break;
|
||
|
|
||
|
default:
|
||
|
printf(", target frame %i method F%i", Frame, FixData.s.Frame);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
printf(", frame uses thread %i", FixData.s.Frame);
|
||
|
}
|
||
|
|
||
|
if (FixData.s.T == 0) {
|
||
|
// Target specified
|
||
|
Target = Records[i].GetIndex();
|
||
|
uint32 TargetMethod = FixData.s.Target + FixData.s.P * 4;
|
||
|
|
||
|
switch (FixData.s.Target) { // = Target method modulo 4
|
||
|
case 0: // T0 and T4: Target = segment
|
||
|
case 1: // T1 and T5: Target = segment group
|
||
|
printf(". Segment %s (T%i)",
|
||
|
GetSegmentName(Target), TargetMethod);
|
||
|
break;
|
||
|
case 2: // T2 and T6: Target = external symbol
|
||
|
printf(". Symbol %s (T%i)",
|
||
|
GetSymbolName(Target), TargetMethod);
|
||
|
break;
|
||
|
default: // Unknown method
|
||
|
printf(", target %i unknown method T%i", Target, TargetMethod);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// Target specified in previous thread
|
||
|
printf(", target uses thread %i", FixData.s.Target);
|
||
|
}
|
||
|
|
||
|
if (FixData.s.P == 0) {
|
||
|
TargetDisplacement = Records[i].GetNumeric();
|
||
|
printf("\n target displacement %i", TargetDisplacement);
|
||
|
}
|
||
|
// Get inline addend
|
||
|
if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) {
|
||
|
int8 * inlinep = LastDataRecordPointer + Locat.s.Offset;
|
||
|
switch (Locat.s.Location) {
|
||
|
case 0: case 4: // 8 bit
|
||
|
printf(", inline 0x%X", *inlinep); break;
|
||
|
|
||
|
case 1: case 2: case 5: // 16 bit
|
||
|
printf(", inline 0x%X", *(int16*)inlinep); break;
|
||
|
|
||
|
case 3: // 16+16 bit
|
||
|
printf(", inline 0x%X:0x%X", *(int16*)(inlinep+2), *(int16*)inlinep); break;
|
||
|
|
||
|
case 9: case 13: // 32 bit
|
||
|
printf(", inline 0x%X", *(int32*)inlinep); break;
|
||
|
|
||
|
case 6: case 11: // 16+32 bit
|
||
|
printf(", inline 0x%X:0x%X", *(int16*)(inlinep+4), *(int32*)inlinep); break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// This is a THREAD subrecord
|
||
|
TrdDat.b = byte1; // Put byte into bitfield
|
||
|
|
||
|
uint32 Index = 0;
|
||
|
if (TrdDat.s.Method < 4) {
|
||
|
Index = Records[i].GetIndex(); // has index field if method < 4 ?
|
||
|
}
|
||
|
printf("\n %s Thread %i. Method %s%i, index %i",
|
||
|
(TrdDat.s.D ? "Frame" : "Target"), TrdDat.s.Thread,
|
||
|
(TrdDat.s.D ? "F" : "T"), TrdDat.s.Method, Index);
|
||
|
}
|
||
|
} // Finished loop through subrecords
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
} // Finished loop through records
|
||
|
}
|
||
|
|
||
|
|
||
|
void COMF::DumpComments() {
|
||
|
// Dump COMENT records
|
||
|
uint32 i; // Record index
|
||
|
int startindex;
|
||
|
printf("\n");
|
||
|
for (i = 0; i < NumRecords; i++) {
|
||
|
if (Records[i].Type2 == OMF_COMENT) {
|
||
|
// COMENT record
|
||
|
printf("\nCOMENT record:\n");
|
||
|
startindex = Records[i].Index;
|
||
|
// Print as hex
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
printf("%02X ", Records[i].GetByte());
|
||
|
}
|
||
|
// Print again as string
|
||
|
Records[i].Index = startindex;
|
||
|
printf("\n");
|
||
|
while (Records[i].Index < Records[i].End) {
|
||
|
printf("%c ", Records[i].GetByte());
|
||
|
}
|
||
|
printf("\n");
|
||
|
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void COMF::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
|
||
|
// Make list of public names
|
||
|
// Strings will receive ASCIIZ strings
|
||
|
// Index will receive records of type SStringEntry with Member = m
|
||
|
SOMFRecordPointer rec; // Current OMF record
|
||
|
char * string; // Symbol name
|
||
|
SStringEntry se; // String entry record to save
|
||
|
|
||
|
// Initialize record pointer
|
||
|
rec.Start(Buf(), 0, GetDataSize());
|
||
|
|
||
|
// Loop through records and search for PUBDEF records
|
||
|
do {
|
||
|
// Read record
|
||
|
if (rec.Type2 == OMF_PUBDEF) {
|
||
|
|
||
|
// Public symbols definition found
|
||
|
rec.GetIndex(); // Read group
|
||
|
uint32 Segment = rec.GetIndex(); // Read segment
|
||
|
if (Segment == 0) rec.GetWord(); // Read base frame
|
||
|
// Loop through strings in record
|
||
|
while (rec.Index < rec.End) {
|
||
|
string = rec.GetString(); // Read name
|
||
|
rec.GetNumeric(); // Read offset
|
||
|
rec.GetIndex(); // Read type
|
||
|
// Make SStringEntry record
|
||
|
se.Member = m;
|
||
|
// Store name
|
||
|
se.String = Strings->PushString(string);
|
||
|
// Store name index
|
||
|
Index->Push(se);
|
||
|
}
|
||
|
if (rec.Index != rec.End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
if (rec.Type2 == OMF_CEXTDEF) {
|
||
|
// CEXTDEF record. Store communal symbol names
|
||
|
// Loop through entries in record
|
||
|
while (rec.Index < rec.End) {
|
||
|
uint32 LIndex = rec.GetIndex() - 1; // Index into preceding LNAMES
|
||
|
rec.GetIndex(); // Type index. Ignore
|
||
|
// Check if index valid
|
||
|
if (LIndex < LocalNameOffset.GetNumEntries()) {
|
||
|
// Make SStringEntry record
|
||
|
se.Member = m;
|
||
|
// Get name
|
||
|
char * name = GetLocalName(LIndex);
|
||
|
if (strlen(name) > 0) {
|
||
|
// Store name
|
||
|
se.String = Strings->PushString(name);
|
||
|
// Store name index
|
||
|
Index->Push(se);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (rec.Index != rec.End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
if (rec.Type2 == OMF_LNAMES) {
|
||
|
// LNAMES record. Check if file has been parsed
|
||
|
if (Records.GetNumEntries() == 0) {
|
||
|
// ParseFile has not been called. We need to store LNAMES table because
|
||
|
// these names may be needed by subsequent EXTDEF records.
|
||
|
// Loop through strings in record
|
||
|
while (rec.Index < rec.End) {
|
||
|
char * LocalName = rec.GetString();
|
||
|
uint32 LocalNameIndex = NameBuffer.PushString(LocalName); // Store local name
|
||
|
LocalNameOffset.Push(LocalNameIndex);// Store local name index
|
||
|
}
|
||
|
if (rec.Index != rec.End) err.submit(1203); // Check for consistency
|
||
|
}
|
||
|
}
|
||
|
} // Get next record
|
||
|
while (rec.GetNext()); // End of loop through records
|
||
|
}
|
||
|
|
||
|
char * COMF::GetLocalName(uint32 i) {
|
||
|
// Get section name or class name by name index
|
||
|
if (i == 0 || i >= LocalNameOffset.GetNumEntries()) {
|
||
|
i = NameBuffer.PushString("null");
|
||
|
return NameBuffer.Buf() + i;
|
||
|
}
|
||
|
return NameBuffer.Buf() + LocalNameOffset[i];
|
||
|
}
|
||
|
|
||
|
uint32 COMF::GetLocalNameO(uint32 i) {
|
||
|
// Get section name or class by converting name index offset into NameBuffer
|
||
|
if (i > 0 && i < LocalNameOffset.GetNumEntries()) {
|
||
|
return LocalNameOffset[i];
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
const char * COMF::GetSegmentName(uint32 i) {
|
||
|
// Get section name by segment index
|
||
|
if (i == 0) return "none";
|
||
|
if ((i & 0xC000) == 0x4000) {
|
||
|
// Borland communal section
|
||
|
static char text[32];
|
||
|
sprintf(text, "communal section %i", i - 0x4000);
|
||
|
return text;
|
||
|
}
|
||
|
if (i <= NumRecords) {
|
||
|
return NameBuffer.Buf() + SegmentNameOffset[i];
|
||
|
}
|
||
|
return "?";
|
||
|
}
|
||
|
|
||
|
|
||
|
const char * COMF::GetSymbolName(uint32 i) {
|
||
|
// Get external symbol name by index
|
||
|
if (i == 0) return "null";
|
||
|
if (i < SymbolNameOffset.GetNumEntries()) {
|
||
|
return NameBuffer.Buf() + SymbolNameOffset[i];
|
||
|
}
|
||
|
// return "?";
|
||
|
// index out of range
|
||
|
static char temp[100];
|
||
|
sprintf(temp, "Unknown index %i", i);
|
||
|
return temp;
|
||
|
}
|
||
|
|
||
|
const char * COMF::GetGroupName(uint32 i) {
|
||
|
// Get group name by index
|
||
|
if (i == 0) return "none";
|
||
|
if (i <= NumRecords) {
|
||
|
return NameBuffer.Buf() + GroupNameOffset[i];
|
||
|
}
|
||
|
return "?";
|
||
|
}
|
||
|
|
||
|
const char * COMF::GetRecordTypeName(uint32 i) {
|
||
|
// Get record type name
|
||
|
return Lookup(OMFRecordTypeNames, i);
|
||
|
}
|
||
|
|
||
|
// Member functions for parsing SOMFRecordPointer
|
||
|
uint8 SOMFRecordPointer::GetByte() {
|
||
|
// Read next byte from buffer
|
||
|
return *(buffer + FileOffset + Index++);
|
||
|
}
|
||
|
|
||
|
uint16 SOMFRecordPointer::GetWord() {
|
||
|
// Read next 16 bit word from buffer
|
||
|
uint16 x = *(uint16*)(buffer + FileOffset + Index);
|
||
|
Index += 2;
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
uint32 SOMFRecordPointer::GetDword() {
|
||
|
// Read next 32 bit dword from buffer
|
||
|
uint32 x = *(uint32*)(buffer + FileOffset + Index);
|
||
|
Index += 4;
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
uint32 SOMFRecordPointer::GetIndex() {
|
||
|
// Read byte or word, depending on sign of first byte
|
||
|
uint32 byte1, byte2;
|
||
|
byte1 = GetByte();
|
||
|
if (byte1 & 0x80) {
|
||
|
// Two byte index
|
||
|
byte2 = GetByte();
|
||
|
return ((byte1 & 0x7F) << 8) | byte2;
|
||
|
}
|
||
|
else {
|
||
|
// One byte index
|
||
|
return byte1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint32 SOMFRecordPointer::GetNumeric(){
|
||
|
// Read word or dword, depending on record type even or odd
|
||
|
if (Type & 1) {
|
||
|
// Odd record type. Number is 32 bits
|
||
|
return GetDword();
|
||
|
}
|
||
|
else {
|
||
|
// Even record type. Number is 16 bit s
|
||
|
return GetWord();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint32 SOMFRecordPointer::GetLength() {
|
||
|
// Read 1, 2, 3 or 4 bytes, depending on value of first byte
|
||
|
uint32 x = GetByte();
|
||
|
switch (x) {
|
||
|
case 0x81: // 16-bit value
|
||
|
return GetWord();
|
||
|
case 0x82: // 24-bit value
|
||
|
x = GetWord();
|
||
|
return (GetByte() << 16) + x;
|
||
|
case 0x84: // 32-bit value
|
||
|
return GetDword();
|
||
|
default: // 8-bit value
|
||
|
if (x > 0x80) err.submit(1203);
|
||
|
return x;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char * SOMFRecordPointer::GetString() {
|
||
|
// Read string and return as ASCIIZ string in static buffer
|
||
|
static char String[256];
|
||
|
uint8 Length = GetByte();
|
||
|
if (Length == 0 /*|| Length >= sizeof(String)*/) {
|
||
|
String[0] = 0;
|
||
|
}
|
||
|
else {
|
||
|
// Copy string
|
||
|
memcpy(String, buffer + FileOffset + Index, Length);
|
||
|
// Terminate by 0
|
||
|
String[Length] = 0;
|
||
|
}
|
||
|
// Point to next
|
||
|
Index += Length;
|
||
|
|
||
|
return String;
|
||
|
}
|
||
|
|
||
|
void SOMFRecordPointer::Start(int8 * Buffer, uint32 FileOffset, uint32 FileEnd) {
|
||
|
// Start scanning through records
|
||
|
this->buffer = Buffer;
|
||
|
this->FileOffset = FileOffset;
|
||
|
this->FileEnd = FileEnd;
|
||
|
Index = 0;
|
||
|
Type = GetByte();
|
||
|
Type2 = Type; if (Type2 < OMF_LIBHEAD) Type2 &= ~1; // Make even
|
||
|
uint16 RecordSize = GetWord();
|
||
|
End = Index + RecordSize - 1;
|
||
|
if (FileOffset + RecordSize + 3 > FileEnd) err.submit(2301); // Extends beyond end of file
|
||
|
}
|
||
|
|
||
|
uint8 SOMFRecordPointer::GetNext(uint32 align) {
|
||
|
// Get next record. Returns record type, made even. Returns 0 if finished
|
||
|
// align = alignment after MODEND records = page size. Applies to lib files only
|
||
|
FileOffset += End + 1;
|
||
|
|
||
|
// Check if alignment needed
|
||
|
if (align > 1 && Type2 == OMF_MODEND) {
|
||
|
// Align after MODEND record in library
|
||
|
FileOffset = (FileOffset + align - 1) & - (int32)align;
|
||
|
}
|
||
|
if (FileOffset >= FileEnd) return 0; // End of file
|
||
|
Index = 0; // Start reading record
|
||
|
Type = GetByte(); // Get record type
|
||
|
Type2 = Type; if (Type2 < OMF_LIBHEAD) Type2 &= ~1; // Make even
|
||
|
uint16 RecordSize = GetWord(); // Get record size
|
||
|
End = Index + RecordSize - 1; // Point to checksum byte
|
||
|
if ((uint64)FileOffset + RecordSize + 3 > FileEnd) err.submit(2301); // Extends beyond end of file
|
||
|
return Type2;
|
||
|
}
|
||
|
|
||
|
uint32 SOMFRecordPointer::InterpretLIDATABlock() {
|
||
|
// Interpret Data block in LIDATA record recursively
|
||
|
// Prints repeat count and returns total size
|
||
|
uint32 RepeatCount = GetNumeric();
|
||
|
uint32 BlockCount = GetWord();
|
||
|
uint32 Size = 0;
|
||
|
printf("%i * ", RepeatCount);
|
||
|
if (BlockCount == 0) {
|
||
|
Size = GetByte();
|
||
|
Index += Size;
|
||
|
printf("%i", Size);
|
||
|
return RepeatCount * Size;
|
||
|
}
|
||
|
// Nested repeat blocks
|
||
|
printf("(");
|
||
|
for (uint32 i = 0; i < BlockCount; i++) {
|
||
|
// Recursion
|
||
|
Size += InterpretLIDATABlock();
|
||
|
if (i+1 < BlockCount) printf(" + ");
|
||
|
}
|
||
|
printf(")");
|
||
|
return RepeatCount * Size;
|
||
|
}
|
||
|
|
||
|
|
||
|
uint32 SOMFRecordPointer::UnpackLIDATABlock(int8 * destination, uint32 MaxSize) {
|
||
|
// Unpack Data block in LIDATA record recursively and store data at destination
|
||
|
uint32 RepeatCount = GetNumeric(); // Outer repeat count
|
||
|
uint32 BlockCount = GetWord(); // Inner repeat count
|
||
|
uint32 Size = 0; // Size of data expanded so far
|
||
|
uint32 RSize; // Size of recursively expanded data
|
||
|
uint32 SaveIndex; // Save Index for repetition
|
||
|
uint32 i, j; // Loop counters
|
||
|
if (BlockCount == 0) {
|
||
|
// Contains one repeated block
|
||
|
Size = GetByte(); // Size of repeated block
|
||
|
if (RepeatCount * Size > MaxSize) {
|
||
|
// Data outside allowed area
|
||
|
err.submit(2310); // Error message
|
||
|
Index += Size; // Point to after block
|
||
|
return 0; // No data stored
|
||
|
}
|
||
|
|
||
|
// Loop RepeatCount times
|
||
|
for (i = 0; i < RepeatCount; i++) {
|
||
|
// copy data block into destination
|
||
|
memcpy(destination, buffer + FileOffset + Index, Size);
|
||
|
destination += Size;
|
||
|
}
|
||
|
Index += Size; // Point to after block
|
||
|
return RepeatCount * Size; // Size of expanded data
|
||
|
}
|
||
|
// Nested repeat blocks
|
||
|
SaveIndex = Index;
|
||
|
// Loop RepeatCount times
|
||
|
for (i = 0; i < RepeatCount; i++) {
|
||
|
// Go back and repeat unpacking
|
||
|
Index = SaveIndex;
|
||
|
// Loop BlockCount times
|
||
|
for (j = 0; j < BlockCount; j++) {
|
||
|
// Recursion
|
||
|
RSize = UnpackLIDATABlock(destination, MaxSize);
|
||
|
destination += RSize;
|
||
|
MaxSize -= RSize;
|
||
|
Size += RSize;
|
||
|
}
|
||
|
}
|
||
|
return Size;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Members of COMFFileBuilder, class for building OMF files
|
||
|
COMFFileBuilder::COMFFileBuilder() {
|
||
|
// Constructor
|
||
|
Index = 0;
|
||
|
}
|
||
|
|
||
|
void COMFFileBuilder::StartRecord(uint8 type) {
|
||
|
// Start building new record
|
||
|
this->Type = type; // Save type
|
||
|
RecordStart = Index = GetDataSize(); // Remember start position
|
||
|
PutByte(Type); // Put type into record
|
||
|
PutWord(0); // Reserve space for size, put in later
|
||
|
}
|
||
|
|
||
|
void COMFFileBuilder::EndRecord() {
|
||
|
// Finish building current record
|
||
|
// Update length
|
||
|
Get<uint16>(RecordStart + 1) = GetSize() + 1;
|
||
|
|
||
|
// Make checksum
|
||
|
int8 checksum = 0;
|
||
|
for (uint32 i = RecordStart; i < Index; i++) checksum += Buf()[i];
|
||
|
PutByte(-checksum);
|
||
|
|
||
|
// Check size limit
|
||
|
if (GetSize() > 0x407) {
|
||
|
err.submit(9005);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void COMFFileBuilder::PutByte(uint8 x) {
|
||
|
// Put byte into buffer
|
||
|
Push(&x, 1);
|
||
|
Index++;
|
||
|
}
|
||
|
|
||
|
void COMFFileBuilder::PutWord(uint16 x) {
|
||
|
// Put 16 bit word into buffer
|
||
|
Push(&x, 2);
|
||
|
Index += 2;
|
||
|
}
|
||
|
|
||
|
void COMFFileBuilder::PutDword(uint32 x) {
|
||
|
// Put 32 bit dword into buffer
|
||
|
Push(&x, 4);
|
||
|
Index += 4;
|
||
|
}
|
||
|
|
||
|
void COMFFileBuilder::PutIndex(uint32 x) {
|
||
|
// Put byte or word into buffer (word if > 0x7F)
|
||
|
if (x < 0x80) {
|
||
|
// One byte
|
||
|
PutByte(x);
|
||
|
}
|
||
|
else {
|
||
|
// Two bytes
|
||
|
if (x > 0x7fff) {
|
||
|
err.submit(2303); // Index out of range
|
||
|
}
|
||
|
PutByte((uint8)(x >> 8) | 0x80); // First byte = high byte | 0x80
|
||
|
PutByte(uint8(x)); // Second byte = low byte
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void COMFFileBuilder::PutNumeric(uint32 x) {
|
||
|
// Put word or dword into buffer, depending on type being even or odd
|
||
|
if (Type & 1) {
|
||
|
PutDword(x); // Type is odd, put 32 bits
|
||
|
}
|
||
|
else {
|
||
|
if (x > 0xffff) err.submit(2304);// Index out of range
|
||
|
PutWord(uint16(x)); // Type is even, put 16 bits
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void COMFFileBuilder::PutString(const char * s) {
|
||
|
// Put ASCII string into buffer, preceded by size
|
||
|
uint32 len = (uint32)strlen(s); // Check length
|
||
|
if (len > 255) {
|
||
|
// String too long
|
||
|
err.submit(1204, s); // Issue warning
|
||
|
len = 255; // Truncate string to 255 characters
|
||
|
}
|
||
|
PutByte(uint8(len)); // Store length
|
||
|
Push(s, len); // Store len bytes
|
||
|
Index += len; // Update index
|
||
|
}
|
||
|
|
||
|
void COMFFileBuilder::PutBinary(void * p, uint32 Size) {
|
||
|
// Put binary data of any length
|
||
|
if (Size > 1024) {err.submit(9000); Size = 1024;} // 1024 bytes size limit
|
||
|
Push(p, Size);
|
||
|
Index += Size;
|
||
|
}
|
||
|
|
||
|
uint32 COMFFileBuilder::GetSize() {
|
||
|
// Get size of data added so far
|
||
|
if (Index <= RecordStart + 3) return 0;
|
||
|
return Index - RecordStart - 3; // Type and size fields not included in size
|
||
|
}
|