home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1991
/
09
/
objlib.lst
< prev
next >
Wrap
File List
|
1991-08-21
|
29KB
|
660 lines
_OB╩ LIBRAR┘ MANAGEMENT_
b∙ Thoma≤ Siering
[LISTING ONE]
//****** svc.h -- Service functions *******
#define NOFILE NULL // no error log file
typedef enum {
Message,
Warning,
Error
} MESSAGETYPE;
char *MakeASCIIZ(unsigned char *LString);
void Output(MESSAGETYPE MsgType, FILE *Stream, char *OutputFormat, ...);
[LISTING TWO]
//****** svc.c -- Service functions *******
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "svc.h"
// MakeASCIIZ - Take a string of 1-byte length/data format, and make it ASCIIZ.
char *MakeASCIIZ(unsigned char *LString)
{
char *ASCIIZString;
unsigned char StringLength;
StringLength = *LString++;
if ((ASCIIZString = malloc((int) StringLength + 1)) == NULL)
return (NULL);
strncpy(ASCIIZString, (signed char *) LString, StringLength);
ASCIIZString[StringLength] = '\0';
return (ASCIIZString);
}
// Output -- Write to the output stream. This function adds an exception-
// handling layer to disk IO. It handles abnormal program termination, and
// warnings to both stderr and output. Three types of message can be handled:
// Message, simply printed to a file; Warning, print to file AND stderr;
// Error, same as warning, but terminate with abnormal exit code.
void Output(MESSAGETYPE MsgType, FILE *Stream, char *OutputFormat, ...)
{
char OutputBuffer[133];
va_list VarArgP;
va_start(VarArgP, OutputFormat);
vsprintf(OutputBuffer, OutputFormat, VarArgP);
// If this is (non-fatal) warning or (fatal) error, also send it to stderr
if (MsgType != Message)è fprintf(stderr, "\a%s", OutputBuffer);
// In any case: attempt to print message to output file. Exception check.
if (Stream != NOFILE)
if ((size_t) fprintf(Stream, OutputBuffer) != strlen(OutputBuffer)) {
fprintf(stderr, "\aDisk Write Failure!\n");
abort();
}
/* If this was (fatal) error message, abort on the spot */
if (MsgType == Error) {
flushall();
fcloseall();
abort();
}
va_end(VarArgP);
}
[LISTING THREE]
//***** ole.h -- Global include info for Object Library Engine (ole.c) ******
#define THEADR 0x80 // OMF module header
#define COMENT 0x88 // OMF comment record
#define MODEND 0x8A // OMF module end record
#define LIBMOD 0xA3 // library module name comment class
#define LIBHEADER 0xF0 // LIB file header
#define MARKER_RECORD 0xF1 // marker between modules & dictionary
#define NUMBUCKETS 37 // number of buckets/block
#define DICTBLOCKSIZE 512 // bytes/symbol dictionary block
#define DICTBLKFULL 0xFF // Symbol dictionary block full
#define UNDEFINED -1 // to indicate non-initialized data
#define STR_EQUAL 0 // string equality
// These two macros will rotate word operand opw by nbits bits (0 - 16)
#define WORDBITS 16
#define ROL(opw, nbits) (((opw) << (nbits)) | ((opw) >> (WORDBITS - (nbits))))
#define ROR(opw, nbits) (((opw) >> (nbits)) | ((opw) << (WORDBITS - (nbits))))
typedef enum {
false,
true
} bool;
#pragma pack(1)
typedef struct {
unsigned char RecType;
int RecLength;
} OMFHEADER;
typedef struct {
unsigned char RecType;
int RecLength;è unsigned char Attrib;
unsigned char CommentClass;
} COMENTHEADER;
typedef struct { // Record Type F0h
int PageSize; // Header length (excl. first 3 bytes)
// == page size (module at page boundary)
// page size == 2 ** n, 4 <= n <= 15
long DictionaryOffset; // file offset of Symbol Dictionary
int NumDictBlocks; // number of Symbol Dictionary blocks
// <= 251 512-byte dictionary pages
unsigned char Flags; // only valid flag: 01h => case-sensitive
bool IsCaseSensitive;
bool IsLIBMODFormat; // is MS extension type LIBMOD present?
} LIBHDR;
typedef struct {
unsigned char MarkerType; // This's better be F1h
int MarkerLength; // filler to dictionary's 512-byte alignment
} DICTMARKER;
typedef struct {
int BlockNumber;
int BucketNumber;
unsigned char *SymbolP;
long ModuleFilePos;
bool IsFound;
} DICTENTRY;
typedef struct {
int BlockHash;
int BlockOvfl;
int BucketHash;
int BucketOvfl;
} HashT;
void GetLibHeader(LIBHDR *LibHeader, FILE *InLibFH);
HashT Hash(char SymbolZ[], int NumHashBlocks);
DICTENTRY FindSymbol(char *SymbolZ, LIBHDR *LibHeader, FILE *InLibFH);
void GetSymDictBlock(int BlockNumber, LIBHDR *LibHeader,
FILE *InLibFH);
long FindModule(char *ModuleName, LIBHDR *LibHeader, FILE *InLibFH);
DICTENTRY GetSymDictEntry(int BlockNumber, int BucketNumber,
LIBHDR *LibHeader, FILE *InLibFH);
char *GetModuleName(long ModuleFilePos, LIBHDR *LibHeader, FILE *InLibFH);
bool FindLIBMOD(FILE *InLibFH);
bool FindObjRecord(FILE *ObjFH, unsigned char RecType);
bool ExtractModule(char *ModuleName, char *NewModuleName, LIBHDR *LibHeader,
FILE *InLibFH);
void CopyObjModule(FILE *NewObjFH, long FilePos, FILE *InLibFH);
[LISTING FOUR]
è//***** ole.c -- Object Library Engine ******
#include <stdio.h>
#include <io.h>
#include <stdlib.h>
#include <string.h>
#include "ole.h"
#include "svc.h"
typedef struct {
unsigned char SymbolDictBlock[DICTBLOCKSIZE]; // symbol dictionary block
int FreeSpaceIdx; // cursor to next free symbol space slot
bool IsFull; // is this sym. dict. block full?
int BlockNumber; // current block number
} DICTBLOCK;
// The number of pages in the Symbol Dictionary has to be a prime <= 251.
// NOTE: The smallest page number in MS LIB is 2, in Borland TLIB it's 1.
static int Primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
197, 199, 211, 223, 227, 229, 233, 239, 241, 251 };
// Symbol Dictionary Block
static DICTBLOCK DictBlock;
// GetLibHeader -- Get header of an object module library. The library
// header's ( record type F0) main purpose is to identify this data file as a
// library, give page size, and size and location of Symbol Dictionary.
void GetLibHeader(LIBHDR *LibHeader, FILE *InLibFH)
{
if (fgetc(InLibFH) != LIBHEADER)
Output(Error, NOFILE, "Bogus Library Header\n");
// NOTE: The LIBHDR data structure has been enlarged to include more
// info than the actual LIB header contains. As a result, a few more bytes
// are read in past the actual header when we take sizeof(LIBHDR). This
// is no problem since there's plenty to read after the header, anyway!
if (fread(LibHeader, sizeof(LIBHDR), 1, InLibFH) != 1)
Output(Error, NOFILE, "Couldn't Read Library Header\n");
// Add in Header length word & checksum byte
LibHeader->PageSize += 3;
// Determine if LIB includes Microsoft's LIBMOD extension
// Find the first OBJ module in the LIB file
if (fseek(InLibFH, (long) LibHeader->PageSize, SEEK_SET) != 0)
Output(Error, NOFILE, "Seek for first object module failed\n");
LibHeader->IsLIBMODFormat = FindLIBMOD(InLibFH);
LibHeader->IsCaseSensitive = LibHeader->Flags == 0x01 ? true : false;
// Make it clear that we haven't read Symbol Dictionary yet
DictBlock.BlockNumber = UNDEFINED;
}
// FindModule -- Find a module in Symbol Dictionary and return its file
// position. If not found, return -1L.
long FindModule(char *ModuleName, LIBHDR *LibHeader, FILE *InLibFH)
{
char *ObjName;
DICTENTRY DictEntry;
char *ExtP;è // Allow extra space for terminating "!\0"
if ((ObjName = malloc(strlen(ModuleName) + 2)) == NULL)
Output(Error, NOFILE, "OBJ Name Memory Allocation Failed\n");
strcpy(ObjName, ModuleName);
// Allow search for module name xxx.obj
if ((ExtP = strrchr(ObjName, '.')) != NULL)
*ExtP = '\0';
// NOTE: Module names are stored in LIB's with terminating '!'
strcat(ObjName, "!");
DictEntry = FindSymbol(ObjName, LibHeader, InLibFH);
free(ObjName);
return (DictEntry.IsFound == true ? DictEntry.ModuleFilePos : -1L);
}
// FindSymbol -- Find a symbol in Symbol Dictionary by (repeatedly, if
// necessary) hashing the symbol and doing dictionary lookup.
DICTENTRY FindSymbol(char *SymbolZ, LIBHDR *LibHeader, FILE *InLibFH)
{
DICTENTRY DictEntry;
char *SymbolP;
HashT HashVal;
int MaxTries;
int Block, Bucket;
HashVal = Hash(SymbolZ, LibHeader->NumDictBlocks);
Block = HashVal.BlockHash;
Bucket = HashVal.BucketHash;
MaxTries = LibHeader->NumDictBlocks * NUMBUCKETS;
DictEntry.IsFound = false;
while (MaxTries--) {
DictEntry = GetSymDictEntry(Block, Bucket, LibHeader, InLibFH);
// Three alternatives to check after Symbol Dictionary lookup:
// 1. If the entry is zero, but the dictionary block is NOT full,
// the symbol is not present:
if (DictEntry.IsFound == false && DictBlock.IsFull == false)
return (DictEntry);
// 2. If the entry is zero, and the dictionary block is full, the
// symbol may have been rehashed to another block; keep looking:
// 3. If the entry is non-zero, we still have to verify the symbol.
// If it's the wrong one (hash clash), keep looking:
if (DictEntry.IsFound == true) {
// Get the symbol name
SymbolP = MakeASCIIZ(DictEntry.SymbolP);
// Choose case-sensitive or insensitive comparison as appropriate
if ((LibHeader->IsCaseSensitive == true ? strcmp(SymbolZ, SymbolP) :
stricmp(SymbolZ, SymbolP)) == STR_EQUAL) {
free(SymbolP);
return (DictEntry);
}
free(SymbolP);
}
// Cases 2 and 3 (w/o a symbol match) require re-hash:
Block += HashVal.BlockOvfl;
Bucket += HashVal.BucketOvfl;è Block %= LibHeader->NumDictBlocks;
Bucket %= NUMBUCKETS;
}
// We never found the entry!
DictEntry.IsFound = false;
return (DictEntry);
}
// Hash -- Hash a symbol for Symbol Dictionary entry
// Inputs: SymbolZ - Symbol in ASCIIZ form; NumHashBlocks - current number of
// Symbol Dictionary blocks (MS LIB max. 251 blocks)
// Outputs: Hash data structure, containing: BlockHash, index of block
// containing symbol; BlockOvfl, block index's rehash delta; BucketHash,
// index of symbol's bucket (position) on page; BucketOvfl, bucket index's
// rehash delta
// Algorithm: Determine block index, i.e. page number in Symbol Dictionary
// where the symbol is to reside, and the bucket index, i.e. the position
// within that page (0-36). If this leads to collision, retry with bucket
// delta until entire block has turned out to be full. Then, apply block
// delta, and start over with original bucket index.
HashT Hash(char SymbolZ[], int NumHashBlocks)
{
HashT SymHash; // the resulting aggregate hash values
unsigned char *SymbolC; // symbol with prepended count
int SymLength; // length of symbol to be hashed
unsigned char *FwdP, *BwdP; // temp. pts's to string: forward/back.
unsigned int FwdC, BwdC; // current char's at fwd/backw. pointers
unsigned int BlockH, BlockD, BucketH, BucketD; // temporary values
int i;
SymLength = strlen(SymbolZ);
// Make symbol string in Length byte/ASCII string format
if ((SymbolC = malloc(SymLength + 2)) == NULL)
Output(Error, NOFILE, "Memory Allocation Failed\n");
SymbolC[0] = (unsigned char) SymLength;
// copy w/o EOS
strncpy((signed char *) &SymbolC[1], SymbolZ, SymLength + 1);
FwdP = &SymbolC[0];
BwdP = &SymbolC[SymLength];
BlockH = BlockD = BucketH = BucketD = 0;
for (i = 0; i < SymLength; i++) {
// Hashing is done case-insensitive, incl. length byte
FwdC = (unsigned int) *FwdP++ | 0x20;
BwdC = (unsigned int) *BwdP-- | 0x20;
// XOR the current character (moving forward or reverse, depending
// on variable calculated) with the intermediate result rotated
// by 2 bits (again, left or right, depending on variable).
// Block Hash: traverse forward, rotate left
BlockH = FwdC ^ ROL(BlockH, 2);
// Block Overflow delta: traverse reverse, rotate left
BlockD = BwdC ^ ROL(BlockD, 2);
// Bucket Hash: traverse reverse, rotate right
BucketH = BwdC ^ ROR(BucketH, 2);
// Bucket Overflow delta: traverse forward, rotate right
BucketD = FwdC ^ ROR(BucketD, 2);
}
// NOTE: Results are zero-basedè SymHash.BlockHash = BlockH % NumHashBlocks;
SymHash.BucketHash = BucketH % NUMBUCKETS;
// Obviously, hash deltas of 0 would be nonsense!
SymHash.BlockOvfl = max(BlockD % NumHashBlocks, 1);
SymHash.BucketOvfl = max(BucketD % NUMBUCKETS, 1);
free(SymbolC);
return (SymHash);
}
// GetSymDictBlock -- Read and pre-process a Symbol Dictionary block
void GetSymDictBlock(int BlockNumber, LIBHDR *LibHeader, FILE *InLibFH)
{
// Find and read the whole Symbol Dictionary block
if (fseek(InLibFH, LibHeader->DictionaryOffset + (long) BlockNumber *
(long) DICTBLOCKSIZE, SEEK_SET) != 0)
Output(Error, NOFILE, "Could Not Find Symbol Dictionary\n");
if (fread(DictBlock.SymbolDictBlock, DICTBLOCKSIZE, 1, InLibFH) != 1)
Output(Error, NOFILE, "Couldn't Read Library Header\n");
// Is this block all used up?
DictBlock.FreeSpaceIdx = DictBlock.SymbolDictBlock[NUMBUCKETS];
DictBlock.IsFull = (DictBlock.FreeSpaceIdx == DICTBLKFULL) ? true : false;
// For future reference, remember block number
DictBlock.BlockNumber = BlockNumber;
}
// GetSymDictEntry -- Look up and process a Symbol Dictionary block entry
DICTENTRY GetSymDictEntry(int BlockNumber, int BucketNumber,
LIBHDR *LibHeader, FILE *InLibFH)
{
DICTENTRY DictEntry;
unsigned char SymbolOffset;
unsigned char SymbolLength;
int PageNumber;
// Remember entry's block/bucket and init. to no (NULL) entry
DictEntry.BlockNumber = BlockNumber;
DictEntry.BucketNumber = BucketNumber;
DictEntry.SymbolP = NULL;
DictEntry.IsFound = false;
// Make sure the appropriate block was already read from obj. mod. library
if (DictBlock.BlockNumber != BlockNumber)
GetSymDictBlock(BlockNumber, LibHeader, InLibFH);
// WORD offset of symbol in dictionary block: 0 means no entry
SymbolOffset = DictBlock.SymbolDictBlock[BucketNumber];
if (SymbolOffset != 0) {
// Since it's word offset, need to multiply by two
DictEntry.SymbolP = &DictBlock.SymbolDictBlock[SymbolOffset * 2];
// Get the symbol's object module offset in LIB
SymbolLength = *DictEntry.SymbolP;
// Object module's LIB page number is right after symbol string
PageNumber = *(int *) (DictEntry.SymbolP + SymbolLength + 1);
DictEntry.ModuleFilePos = (long) PageNumber *
(long) LibHeader->PageSize;
DictEntry.IsFound = true;
}
return (DictEntry);
}è// GetModuleName -- Read the OMF module header record (THEADR - 80h) or, if
// present, MS's LIBMOD extension record type. NOTE: For Microsoft C,
// THEADR reflects the source code name file at compilation time. OBJ name
// may differ from this; the LIBMOD record will contain its name. For
// Borland C++, THEADR is the only pertinent record and will contain OBJ
// module's name rather than the source's.
char *GetModuleName(long ModuleFilePos, LIBHDR *LibHeader, FILE *InLibFH)
{
int SymbolLength;
char *ModuleName;
OMFHEADER OmfHeader;
// Position at beginning of pertinent object module
if (fseek(InLibFH, ModuleFilePos, SEEK_SET) != 0)
Output(Error, NOFILE, "Seek for object module at %lx failed\n",
ModuleFilePos);
if (LibHeader->IsLIBMODFormat == false) {
if (fread(&OmfHeader, sizeof(OmfHeader), 1, InLibFH) != 1)
Output(Error, NOFILE, "Couldn't Read THEADR at %lx\n",
ModuleFilePos);
if (OmfHeader.RecType != THEADR)
Output(Error, NOFILE, "Bogus THEADR OMF record at %lx\n",
ModuleFilePos);
}
else
if (FindLIBMOD(InLibFH) == false) {
Output(Warning, NOFILE, "No LIBMOD record found at %lx\n",
ModuleFilePos);
return (NULL);
}
SymbolLength = fgetc(InLibFH);
if ((ModuleName = malloc(SymbolLength + 1)) == NULL)
Output(Error, NOFILE, "Malloc failure Reading module name\n");
if (fread(ModuleName, SymbolLength, 1, InLibFH) != 1)
Output(Error, NOFILE, "Couldn't Read THEADR\n");
ModuleName[SymbolLength] = '\0';
return(ModuleName);
}
// FindLIBMOD -- Get a LIBMOD (A3) comment record, if present.
// NOTE: This is a special OMF COMENT (88h) record comment class used by
// Microsoft only. It provides the name of the object modules which may
// differ from the source (contained in THEADR). This record is added when an
// object module is put into library, and stripped out when it's extracted.
// This routine will leave file pointer at the LIBMOD name field.
bool FindLIBMOD(FILE *InLibFH)
{
COMENTHEADER CommentHdr;
// Search (up to) all COMENT records in OBJ module
while (FindObjRecord(InLibFH, COMENT) == true) {
if (fread(&CommentHdr, sizeof(CommentHdr), 1, InLibFH) != 1)
Output(Error, NOFILE, "Couldn't Read OBJ\n");
if (CommentHdr.CommentClass == LIBMOD)
return (true);
else
// if not found: forward to next record, and retry
if (fseek(InLibFH, (long) CommentHdr.RecLength - è sizeof(CommentHdr) + sizeof(OMFHEADER), SEEK_CUR) != 0)
Output(Error, NOFILE, "Seek retry for LIBMOD failed\n");
}
// We got here only if COMENT of class LIBMOD was never found
return (false);
}
// FindObjRecord -- Find an object module record in one given module.
// On call, file pointer must be set to an objec record. Search will
// quit at the end of current module (or when record found).
bool FindObjRecord(FILE *ObjFH, unsigned char RecType)
{
OMFHEADER ObjHeader;
while (fread(&ObjHeader, sizeof(ObjHeader), 1, ObjFH) == 1) {
// If it's the record type we're looking for, we're done
if (ObjHeader.RecType == RecType) {
// Return with obj module set to record requested
if (fseek(ObjFH, -(long) sizeof(ObjHeader), SEEK_CUR) != 0)
Output(Error, NOFILE, "Seek for Record Type %02x failed\n",
RecType & 0xFF);
return (true);
}
// End of object module, record type NEVER found
if (ObjHeader.RecType == MODEND)
return (false);
// Forward file pointer to next object module record
if (fseek(ObjFH, (long) ObjHeader.RecLength, SEEK_CUR) != 0)
Output(Error, NOFILE, "Seek retry for Record Type %02x failed\n",
RecType & 0xFF);
}
// If this quit due to I/O condition, it's either EOF or I/O error
if (feof(ObjFH) == 0)
Output(Error, NOFILE, "Couldn't Read OBJ\n");
// we completed w/o error and w/o finding the record (should NEVER happen)
return (false);
}
// ExtractModule -- Find an object module in a library and extract it into
// "stand-alone" object file. Return true if ok, else false.
// Optional: Can specify a new name for the module.
bool ExtractModule(char *ModuleName, char *NewModuleName, LIBHDR *LibHeader,
FILE *InLibFH)
{
long FilePos;
char *NewObjP;
char *NewObjName;
FILE *NewObjFH;
// Find the object module's position in the library file
FilePos = FindModule(ModuleName, LibHeader, InLibFH);
if (FilePos == -1L)
return (false);
// Determine name for new .obj, and set it up
NewObjP = NewModuleName != NULL ? NewModuleName : ModuleName;
if ((NewObjName = malloc(strlen(NewObjP) + 5)) == NULL)
Output(Error, NOFILE, "Malloc failure Making module name %s\n",
NewObjP);
strcpy(NewObjName, NewObjP);è // Open the new .obj file, and pass everything off to low-level routine
if ((NewObjFH = fopen(NewObjName, "wb")) == NULL)
Output(Error, NOFILE, "Open failure new module %s\n", NewObjName);
CopyObjModule(NewObjFH, FilePos, InLibFH);
fclose(NewObjFH);
free(NewObjName);
return (true);
}
// CopyObjModule -- Low-level copy of LIB member to OBJ file.
void CopyObjModule(FILE *NewObjFH, long FilePos, FILE *InLibFH)
{
OMFHEADER RecHdr;
// Get to the object module in LIB
if (fseek(InLibFH, FilePos, SEEK_SET) != 0)
Output(Error, NOFILE, "Seek failure to file position %ld\n", FilePos);
// Write module from LIB to separate obj file
do {
// Read OMF header record, this will give record type and length
if (fread(&RecHdr, sizeof(RecHdr), 1, InLibFH) != 1)
Output(Error, NOFILE, "Couldn't Read OBJ\n");
// Need to check every COMENT record to make sure to strip LIBMOD out
if (RecHdr.RecType == COMENT) {
// Throw away next byte (Attrib COMENT byte) for now
fgetc(InLibFH);
// Check COMENT's Comment Class
// If it's a LIBMOD, set file pointer ro next record and continue
if (fgetc(InLibFH) == LIBMOD) {
if (fseek(InLibFH, (long) RecHdr.RecLength - 2L, SEEK_CUR) != 0)
Output(Error, NOFILE, "Seek error on COMENT\n");
continue;
}
else
// Wasn't a LIBMOD: reset file pointer to continue normally
if (fseek(InLibFH, -2L, SEEK_CUR) != 0)
Output(Error, NOFILE, "Seek error on COMENT\n");
}
if (fwrite(&RecHdr, sizeof(RecHdr), 1, NewObjFH) != 1)
Output(Error, NOFILE, "Couldn't Write new OBJ\n");
while (RecHdr.RecLength--)
fputc(fgetc(InLibFH), NewObjFH);
} while (RecHdr.RecType != MODEND);
}
[LISTING FIVE]
//***** olu1.c -- Object Library Utility, Sample Application 1. *****
// This utility performs a linear scan and dump of an object module library's
// Symbol Dictionary. NOTE: Due to Borland TLIB bug, this utility may NOT work
// with libraries generated with versions 3.01 or less.
//*****************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include "ole.h"è#include "svc.h"
static void DumpSymbolDictionary(LIBHDR *LibHeader, FILE *InLibFH);
void main(int argc, char *argv[]);
// main -- Surprise!
void main(int argc, char *argv[])
{
FILE *InLibFH;
LIBHDR LibHeader;
long ModFilePos;
if (argc != 2)
Output(Error, NOFILE, "Usage: %s file.lib\n", argv[0]);
if ((InLibFH = fopen(argv[1], "rb")) == NULL)
Output(Error, NOFILE, "Couldn't Open %s\n", argv[1]);
GetLibHeader(&LibHeader, InLibFH);
DumpSymbolDictionary(&LibHeader, InLibFH);
}
// DumpSymbolDictionary -- Print out an entire Symbol Dictionary
static void DumpSymbolDictionary(LIBHDR *LibHeader, FILE *InLibFH)
{
int BlockIdx, BucketIdx;
DICTENTRY DictEntry;
char *ModuleName;
char *SymbolP;
for (BlockIdx = 0; BlockIdx < LibHeader->NumDictBlocks; BlockIdx++)
for (BucketIdx = 0; BucketIdx < NUMBUCKETS; BucketIdx++) {
DictEntry = GetSymDictEntry(BlockIdx, BucketIdx, LibHeader,
InLibFH);
if (DictEntry.IsFound == false)
continue;
// Get the symbol name
SymbolP = MakeASCIIZ(DictEntry.SymbolP);
// Get to the corresponding module name record (THEADR or LIBMOD)
ModuleName = GetModuleName(DictEntry.ModuleFilePos, LibHeader,
InLibFH);
printf("%s -- Module %s (%08lxh)\n", SymbolP,
ModuleName, DictEntry.ModuleFilePos);
printf("Hash: Block %d , Bucket %d\n", BlockIdx, BucketIdx);
free(SymbolP);
free(ModuleName);
}
}
[LISTING SIX]
//***** olu2.c -- Object Library Utility, Sample Application 2. *****
// This utility explodes an object module library, i.e. move all its members
// out into .obj form. This functionality is absent from popular library
// managers; useful for libraries the user is unfamiliar with. Optionally,
// named single members can be copied, as well. NOTE: Modules can be
// extracted in sequence efficiently, but we're showing off functions!
#include <stdio.h>
#include <stdlib.h>è#include <string.h>
#include "ole.h"
#include "svc.h"
static void ExplodeLibrary(LIBHDR *LibHeader, FILE *InLibFH);
void main(int argc, char *argv[]);
// main -- Surprise!
void main(int argc, char *argv[])
{
FILE *InLibFH;
LIBHDR LibHeader;
if (argc != 2 && argc!= 3)
Output(Error, NOFILE, "Usage: %s file.lib [file.obj]\n", argv[0]);
if ((InLibFH = fopen(argv[1], "rb")) == NULL)
Output(Error, NOFILE, "Couldn't Open %s\n", argv[1]);
GetLibHeader(&LibHeader, InLibFH);
if (argc == 3) {
if (ExtractModule(argv[2], NULL, &LibHeader, InLibFH) == false)
Output(Error, NOFILE, "Extraction of Module %s failed\n",
argv[2]);
}
else
ExplodeLibrary(&LibHeader, InLibFH);
}
// Explode Library -- Extract all (or one specific) library member(s).
// NOTE: This is done in a contrived way just to show off some of functions.
// We go through entire Symbol Dict., determine if a symbol is a module name
// by comparing its entry to the module name that entry is leading to, and
// then extract the module.
static void ExplodeLibrary(LIBHDR *LibHeader, FILE *InLibFH)
{
int BlockIdx, BucketIdx;
DICTENTRY DictEntry;
char *ModuleName;
char *SymbolP;
char *ModuleFN;
for (BlockIdx = 0; BlockIdx < LibHeader->NumDictBlocks; BlockIdx++)
for (BucketIdx = 0; BucketIdx < NUMBUCKETS; BucketIdx++) {
DictEntry = GetSymDictEntry(BlockIdx, BucketIdx, LibHeader,
InLibFH);
if (DictEntry.IsFound == false)
continue;
// Get the symbol name
SymbolP = MakeASCIIZ(DictEntry.SymbolP);
ModuleName = GetModuleName(DictEntry.ModuleFilePos, LibHeader,
InLibFH);
// If it compares, it's a module name
if (strnicmp(SymbolP, ModuleName, strlen(ModuleName)) ==
STR_EQUAL) {
if ((ModuleFN = malloc(strlen(ModuleName) + 4)) == NULL)
Output(Error, NOFILE, "Couldn't malloc file name %s\n",
ModuleName);
strcpy(ModuleFN, ModuleName);è strcat(ModuleFN, ".obj");
if (ExtractModule(ModuleFN, NULL, LibHeader, InLibFH) ==
false)
Output(Error, NOFILE, "Extraction of Module %s failed\n",
ModuleFN);
free(ModuleFN);
}
free(SymbolP);
free(ModuleName);
}
}