source: trunk/tools/common/kFileLX.cpp@ 6932

Last change on this file since 6932 was 6932, checked in by bird, 24 years ago

Corrected bug in export enumeration.

File size: 20.9 KB
Line 
1/* $Id: kFileLX.cpp,v 1.6 2001-10-03 01:44:49 bird Exp $
2 *
3 *
4 *
5 * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 */
10
11/*******************************************************************************
12* Defined Constants *
13*******************************************************************************/
14/* emx fixups */
15#ifdef __EMX__
16 #define __stdcall
17 #define max(a,b) (((a) > (b)) ? (a) : (b))
18 #define min(a,b) (((a) < (b)) ? (a) : (b))
19#endif
20#define INCL_DOSERRORS
21#define FOR_EXEHDR 1 /* exe386.h flag */
22#define DWORD ULONG /* Used by exe386.h / newexe.h */
23#define WORD USHORT /* Used by exe386.h / newexe.h */
24
25
26/******************************************************************************
27* Header Files *
28******************************************************************************/
29#ifdef __EMX__
30#define INT INT_
31#define PCHAR PCHAR_
32#endif
33#include <os2.h>
34#ifdef __EMX__
35#undef PCHAR
36#undef INT
37#endif
38#include <newexe.h>
39#include <exe386.h>
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <malloc.h>
45
46#include <assert.h>
47
48#include "kFile.h"
49#include "kFileFormatBase.h"
50#include "kInterfaces.h"
51#include "kFileLX.h"
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57typedef struct _export_state
58{
59 struct b32_bundle * pb32; /* Pointer to current bundle. */
60 int iOrdinalBundle; /* The ordinal the bundle starts at. */
61 struct e32_entry * pe32; /* Pointer to the current bundle entry. */
62 int iOrdinal; /* The current ordinal. */
63} EXPSTATE, *PEXPSTATE;
64
65
66/*******************************************************************************
67* Global Variables *
68*******************************************************************************/
69#if 0
70static kFileLX tst((kFile*)NULL);
71#endif
72
73
74/**
75 * Internal worker which lookup the name corresponding to an ordinal.
76 * @returns Success indicator.
77 * @param iOrdinal ( >= 0).
78 * @param pszBuffer.
79 */
80BOOL kFileLX::queryExportName(int iOrdinal, char *pszBuffer)
81{
82 PUSHORT pus;
83 PUCHAR puch;
84
85 /* resident name table */
86 if (pe32->e32_restab)
87 {
88 puch = (PUCHAR)pvBase + offLXHdr + pe32->e32_restab;
89 while (*puch != 0)
90 {
91 pus = (PUSHORT)(puch + 1 + *puch);
92 if (*pus == iOrdinal)
93 {
94 memcpy(pszBuffer, puch + 1, *puch);
95 pszBuffer[*puch] = '\0';
96 return TRUE;
97 }
98 puch += *puch + 1 + 2;
99 }
100 }
101
102 /* not found, check the non-resident name table too */
103 if (pe32->e32_nrestab)
104 {
105 puch = (PUCHAR)pvBase + pe32->e32_nrestab;
106 while (*puch != 0)
107 {
108 pus = (PUSHORT)(puch + 1 + *puch);
109 if (*pus == iOrdinal)
110 {
111 memcpy(pszBuffer, puch + 1, *puch);
112 pszBuffer[*puch] = '\0';
113 return TRUE;
114 }
115 puch += *puch + 1 + 2;
116 }
117 }
118
119 return FALSE;
120}
121
122
123
124/**
125 * Create an LX file object from an LX executable image.
126 * @param pszFilename LX executable image name.
127 */
128kFileLX::kFileLX(const char *pszFilename) throw (int)
129: pvBase(NULL)
130{
131 struct exe_hdr * pehdr;
132
133 /* create filemapping */
134 pvBase = kFile::readFile(pszFilename);
135 if (pvBase == NULL)
136 throw(1);
137
138 pehdr = (struct exe_hdr*)pvBase;
139 if (pehdr->e_magic == EMAGIC)
140 offLXHdr = pehdr->e_lfanew;
141 else
142 offLXHdr = 0;
143
144 pe32 = (struct e32_exe*)((char*)pvBase + offLXHdr);
145 if (*(PUSHORT)pe32 != E32MAGIC)
146 {
147 free(pvBase);
148 pvBase = NULL;
149 throw(2);
150 }
151
152 paObject = pe32->e32_objtab && pe32->e32_objcnt
153 ? (struct o32_obj*)((char*)pvBase + pe32->e32_objtab + offLXHdr) : NULL;
154 paMap = pe32->e32_objmap
155 ? (struct o32_map*)((char*)pvBase + pe32->e32_objmap + offLXHdr) : NULL;
156}
157
158
159/**
160 * Create an LX file object from an LX executable image.
161 * @param pFile Pointer to opened LX file.
162 */
163kFileLX::kFileLX(kFile *pFile) throw (int)
164: pvBase(NULL)
165{
166 struct exe_hdr * pehdr;
167
168 /* create filemapping */
169 pvBase = pFile->readFile();
170 if (pvBase == NULL)
171 throw(1);
172
173 pehdr = (struct exe_hdr*)pvBase;
174 if (pehdr->e_magic == EMAGIC)
175 offLXHdr = pehdr->e_lfanew;
176 else
177 offLXHdr = 0;
178
179 pe32 = (struct e32_exe*)((char*)pvBase + offLXHdr);
180 if (*(PUSHORT)pe32 != E32MAGIC)
181 {
182 free(pvBase);
183 pvBase = NULL;
184 throw(2);
185 }
186
187 paObject = pe32->e32_objtab && pe32->e32_objcnt
188 ? (struct o32_obj*)((char*)pvBase + pe32->e32_objtab + offLXHdr) : NULL;
189 paMap = pe32->e32_objmap
190 ? (struct o32_map*)((char*)pvBase + pe32->e32_objmap + offLXHdr) : NULL;
191}
192
193
194
195/**
196 * Destructor.
197 */
198kFileLX::~kFileLX()
199{
200 if (pvBase != NULL)
201 free(pvBase);
202 pvBase = NULL;
203}
204
205
206
207/**
208 * Query for the module name.
209 * @returns Success indicator. TRUE / FALSE.
210 * @param pszBuffer Pointer to buffer which to put the name into.
211 * @param cchBuffer Size of the buffer (defaults to 260 chars).
212 */
213BOOL kFileLX::moduleGetName(char *pszBuffer, int cchBuffer/*= 260*/)
214{
215 /* The module name is the 0 ordinal entry in resident name table */
216 assert(cchBuffer >= 255);
217 return queryExportName(0, pszBuffer);
218}
219
220
221/**
222 * Finds the first exports.
223 * @returns Success indicator. TRUE / FALSE.
224 * @param pExport Pointer to export structure.
225 */
226BOOL kFileLX::exportFindFirst(kExportEntry *pExport)
227{
228 struct b32_bundle * pBundle = (struct b32_bundle*)((char*)pvBase + pe32->e32_enttab + offLXHdr);
229 struct e32_entry * pEntry;
230 int iOrdinal = 1;
231
232 if (pe32->e32_enttab)
233 {
234 while (pBundle->b32_cnt != 0)
235 {
236 /* skip empty bundles */
237 while (pBundle->b32_cnt != 0 && pBundle->b32_type == EMPTY)
238 {
239 iOrdinal += pBundle->b32_cnt;
240 pBundle = (struct b32_bundle*)((char*)pBundle + 2);
241 }
242
243 /* FIXME forwarders are not implemented so we'll skip them too. */
244 while (pBundle->b32_cnt != 0 && (pBundle->b32_type & ~TYPEINFO) == ENTRYFWD)
245 {
246 iOrdinal += pBundle->b32_cnt;
247 pBundle = (struct b32_bundle*)((char*)(pBundle + 1) + pBundle->b32_cnt * 7);
248 }
249
250 /* we'll ignore any flags for the moment - TODO */
251 if (pBundle->b32_cnt != 0)
252 {
253 pExport->ulOrdinal = iOrdinal;
254 pExport->iObject = pBundle->b32_obj;
255
256 /* look for name */
257 pExport->achIntName[0] = '\0';
258 if (!queryExportName(iOrdinal, pExport->achName))
259 pExport->achName[0] = '\0';
260
261 pEntry = (struct e32_entry*)(pBundle+1);
262 switch (pBundle->b32_type & ~TYPEINFO)
263 {
264 case ENTRY16:
265 pExport->ulOffset = pEntry->e32_variant.e32_offset.offset16;
266 break;
267
268 case ENTRY32:
269 pExport->ulOffset = pEntry->e32_variant.e32_offset.offset32;
270 break;
271
272 case GATE16:
273 pExport->ulOffset = pEntry->e32_variant.e32_callgate.offset;
274 break;
275 default:
276 assert(!"ARG!!!! invalid bundle type!");
277 }
278
279 /* store status - current export entry */
280 PEXPSTATE pExpState = (PEXPSTATE)malloc(sizeof(EXPSTATE));
281 pExport->pv = pExpState;
282 pExpState->pb32 = pBundle;
283 pExpState->iOrdinalBundle = iOrdinal;
284 pExpState->pe32 = pEntry;
285 pExpState->iOrdinal = iOrdinal;
286 pExport->ulAddress = ~0UL; /* TODO */
287 return TRUE;
288 }
289 }
290
291 }
292
293 return FALSE;
294}
295
296
297/**
298 * Finds the next export.
299 * @returns Success indicator. TRUE / FALSE.
300 * @param pExport Pointer to export structure.
301 */
302BOOL kFileLX::exportFindNext(kExportEntry *pExport)
303{
304 static int acbEntry[] =
305 {
306 0, /* EMPTY */
307 3, /* ENTRY16 */
308 5, /* GATE16 */
309 5, /* ENTRY32 */
310 7 /* ENTRYFWD */
311 };
312
313 PEXPSTATE pExpState = (PEXPSTATE)pExport->pv;
314 pExport->ulAddress = ~0UL; /* TODO */
315
316 /*
317 * Get more ordinals from the current bundle if any left.
318 */
319 if (pExpState->pb32->b32_cnt > (pExpState->iOrdinal - pExpState->iOrdinalBundle + 1))
320 {
321 /* skip to the next entry */
322 pExpState->iOrdinal++;
323 pExpState->pe32 = (struct e32_entry*)((char*)pExpState->pe32
324 + acbEntry[pExpState->pb32->b32_type & ~TYPEINFO]);
325
326 /* fill output struct */
327 pExport->ulOrdinal = pExpState->iOrdinal;
328 pExport->iObject = pExpState->pb32->b32_obj;
329
330 /* look for name */
331 pExport->achIntName[0] = '\0';
332 if (!queryExportName(pExpState->iOrdinal, pExport->achName))
333 pExport->achName[0] = '\0';
334
335 /* ulOffset */
336 switch (pExpState->pb32->b32_type & ~TYPEINFO)
337 {
338 case ENTRY16:
339 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset16;
340 break;
341
342 case ENTRY32:
343 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset32;
344 break;
345
346 case GATE16:
347 pExport->ulOffset = pExpState->pe32->e32_variant.e32_callgate.offset;
348 break;
349 }
350
351 return TRUE;
352 }
353
354 /*
355 * next bundle.
356 */
357 pExpState->pb32 = (struct b32_bundle*)((char*)(pExpState->pb32 + 1) +
358 pExpState->pb32->b32_cnt * acbEntry[pExpState->pb32->b32_type & ~TYPEINFO]);
359 pExpState->iOrdinal++;
360 while (pExpState->pb32->b32_cnt != 0)
361 {
362 /* skip empty bundles */
363 if (pExpState->pb32->b32_cnt != 0 && pExpState->pb32->b32_type == EMPTY)
364 {
365 pExpState->iOrdinal += pExpState->pb32->b32_cnt;
366 pExpState->pb32 = (struct b32_bundle*)((char*)pExpState->pb32 + 2);
367 continue;
368 }
369
370 /* FIXME forwarders are not implemented so we'll skip them too. */
371 if (pExpState->pb32->b32_cnt != 0 && (pExpState->pb32->b32_type & ~TYPEINFO) == ENTRYFWD)
372 {
373 pExpState->iOrdinal += pExpState->pb32->b32_cnt;
374 pExpState->pb32 = (struct b32_bundle*)((char*)(pExpState->pb32 + 1) + pExpState->pb32->b32_cnt * 7);
375 continue;
376 }
377
378 /* we'll ignore any flags for the moment - TODO */
379 if (pExpState->pb32->b32_cnt != 0)
380 {
381 pExpState->iOrdinalBundle = pExpState->iOrdinal;
382
383 pExport->ulOrdinal = pExpState->iOrdinal;
384 pExport->iObject = pExpState->pb32->b32_obj;
385
386 /* look for name */
387 pExport->achIntName[0] = '\0';
388 if (!queryExportName(pExpState->iOrdinal, pExport->achName))
389 pExport->achName[0] = '\0';
390
391 pExpState->pe32 = (struct e32_entry*)(pExpState->pb32+1);
392 switch (pExpState->pb32->b32_type & ~TYPEINFO)
393 {
394 case ENTRY16:
395 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset16;
396 break;
397
398 case ENTRY32:
399 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset32;
400 break;
401
402 case GATE16:
403 pExport->ulOffset = pExpState->pe32->e32_variant.e32_callgate.offset;
404 break;
405
406 default:
407 assert(!"ARG!!!! invalid bundle type!");
408 }
409
410 return TRUE;
411 }
412 }
413
414
415 /*
416 * No more exports - clean up
417 */
418 free(pExport->pv);
419 pExport->pv = NULL;
420 return FALSE;
421}
422
423
424/**
425 * Frees resources associated with the communicatin area.
426 * It's not necessary to call this when exportFindNext has return FALSE.
427 * @param pExport Communication area which has been successfully
428 * processed by findFirstExport.
429 */
430void kFileLX::exportFindClose(kExportEntry *pExport)
431{
432 free(pExport->pv);
433 pExport->pv = NULL;
434 return;
435}
436
437
438/**
439 * Lookup information on a spesific export given by ordinal number.
440 * @returns Success indicator.
441 * @param pExport Communication area containing export information
442 * on successful return.
443 * @remark stub
444 */
445BOOL kFileLX::exportLookup(unsigned long ulOrdinal, kExportEntry *pExport)
446{
447 assert(!"not implemented.");
448 ulOrdinal = ulOrdinal;
449 pExport = pExport;
450 return FALSE;
451}
452
453/**
454 * Lookup information on a spesific export given by name.
455 * @returns Success indicator.
456 * @param pExport Communication area containing export information
457 * on successful return.
458 * @remark stub
459 */
460BOOL kFileLX::exportLookup(const char * pszName, kExportEntry *pExport)
461{
462 assert(!"not implemented.");
463 pszName = pszName;
464 pExport = pExport;
465 return FALSE;
466}
467
468
469/**
470 * Gets a specific LX object.
471 * @returns Pointer to object. NULL on error / invalid index.
472 * @param iObject object number (0-based)
473 */
474struct o32_obj * kFileLX::getObject(int iObject)
475{
476
477 if (iObject < pe32->e32_objcnt)
478 return &paObject[iObject];
479 return NULL;
480}
481
482
483/**
484 * Gets the count of LX objects.
485 * @returns Count of LX objects.
486 */
487int kFileLX::getObjectCount()
488{
489 return (int)pe32->e32_objcnt;
490}
491
492#if 0
493
494/** @cat Get and put page methods. (the first ones are generic) */
495BOOL kFileLX::getPage(char *pachPage, ULONG ulAddress)
496{
497 int iObj;
498
499 for (iObj = 0; iObj < pe32->e32_objcnt; iObj++)
500 if ( paObject[iObj].o32_base > ulAddress
501 && paObject[iObj].o32_base + paObject[iObj].o32_size > ulAddress
502 )
503 return getPage(pachPage, iObj, ulAddress - paObject[iObj].o32_base);
504
505 return FALSE;
506}
507
508BOOL kFileLX::getPage(char *pachPage, int iObject, int offObject)
509{
510 offObject &= ~(PAGESIZE - 1);
511 if ( iObject >= pe32->e32_objcnt
512 && offObject >= paObject[iObject].o32_size
513 )
514 return FALSE;
515
516 /*
517 * Is there a pagemap entry for the requested page?
518 */
519 if ((offObject >> PAGESHIFT) < paObject[iObject].o32_mapsize)
520 { /* yes */
521 int iPage = (offObject >> PAGESIZE) + paObject[iObject].o32_pagemap - 1;
522 char * pchPageData = (char*)((paMap[iPage].o32_pagedataoffset << pe32->e32_pageshift) + pe32->e32_datapage + (char*)pvBase);
523
524 if (pchPageData )
525 {
526 }
527
528 }
529 else
530 { /* no, so it's a zero page */
531 memset(pachPage, 0, PAGESIZE);
532 }
533
534 return FALSE;
535}
536
537BOOL kFileLX::putPage(const char *pachPage, ULONG ulAddress)
538{
539 return FALSE;
540}
541
542BOOL kFileLX::putPage(const char *pachPage, int iObject, int offObject)
543{
544 return FALSE;
545}
546
547BOOL kFileLX::getPageLX(char *pachPage, int iObject, int iPage)
548{
549 return FALSE;
550}
551
552BOOL kFileLX::getPageLX(char *pachPage, int iPage)
553{
554 return FALSE;
555}
556
557BOOL kFileLX::putPageLX(const char *pachPage, int iObject, int iPage)
558{
559 return FALSE;
560}
561
562BOOL kFileLX::putPageLX(const char *pachPage, int iPage)
563{
564 return FALSE;
565}
566
567
568/**
569 * Expands a page compressed with the old exepack method introduced with OS/2 2.0.
570 * (/EXEPACK or just /EXEPACK)
571 * @returns Successindicator.
572 * @param pachPage Pointer to output page. size: PAGESIZE
573 * Upon successful return this will contain the expanded page data.
574 * @param pachSrcPage Pointer to source data. size: cchSrcPage.
575 * This data should be compressed with EXEPACK:2!
576 * @sketch Have no good idea right now.
577 * @status Completely implemented.
578 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
579 * @remark
580 */
581BOOL kFileLX::expandPage1(char *pachPage, const char * pachSrcPage, int cchSrcPage)
582{
583 struct LX_Iter *pIter = (struct LX_Iter *)pachSrcPage;
584 char * pachDestPage = pachPage; /* Store the pointer for boundrary checking. */
585
586 /* Validate size of data. */
587 if (cchSrcPage >= PAGESIZE - 2)
588 return FALSE;
589
590 /*
591 * Expand the page.
592 */
593 while (pIter->LX_nIter)
594 {
595 /* Check if we're out of bound. */
596 if ( pachPage - pachDesPage + pIter->LX_nIter * pIter->LX_nBytes > PAGESIZE
597 || cchSrcPage <= 0)
598 return FALSE;
599
600 if (pIter->LX_nBytes == 1)
601 { /* one databyte */
602 memset(pachPage, &pIter->LX_Iterdata, pIter->LX_nIter);
603 pchPage += pIter->LX_nIter;
604 cchSrcPage -= pIter->LX_nIter + 4;
605 pIter++;
606 }
607 else
608 {
609 for (int i = 0; i < pIter->LX_nIter; i++, pachPage += pIter->LX_nBytes)
610 memcpy(pachPage, &pIter->LX_Iterdata, pIter->LX_nBytes);
611 cchSrcPage -= 4 + pIter->LX_nBytes;
612 pIter = (pIter)((char*)pIter 4 + pIter->LX_nBytes);
613 }
614 }
615 return TRUE;
616#if 0
617/* example code */
618 int off;
619 struct LX_Iter *pIter;
620 char * pch = pvPage; /* Current position on page */
621
622 off = pe32->e32_datapage + (pObjMap->o32_pagedataoffset << pe32->e32_pageshift);
623 if (pObjMap->o32_pagesize && (off + pObjMap->o32_pagesize - 1) >= cbFile)
624 {
625 fprintf(stderr, "Error: Page resides outside of the file.\n");
626 return 1;
627 }
628 pIter = (struct LX_Iter *)((char*)pvFile + off);
629
630 /* expand page */
631 while (pIter->LX_nIter > 0)
632 {
633 if (pch + (pIter->LX_nBytes * pIter->LX_nIter) > (char*)pvPage + OBJPAGELEN)
634 {
635 fprintf(stderr, "Error: Iterated page expands to more than a page!\n");
636 return 1;
637 }
638
639 if (pIter->LX_nBytes == 1)
640 {
641 memset(pch, pIter->LX_Iterdata, pIter->LX_nIter);
642 pch += pIter->LX_nIter;
643 pIter++;
644 }
645 else
646 {
647 int i;
648 for (i = 0; i < pIter->LX_nIter; i++, pch += pIter->LX_nBytes)
649 memcpy(pch, &pIter->LX_Iterdata, pIter->LX_nBytes);
650 #if 1 /* curious */
651 if (pIter->LX_nBytes > 2) fprintf(stdout, "pIter->LX_nBytes = %\n", pIter->LX_nBytes);
652 #endif
653
654 pIter = (struct LX_Iter*)((char*)pIter + 4 + pIter->LX_nBytes);
655 }
656 }
657
658 return FALSE;
659#endif
660}
661
662
663/**
664 * Expands a page compressed with the exepack method introduced with OS/2 Warp 3.0.
665 * (/EXEPACK:2)
666 * @returns Successindicator.
667 * @param pachPage Pointer to output page. size: PAGESIZE
668 * Upon successful return this will contain the expanded page data.
669 * @param pachSrcPage Pointer to source data. size: cchSrcPage.
670 * This data should be compressed with EXEPACK:2!
671 * @sketch Have no good idea right now.
672 * @status Stub.
673 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
674 * @remark
675 */
676BOOL kFileLX::expandPage2(char *pachPage, const char * pachSrcPage, int cchSrcPage)
677{
678 NOREF(pachPage);
679 NOREF(pachSrcPage);
680 NOREF(cchSrcPage);
681 return FALSE;
682}
683
684
685/**
686 * Compresses a page using the old exepack method introduced with OS/2 2.0.
687 * (/EXEPACK:1 or just /EXEPACK)
688 * @returns Size of the compressed page in the pachPage buffer.
689 * PAGESIZE if failed to compress the page.
690 * -1 on error.
691 * @param pachPage Pointer to output buffer. size: PAGESIZE.
692 * This will hold the compressed page data upon return.
693 * @param pachSrcPage Pointer to page to compress. size: PAGESIZE.
694 * @sketch
695 * @status stub.
696 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
697 * @remark Not implemented.
698 */
699int kFileLX::compressPage1(char *pachPage, const char * pachSrcPage)
700{
701 NOREF(pachPage);
702 NOREF(pachSrcPage);
703 return -1;
704}
705
706
707/**
708 * Compresses a page using the exepack method introduced with OS/2 Warp 3.0.
709 * (/EXEPACK:2)
710 * @returns Size of the compressed page in the pachPage buffer.
711 * PAGESIZE if failed to compress the page.
712 * -1 on error.
713 * @param pachPage Pointer to output buffer. size: PAGESIZE.
714 * This will hold the compressed page data upon return.
715 * @param pachSrcPage Pointer to page to compress. size: PAGESIZE.
716 * @sketch Have no idea!
717 * @status stub.
718 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
719 * @remark Not implemented.
720 */
721int kFileLX::compressPage2(char *pachPage, const char * pachSrcPage)
722{
723 NOREF(pachPage);
724 NOREF(pachSrcPage);
725 return -1;
726}
727
728#endif
Note: See TracBrowser for help on using the repository browser.