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

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

Second iteration of the kFile* classes and interfaces.

File size: 20.8 KB
Line 
1/* $Id: kFileLX.cpp,v 1.5 2001-04-17 00:26:11 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 while (pExpState->pb32->b32_cnt != 0)
360 {
361 /* skip empty bundles */
362 while (pExpState->pb32->b32_cnt != 0 && pExpState->pb32->b32_type == EMPTY)
363 {
364 pExpState->iOrdinal += pExpState->pb32->b32_cnt;
365 pExpState->pb32 = (struct b32_bundle*)((char*)pExpState->pb32 + 2);
366 }
367
368 /* FIXME forwarders are not implemented so we'll skip them too. */
369 while (pExpState->pb32->b32_cnt != 0 && (pExpState->pb32->b32_type & ~TYPEINFO) == ENTRYFWD)
370 {
371 pExpState->iOrdinal += pExpState->pb32->b32_cnt;
372 pExpState->pb32 = (struct b32_bundle*)((char*)(pExpState->pb32 + 1) + pExpState->pb32->b32_cnt * 7);
373 }
374
375 /* we'll ignore any flags for the moment - TODO */
376 if (pExpState->pb32->b32_cnt != 0)
377 {
378 pExpState->iOrdinalBundle = pExpState->iOrdinal;
379
380 pExport->ulOrdinal = pExpState->iOrdinal;
381 pExport->iObject = pExpState->pb32->b32_obj;
382
383 /* look for name */
384 pExport->achIntName[0] = '\0';
385 if (!queryExportName(pExpState->iOrdinal, pExport->achName))
386 pExport->achName[0] = '\0';
387
388 pExpState->pe32 = (struct e32_entry*)(pExpState->pb32+1);
389 switch (pExpState->pb32->b32_type & ~TYPEINFO)
390 {
391 case ENTRY16:
392 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset16;
393 break;
394
395 case ENTRY32:
396 pExport->ulOffset = pExpState->pe32->e32_variant.e32_offset.offset32;
397 break;
398
399 case GATE16:
400 pExport->ulOffset = pExpState->pe32->e32_variant.e32_callgate.offset;
401 break;
402 default:
403 assert(!"ARG!!!! invalid bundle type!");
404 }
405
406 return TRUE;
407 }
408 }
409
410
411 /*
412 * No more exports - clean up
413 */
414 free(pExport->pv);
415 pExport->pv = NULL;
416 return FALSE;
417}
418
419
420/**
421 * Frees resources associated with the communicatin area.
422 * It's not necessary to call this when exportFindNext has return FALSE.
423 * @param pExport Communication area which has been successfully
424 * processed by findFirstExport.
425 */
426void kFileLX::exportFindClose(kExportEntry *pExport)
427{
428 free(pExport->pv);
429 pExport->pv = NULL;
430 return;
431}
432
433
434/**
435 * Lookup information on a spesific export given by ordinal number.
436 * @returns Success indicator.
437 * @param pExport Communication area containing export information
438 * on successful return.
439 * @remark stub
440 */
441BOOL kFileLX::exportLookup(unsigned long ulOrdinal, kExportEntry *pExport)
442{
443 assert(!"not implemented.");
444 ulOrdinal = ulOrdinal;
445 pExport = pExport;
446 return FALSE;
447}
448
449/**
450 * Lookup information on a spesific export given by name.
451 * @returns Success indicator.
452 * @param pExport Communication area containing export information
453 * on successful return.
454 * @remark stub
455 */
456BOOL kFileLX::exportLookup(const char * pszName, kExportEntry *pExport)
457{
458 assert(!"not implemented.");
459 pszName = pszName;
460 pExport = pExport;
461 return FALSE;
462}
463
464
465/**
466 * Gets a specific LX object.
467 * @returns Pointer to object. NULL on error / invalid index.
468 * @param iObject object number (0-based)
469 */
470struct o32_obj * kFileLX::getObject(int iObject)
471{
472
473 if (iObject < pe32->e32_objcnt)
474 return &paObject[iObject];
475 return NULL;
476}
477
478
479/**
480 * Gets the count of LX objects.
481 * @returns Count of LX objects.
482 */
483int kFileLX::getObjectCount()
484{
485 return (int)pe32->e32_objcnt;
486}
487
488#if 0
489
490/** @cat Get and put page methods. (the first ones are generic) */
491BOOL kFileLX::getPage(char *pachPage, ULONG ulAddress)
492{
493 int iObj;
494
495 for (iObj = 0; iObj < pe32->e32_objcnt; iObj++)
496 if ( paObject[iObj].o32_base > ulAddress
497 && paObject[iObj].o32_base + paObject[iObj].o32_size > ulAddress
498 )
499 return getPage(pachPage, iObj, ulAddress - paObject[iObj].o32_base);
500
501 return FALSE;
502}
503
504BOOL kFileLX::getPage(char *pachPage, int iObject, int offObject)
505{
506 offObject &= ~(PAGESIZE - 1);
507 if ( iObject >= pe32->e32_objcnt
508 && offObject >= paObject[iObject].o32_size
509 )
510 return FALSE;
511
512 /*
513 * Is there a pagemap entry for the requested page?
514 */
515 if ((offObject >> PAGESHIFT) < paObject[iObject].o32_mapsize)
516 { /* yes */
517 int iPage = (offObject >> PAGESIZE) + paObject[iObject].o32_pagemap - 1;
518 char * pchPageData = (char*)((paMap[iPage].o32_pagedataoffset << pe32->e32_pageshift) + pe32->e32_datapage + (char*)pvBase);
519
520 if (pchPageData )
521 {
522 }
523
524 }
525 else
526 { /* no, so it's a zero page */
527 memset(pachPage, 0, PAGESIZE);
528 }
529
530 return FALSE;
531}
532
533BOOL kFileLX::putPage(const char *pachPage, ULONG ulAddress)
534{
535 return FALSE;
536}
537
538BOOL kFileLX::putPage(const char *pachPage, int iObject, int offObject)
539{
540 return FALSE;
541}
542
543BOOL kFileLX::getPageLX(char *pachPage, int iObject, int iPage)
544{
545 return FALSE;
546}
547
548BOOL kFileLX::getPageLX(char *pachPage, int iPage)
549{
550 return FALSE;
551}
552
553BOOL kFileLX::putPageLX(const char *pachPage, int iObject, int iPage)
554{
555 return FALSE;
556}
557
558BOOL kFileLX::putPageLX(const char *pachPage, int iPage)
559{
560 return FALSE;
561}
562
563
564/**
565 * Expands a page compressed with the old exepack method introduced with OS/2 2.0.
566 * (/EXEPACK or just /EXEPACK)
567 * @returns Successindicator.
568 * @param pachPage Pointer to output page. size: PAGESIZE
569 * Upon successful return this will contain the expanded page data.
570 * @param pachSrcPage Pointer to source data. size: cchSrcPage.
571 * This data should be compressed with EXEPACK:2!
572 * @sketch Have no good idea right now.
573 * @status Completely implemented.
574 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
575 * @remark
576 */
577BOOL kFileLX::expandPage1(char *pachPage, const char * pachSrcPage, int cchSrcPage)
578{
579 struct LX_Iter *pIter = (struct LX_Iter *)pachSrcPage;
580 char * pachDestPage = pachPage; /* Store the pointer for boundrary checking. */
581
582 /* Validate size of data. */
583 if (cchSrcPage >= PAGESIZE - 2)
584 return FALSE;
585
586 /*
587 * Expand the page.
588 */
589 while (pIter->LX_nIter)
590 {
591 /* Check if we're out of bound. */
592 if ( pachPage - pachDesPage + pIter->LX_nIter * pIter->LX_nBytes > PAGESIZE
593 || cchSrcPage <= 0)
594 return FALSE;
595
596 if (pIter->LX_nBytes == 1)
597 { /* one databyte */
598 memset(pachPage, &pIter->LX_Iterdata, pIter->LX_nIter);
599 pchPage += pIter->LX_nIter;
600 cchSrcPage -= pIter->LX_nIter + 4;
601 pIter++;
602 }
603 else
604 {
605 for (int i = 0; i < pIter->LX_nIter; i++, pachPage += pIter->LX_nBytes)
606 memcpy(pachPage, &pIter->LX_Iterdata, pIter->LX_nBytes);
607 cchSrcPage -= 4 + pIter->LX_nBytes;
608 pIter = (pIter)((char*)pIter 4 + pIter->LX_nBytes);
609 }
610 }
611 return TRUE;
612#if 0
613/* example code */
614 int off;
615 struct LX_Iter *pIter;
616 char * pch = pvPage; /* Current position on page */
617
618 off = pe32->e32_datapage + (pObjMap->o32_pagedataoffset << pe32->e32_pageshift);
619 if (pObjMap->o32_pagesize && (off + pObjMap->o32_pagesize - 1) >= cbFile)
620 {
621 fprintf(stderr, "Error: Page resides outside of the file.\n");
622 return 1;
623 }
624 pIter = (struct LX_Iter *)((char*)pvFile + off);
625
626 /* expand page */
627 while (pIter->LX_nIter > 0)
628 {
629 if (pch + (pIter->LX_nBytes * pIter->LX_nIter) > (char*)pvPage + OBJPAGELEN)
630 {
631 fprintf(stderr, "Error: Iterated page expands to more than a page!\n");
632 return 1;
633 }
634
635 if (pIter->LX_nBytes == 1)
636 {
637 memset(pch, pIter->LX_Iterdata, pIter->LX_nIter);
638 pch += pIter->LX_nIter;
639 pIter++;
640 }
641 else
642 {
643 int i;
644 for (i = 0; i < pIter->LX_nIter; i++, pch += pIter->LX_nBytes)
645 memcpy(pch, &pIter->LX_Iterdata, pIter->LX_nBytes);
646 #if 1 /* curious */
647 if (pIter->LX_nBytes > 2) fprintf(stdout, "pIter->LX_nBytes = %\n", pIter->LX_nBytes);
648 #endif
649
650 pIter = (struct LX_Iter*)((char*)pIter + 4 + pIter->LX_nBytes);
651 }
652 }
653
654 return FALSE;
655#endif
656}
657
658
659/**
660 * Expands a page compressed with the exepack method introduced with OS/2 Warp 3.0.
661 * (/EXEPACK:2)
662 * @returns Successindicator.
663 * @param pachPage Pointer to output page. size: PAGESIZE
664 * Upon successful return this will contain the expanded page data.
665 * @param pachSrcPage Pointer to source data. size: cchSrcPage.
666 * This data should be compressed with EXEPACK:2!
667 * @sketch Have no good idea right now.
668 * @status Stub.
669 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
670 * @remark
671 */
672BOOL kFileLX::expandPage2(char *pachPage, const char * pachSrcPage, int cchSrcPage)
673{
674 NOREF(pachPage);
675 NOREF(pachSrcPage);
676 NOREF(cchSrcPage);
677 return FALSE;
678}
679
680
681/**
682 * Compresses a page using the old exepack method introduced with OS/2 2.0.
683 * (/EXEPACK:1 or just /EXEPACK)
684 * @returns Size of the compressed page in the pachPage buffer.
685 * PAGESIZE if failed to compress the page.
686 * -1 on error.
687 * @param pachPage Pointer to output buffer. size: PAGESIZE.
688 * This will hold the compressed page data upon return.
689 * @param pachSrcPage Pointer to page to compress. size: PAGESIZE.
690 * @sketch
691 * @status stub.
692 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
693 * @remark Not implemented.
694 */
695int kFileLX::compressPage1(char *pachPage, const char * pachSrcPage)
696{
697 NOREF(pachPage);
698 NOREF(pachSrcPage);
699 return -1;
700}
701
702
703/**
704 * Compresses a page using the exepack method introduced with OS/2 Warp 3.0.
705 * (/EXEPACK:2)
706 * @returns Size of the compressed page in the pachPage buffer.
707 * PAGESIZE if failed to compress the page.
708 * -1 on error.
709 * @param pachPage Pointer to output buffer. size: PAGESIZE.
710 * This will hold the compressed page data upon return.
711 * @param pachSrcPage Pointer to page to compress. size: PAGESIZE.
712 * @sketch Have no idea!
713 * @status stub.
714 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
715 * @remark Not implemented.
716 */
717int kFileLX::compressPage2(char *pachPage, const char * pachSrcPage)
718{
719 NOREF(pachPage);
720 NOREF(pachSrcPage);
721 return -1;
722}
723
724#endif
Note: See TracBrowser for help on using the repository browser.