Ignore:
Timestamp:
Feb 24, 2002, 3:47:28 AM (24 years ago)
Author:
bird
Message:

New kFile* classes; now in sync with os2tools.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tools/common/kFileLX.cpp

    r6932 r8003  
    1 /* $Id: kFileLX.cpp,v 1.6 2001-10-03 01:44:49 bird Exp $
     1/* $Id: kFileLX.cpp,v 1.7 2002-02-24 02:47:26 bird Exp $
    22 *
    33 *
     
    99 */
    1010
    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 
    2611/******************************************************************************
    2712*   Header Files                                                              *
    2813******************************************************************************/
    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>
     14#include <MZexe.h>
     15#include <LXexe.h>
    4016
    4117#include <stdio.h>
    4218#include <stdlib.h>
    4319#include <string.h>
    44 #include <malloc.h>
    45 
    46 #include <assert.h>
    47 
     20
     21#include "kTypes.h"
     22#include "kError.h"
    4823#include "kFile.h"
    4924#include "kFileFormatBase.h"
    50 #include "kInterfaces.h"
     25#include "kFileInterfaces.h"
    5126#include "kFileLX.h"
    5227
     
    5530*   Structures and Typedefs                                                    *
    5631*******************************************************************************/
    57 typedef struct _export_state
     32typedef struct _LXExportState
    5833{
    5934    struct b32_bundle * pb32;           /* Pointer to current bundle. */
     
    6237    int                 iOrdinal;       /* The current ordinal. */
    6338} EXPSTATE, *PEXPSTATE;
     39
     40
     41/**
     42 * relocFind*() state info.
     43 * Stored as kRelocEntry::pv1.
     44 */
     45typedef struct _LXRelocState
     46{
     47    unsigned long   ulSegment;          /* The current segment. (0-based) */
     48    unsigned long   ulPage;             /* The current page. (0-based index) */
     49    char *          pchFixupRec;        /* The current fixup record. */
     50    unsigned short  usSrcOffIdx;        /* The current source offset index. (0-based) */
     51} LXRELOCSTATE, *PLXRELOCSTATE;
    6452
    6553
     
    7260
    7361
     62/*******************************************************************************
     63*   Internal Functions                                                         *
     64*******************************************************************************/
     65inline void memcpyw(char *pch1, const char *pch2, size_t cch);
     66inline void memcpyb(char *pch1, const char *pch2, size_t cch);
     67
     68
    7469/**
    7570 * Internal worker which lookup the name corresponding to an ordinal.
     
    7873 * @param   pszBuffer.
    7974 */
    80 BOOL kFileLX::queryExportName(int iOrdinal, char *pszBuffer)
    81 {
    82     PUSHORT pus;
    83     PUCHAR puch;
     75KBOOL kFileLX::queryExportName(int iOrdinal, char *pszBuffer)
     76{
     77    unsigned short *pus;
     78    unsigned char * puch;
    8479
    8580    /* resident name table */
    8681    if (pe32->e32_restab)
    8782    {
    88         puch = (PUCHAR)pvBase + offLXHdr + pe32->e32_restab;
     83        puch = (unsigned char *)pvBase + offLXHdr + pe32->e32_restab;
    8984        while (*puch != 0)
    9085        {
    91             pus = (PUSHORT)(puch + 1 + *puch);
     86            pus = (unsigned short *)(puch + 1 + *puch);
    9287            if (*pus == iOrdinal)
    9388            {
     
    10398    if (pe32->e32_nrestab)
    10499    {
    105         puch = (PUCHAR)pvBase + pe32->e32_nrestab;
     100        puch = (unsigned char *)pvBase + pe32->e32_nrestab;
    106101        while (*puch != 0)
    107102        {
    108             pus = (PUSHORT)(puch + 1 + *puch);
     103            pus = (unsigned short *)(puch + 1 + *puch);
    109104            if (*pus == iOrdinal)
    110105            {
     
    120115}
    121116
     117/**
     118 * Converts a FLAT address to an obj:offset address.
     119 * @returns The offset into the object.
     120 *          -1 (0xffffffff) on error.
     121 * @param   ulAddress   Address to map.
     122 * @param   pulObject   Pointer to variable which will receive the object number (0-based).
     123 */
     124unsigned long kFileLX::lxAddressToObjectOffset(unsigned long ulAddress, unsigned long * pulObject) const
     125{
     126    int     i;
     127
     128    /* look for a object which contains the given address */
     129    for (i = 0; i < pe32->e32_objcnt; i++)
     130    {
     131        if (    paObject[i].o32_base <= ulAddress
     132            &&  paObject[i].o32_base + paObject[i].o32_size > ulAddress)
     133        {
     134            if (pulObject)
     135                *pulObject = i;
     136            return ulAddress - paObject[i].o32_base;
     137        }
     138    }
     139
     140    return ~0UL;                        /* not found */
     141}
     142
     143
     144/**
     145 * Converts an sel:off address, where sel is one of the special selectors,
     146 * to a obj:off address.
     147 * @returns The offset into the object.
     148 *          -1 (0xffffffff) on error.
     149 * @param   offObject   Offset into the selector described by *pulObject.
     150 * @param   pulObject   IN: Special selector.
     151 *                      OUT: Pointer to variable which will receive the object number (0-based).
     152 */
     153unsigned long kFileLX::lxSpecialSelectorToObjectOffset(unsigned long offObject, unsigned long * pulObject) const
     154{
     155    switch (*pulObject)
     156    {
     157        case kRelocEntry::enmRVASelector:
     158            return lxAddressToObjectOffset(offObject + paObject[0].o32_base, pulObject);
     159
     160        case kRelocEntry::enmVASelector:
     161            return lxAddressToObjectOffset(offObject, pulObject);
     162
     163        default:
     164            kASSERT(!"Internal error line");
     165    }
     166
     167    return ~0UL;
     168}
     169
     170
     171/**
     172 * Validates a FLAT address.
     173 * @returns TRUE if valid, FALSE if invalid.
     174 * @param   ulAddress   FLAT address to validate.
     175 */
     176KBOOL kFileLX::lxValidateAddress(unsigned long ulAddress) const
     177{
     178    int     i;
     179
     180    /* look for a object which contains the given address */
     181    for (i = 0; i < pe32->e32_objcnt; i++)
     182    {
     183        if (    paObject[i].o32_base <= ulAddress
     184            &&  paObject[i].o32_base + paObject[i].o32_size > ulAddress)
     185        {
     186            return TRUE;
     187        }
     188    }
     189
     190    return FALSE;
     191}
     192
     193
     194/**
     195 * Validates a object:offset address.
     196 * @returns TRUE if valid, FALSE if invalid.
     197 * @param   ulObject    Object number. (0-based)
     198 * @param   offObject   Offset into that object.
     199 */
     200KBOOL kFileLX::lxValidateObjectOffset(unsigned long ulObject, unsigned long offObject) const
     201{
     202    return pe32->e32_objcnt > ulObject && offObject < paObject[ulObject].o32_size;
     203}
     204
     205
     206
     207/**
     208 * Gets the module name corresponding to the given ordinal.
     209 * @returns Pointer to sz of the modulename. The caller is responsible for freeing it.
     210 *          NULL if invalid ordinal.
     211 * @param   ordModule   Ordinal number of the module name. (1-based)
     212 */
     213char *kFileLX::lxGetImportModuleName(unsigned long ordModule) const
     214{
     215    if (pe32->e32_impmodcnt < ordModule)
     216        return NULL;
     217
     218    char *pch = (char*)pe32 + pe32->e32_impmod;
     219    while (--ordModule)
     220        pch += *pch + 1;
     221
     222    if (!*pch)
     223        return NULL;
     224
     225    /* Copy the module name. */
     226    char *psz = new char[*pch + 1];
     227    strncpy(psz, pch + 1, *pch);
     228    psz[*pch] = '\0';
     229    return psz;
     230}
     231
     232
     233/**
     234 * Gets the proc name at the given offset.
     235 * @returns Pointer to sz of the proc name. The caller is responsible for freeing it.
     236 *          NULL if invalid offset.
     237 * @param   offProc     Offset of the proc name.
     238 */
     239char *kFileLX::lxGetImportProcName(unsigned long offProc) const
     240{
     241    char *pch = (char*)pe32 + pe32->e32_impproc + offProc;
     242    if (!*pch)
     243        return NULL;
     244
     245    /* Copy the proc name. */
     246    char *psz = new char[*pch + 1];
     247    strncpy(psz, pch + 1, *pch);
     248    psz[*pch] = '\0';
     249    return psz;
     250}
     251
    122252
    123253
     
    126256 * @param     pszFilename   LX executable image name.
    127257 */
    128 kFileLX::kFileLX(const char *pszFilename)  throw (int)
    129 : pvBase(NULL)
     258kFileLX::kFileLX(const char *pszFilename) :
     259    kFileFormatBase(NULL), pvBase(NULL)
    130260{
    131261    struct exe_hdr * pehdr;
    132262
    133263    /* create filemapping */
    134     pvBase = kFile::readFile(pszFilename);
    135     if (pvBase == NULL)
    136         throw(1);
    137 
     264    pvBase = kFile::mapFile(pszFilename);
    138265    pehdr = (struct exe_hdr*)pvBase;
    139266    if (pehdr->e_magic == EMAGIC)
     
    143270
    144271    pe32 = (struct e32_exe*)((char*)pvBase + offLXHdr);
    145     if (*(PUSHORT)pe32 != E32MAGIC)
    146     {
    147         free(pvBase);
     272    if (*(unsigned short *)pe32 != E32MAGIC)
     273    {
     274        kFile::mapFree(pvBase);
    148275        pvBase = NULL;
    149         throw(2);
     276        throw(kError(kError::INVALID_EXE_SIGNATURE));
    150277    }
    151278
    152279    paObject = pe32->e32_objtab && pe32->e32_objcnt
    153         ? (struct o32_obj*)((char*)pvBase + pe32->e32_objtab + offLXHdr) : NULL;
     280        ? (struct o32_obj *)((char *)pe32 + pe32->e32_objtab) : NULL;
    154281    paMap = pe32->e32_objmap
    155         ? (struct o32_map*)((char*)pvBase + pe32->e32_objmap + offLXHdr) : NULL;
     282        ? (struct o32_map *)((char *)pe32 + pe32->e32_objmap) : NULL;
     283    paulFixupPageTable = pe32->e32_fpagetab
     284        ? (unsigned long *)((char *)pe32 + pe32->e32_fpagetab) : NULL;
     285    pchFixupRecs = pe32->e32_frectab
     286        ? (char *)((char *)pe32 + pe32->e32_frectab) : NULL;
    156287}
    157288
     
    161292 * @param     pFile     Pointer to opened LX file.
    162293 */
    163 kFileLX::kFileLX(kFile *pFile) throw (int)
    164 : pvBase(NULL)
     294kFileLX::kFileLX(kFile *pFile) :
     295    kFileFormatBase(pFile), pvBase(NULL)
    165296{
    166297    struct exe_hdr * pehdr;
    167298
    168299    /* create filemapping */
    169     pvBase = pFile->readFile();
    170     if (pvBase == NULL)
    171         throw(1);
     300    pFile->setThrowOnErrors();
     301    pvBase = pFile->mapFile();
    172302
    173303    pehdr = (struct exe_hdr*)pvBase;
     
    178308
    179309    pe32 = (struct e32_exe*)((char*)pvBase + offLXHdr);
    180     if (*(PUSHORT)pe32 != E32MAGIC)
    181     {
    182         free(pvBase);
     310    if (*(unsigned short *)pe32 != E32MAGIC)
     311    {
     312        kFile::mapFree(pvBase);
    183313        pvBase = NULL;
    184         throw(2);
     314        throw(kError(kError::INVALID_EXE_SIGNATURE));
    185315    }
    186316
    187317    paObject = pe32->e32_objtab && pe32->e32_objcnt
    188         ? (struct o32_obj*)((char*)pvBase + pe32->e32_objtab + offLXHdr) : NULL;
     318        ? (struct o32_obj *)((char *)pe32 + pe32->e32_objtab) : NULL;
    189319    paMap = pe32->e32_objmap
    190         ? (struct o32_map*)((char*)pvBase + pe32->e32_objmap + offLXHdr) : NULL;
     320        ? (struct o32_map *)((char *)pe32 + pe32->e32_objmap) : NULL;
     321    paulFixupPageTable = pe32->e32_fpagetab
     322        ? (unsigned long *)((char *)pe32 + pe32->e32_fpagetab) : NULL;
     323    pchFixupRecs = pe32->e32_frectab
     324        ? (char *)((char *)pe32 + pe32->e32_frectab) : NULL;
    191325}
    192326
     
    199333{
    200334    if (pvBase != NULL)
    201         free(pvBase);
     335        kFile::mapFree(pvBase);
    202336    pvBase = NULL;
    203337}
     
    211345 * @param   cchBuffer   Size of the buffer (defaults to 260 chars).
    212346 */
    213 BOOL kFileLX::moduleGetName(char *pszBuffer, int cchBuffer/*= 260*/)
     347KBOOL kFileLX::moduleGetName(char *pszBuffer, int cchBuffer/*= 260*/)
    214348{
    215349    /* The module name is the 0 ordinal entry in resident name table */
    216     assert(cchBuffer >= 255);
     350    kASSERT(cchBuffer >= 255);
    217351    return queryExportName(0, pszBuffer);
    218352}
     
    224358 * @param     pExport  Pointer to export structure.
    225359 */
    226 BOOL kFileLX::exportFindFirst(kExportEntry *pExport)
     360KBOOL kFileLX::exportFindFirst(kExportEntry *pExport)
    227361{
    228362    struct b32_bundle * pBundle = (struct b32_bundle*)((char*)pvBase + pe32->e32_enttab + offLXHdr);
     
    274408                        break;
    275409                    default:
    276                         assert(!"ARG!!!! invalid bundle type!");
     410                        kASSERT(!"ARG!!!! invalid bundle type!");
    277411                }
    278412
    279413                /* store status - current export entry */
    280                 PEXPSTATE pExpState = (PEXPSTATE)malloc(sizeof(EXPSTATE));
     414                PEXPSTATE pExpState = new EXPSTATE;
    281415                pExport->pv         = pExpState;
    282416                pExpState->pb32     = pBundle;
     
    300434 * @param     pExport  Pointer to export structure.
    301435 */
    302 BOOL kFileLX::exportFindNext(kExportEntry *pExport)
     436KBOOL kFileLX::exportFindNext(kExportEntry *pExport)
    303437{
    304438    static int      acbEntry[] =
     
    357491    pExpState->pb32 = (struct b32_bundle*)((char*)(pExpState->pb32 + 1) +
    358492                        pExpState->pb32->b32_cnt * acbEntry[pExpState->pb32->b32_type & ~TYPEINFO]);
    359     pExpState->iOrdinal++;
    360493    while (pExpState->pb32->b32_cnt != 0)
    361494    {
    362495        /* skip empty bundles */
    363         if (pExpState->pb32->b32_cnt != 0 && pExpState->pb32->b32_type == EMPTY)
     496        while (pExpState->pb32->b32_cnt != 0 && pExpState->pb32->b32_type == EMPTY)
    364497        {
    365498            pExpState->iOrdinal += pExpState->pb32->b32_cnt;
    366499            pExpState->pb32 = (struct b32_bundle*)((char*)pExpState->pb32 + 2);
    367             continue;
    368500        }
    369501
    370502        /* FIXME forwarders are not implemented so we'll skip them too. */
    371         if (pExpState->pb32->b32_cnt != 0 && (pExpState->pb32->b32_type & ~TYPEINFO) == ENTRYFWD)
     503        while (pExpState->pb32->b32_cnt != 0 && (pExpState->pb32->b32_type & ~TYPEINFO) == ENTRYFWD)
    372504        {
    373505            pExpState->iOrdinal += pExpState->pb32->b32_cnt;
    374506            pExpState->pb32 = (struct b32_bundle*)((char*)(pExpState->pb32 + 1) + pExpState->pb32->b32_cnt * 7);
    375             continue;
    376507        }
    377508
     
    403534                    pExport->ulOffset = pExpState->pe32->e32_variant.e32_callgate.offset;
    404535                    break;
    405 
    406536                default:
    407                     assert(!"ARG!!!! invalid bundle type!");
     537                    kASSERT(!"ARG!!!! invalid bundle type!");
    408538            }
    409539
     
    430560void kFileLX::exportFindClose(kExportEntry *pExport)
    431561{
    432     free(pExport->pv);
     562    delete pExport->pv;
    433563    pExport->pv = NULL;
    434564    return;
     
    443573 * @remark  stub
    444574 */
    445 BOOL kFileLX::exportLookup(unsigned long ulOrdinal, kExportEntry *pExport)
    446 {
    447     assert(!"not implemented.");
     575KBOOL kFileLX::exportLookup(unsigned long ulOrdinal, kExportEntry *pExport)
     576{
     577    kASSERT(!"not implemented.");
    448578    ulOrdinal = ulOrdinal;
    449579    pExport = pExport;
     
    458588 * @remark  stub
    459589 */
    460 BOOL kFileLX::exportLookup(const char *  pszName, kExportEntry *pExport)
    461 {
    462     assert(!"not implemented.");
     590KBOOL kFileLX::exportLookup(const char *  pszName, kExportEntry *pExport)
     591{
     592    kASSERT(!"not implemented.");
    463593    pszName = pszName;
    464594    pExport = pExport;
     
    490620}
    491621
    492 #if 0
    493 
    494 /** @cat Get and put page methods. (the first ones are generic) */
    495 BOOL kFileLX::getPage(char *pachPage, ULONG ulAddress)
     622
     623/**
     624 * Get a code, data or resource page from the file.
     625 * @returns 0 on success. kError number on error.
     626 * @param   pachPage    Pointer to a buffer of the size of a page which
     627 *                      will receive the page data on the specified address.
     628 * @param   ulAddress   Page address. This must be page aligned.
     629 */
     630int     kFileLX::pageGet(char *pachPage, unsigned long ulAddress) const
    496631{
    497632    int iObj;
    498633
    499634    for (iObj = 0; iObj < pe32->e32_objcnt; iObj++)
    500         if (    paObject[iObj].o32_base > ulAddress
     635        if (    paObject[iObj].o32_base <= ulAddress
    501636            &&  paObject[iObj].o32_base + paObject[iObj].o32_size > ulAddress
    502637            )
    503             return getPage(pachPage, iObj, ulAddress - paObject[iObj].o32_base);
    504 
    505     return FALSE;
    506 }
    507 
    508 BOOL 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;
     638            return pageGet(pachPage, iObj, ulAddress - paObject[iObj].o32_base);
     639
     640    return kError::INVALID_ADDRESS;
     641}
     642
     643/**
     644 * Get a code, data or resource page from the file.
     645 * @returns 0 on success. kError number on error.
     646 * @param   pachPage    Pointer to a buffer of the size of a page which
     647 *                      will receive the page data on the specified address.
     648 * @param   iSegment    Segment number.  (0-based)
     649 * @param   offObject   Offset into the object. This must be page aligned.
     650 * @remark  Object = Section.
     651 */
     652int     kFileLX::pageGet(char *pachPage, int iSegment, int offObject) const
     653{
     654    /*
     655     * Validation.
     656     */
     657    if (offObject & (pe32->e32_pagesize - 1))
     658        return kError::BAD_ALIGNMENT;
     659    if (iSegment >= pe32->e32_objcnt)
     660        return kError::INVALID_SEGMENT_NUMBER;
     661    if (offObject >= paObject[iSegment].o32_size)
     662        return kError::INVALID_OFFSET;
    515663
    516664    /*
    517665     * Is there a pagemap entry for the requested page?
    518666     */
    519     if ((offObject >> PAGESHIFT) < paObject[iObject].o32_mapsize)
     667    if ((offObject / pe32->e32_pagesize) < paObject[iSegment].o32_mapsize)
    520668    {   /* yes */
    521         int     iPage = (offObject >> PAGESIZE) + paObject[iObject].o32_pagemap - 1;
     669        int     iPage = (offObject / pe32->e32_pagesize) + paObject[iSegment].o32_pagemap - 1;
    522670        char *  pchPageData = (char*)((paMap[iPage].o32_pagedataoffset << pe32->e32_pageshift) + pe32->e32_datapage + (char*)pvBase);
    523671
    524         if (pchPageData )
     672        switch (paMap[iPage].o32_pageflags)
    525673        {
     674            case VALID:
     675                memcpy(pachPage, pchPageData, paMap[iPage].o32_pagesize);
     676                if (paMap[iPage].o32_pagesize < pe32->e32_pagesize)
     677                    memset(pachPage + paMap[iPage].o32_pagesize, 0, pe32->e32_pagesize - paMap[iPage].o32_pagesize);
     678                break;
     679
     680            case ITERDATA:
     681            {
     682                char achTempBuffer[0x1004];
     683                memcpy(achTempBuffer, pchPageData, paMap[iPage].o32_pagesize);
     684                memset(achTempBuffer + paMap[iPage].o32_pagesize, 0, 4);
     685                return kFileLX::expandPage1(pachPage, pe32->e32_pagesize, achTempBuffer, paMap[iPage].o32_pagesize);
     686            }
     687
     688            case INVALID:
     689                return kError::INVALID_PAGE;
     690
     691            case ZEROED:
     692                memset(pachPage, 0, pe32->e32_pagesize);
     693                break;
     694
     695            case ITERDATA2:
     696        {
     697                char achTempBuffer[0x1004];
     698                memcpy(achTempBuffer, pchPageData, paMap[iPage].o32_pagesize);
     699                memset(achTempBuffer + paMap[iPage].o32_pagesize, 0, 4);
     700                return kFileLX::expandPage2(pachPage, pe32->e32_pagesize, achTempBuffer, paMap[iPage].o32_pagesize);
     701            }
     702
     703            case RANGE:
     704            default:
     705                return kError::BAD_EXE_FORMAT;
    526706        }
    527707
    528708    }
    529709    else
    530     {   /* no, so it's a zero page */
    531         memset(pachPage, 0, PAGESIZE);
    532     }
    533 
    534     return FALSE;
    535 }
    536 
    537 BOOL kFileLX::putPage(const char *pachPage, ULONG ulAddress)
    538 {
    539     return FALSE;
    540 }
    541 
    542 BOOL kFileLX::putPage(const char *pachPage, int iObject, int offObject)
    543 {
    544     return FALSE;
    545 }
    546 
    547 BOOL kFileLX::getPageLX(char *pachPage, int iObject, int iPage)
    548 {
    549     return FALSE;
    550 }
    551 
    552 BOOL kFileLX::getPageLX(char *pachPage, int iPage)
    553 {
    554     return FALSE;
    555 }
    556 
    557 BOOL kFileLX::putPageLX(const char *pachPage, int iObject, int iPage)
    558 {
    559     return FALSE;
    560 }
    561 
    562 BOOL kFileLX::putPageLX(const char *pachPage, int iPage)
    563 {
    564     return FALSE;
     710    {   /* no, so it's a zerofilled page */
     711        memset(pachPage, 0, pe32->e32_pagesize);
     712    }
     713
     714    return 0;
     715}
     716
     717
     718/**
     719 * Updates or adds a code, data, or resource page to the file.
     720 * @returns 0 on success. kError number on error.
     721 * @param   pachPage    Pointer to a buffer of the size of a page which
     722 *                      holds the page data.
     723 * @param   ulAddress   Page address. This must be page aligned.
     724 */
     725int kFileLX::pagePut(const char *pachPage, unsigned long ulAddress)
     726{
     727    int iObj;
     728
     729    for (iObj = 0; iObj < pe32->e32_objcnt; iObj++)
     730        if (    paObject[iObj].o32_base <= ulAddress
     731            &&  paObject[iObj].o32_base + paObject[iObj].o32_size > ulAddress
     732            )
     733            return pagePut(pachPage, iObj, ulAddress - paObject[iObj].o32_base);
     734
     735    return kError::INVALID_ADDRESS;
     736}
     737
     738
     739/**
     740 * Updates or adds a code, data, or resource page to the file.
     741 * @returns 0 on success. kError number on error.
     742 * @param   pachPage    Pointer to a buffer of the size of a page which
     743 *                      holds the page data.
     744 * @param   iSegment    Segment number. (0-based)
     745 * @param   offObject   Offset into the object. This must be page aligned.
     746 */
     747int kFileLX::pagePut(const char *pachPage, int iSegment, int offObject)
     748{
     749    /*
     750     * Validation.
     751     */
     752    if (offObject & (pe32->e32_pagesize - 1))
     753        return kError::BAD_ALIGNMENT;
     754    if (iSegment >= pe32->e32_objcnt)
     755        return kError::INVALID_SEGMENT_NUMBER;
     756    if (offObject >= paObject[iSegment].o32_size)
     757        return kError::INVALID_OFFSET;
     758
     759    /*
     760     * Is there a pagemap entry for the page?
     761     */
     762    if ((offObject / pe32->e32_pagesize) < paObject[iSegment].o32_mapsize)
     763    {   /* yes */
     764        int         iPage = (offObject / pe32->e32_pagesize) + paObject[iSegment].o32_pagemap - 1;
     765        char *      pchPageData = (char*)((paMap[iPage].o32_pagedataoffset << pe32->e32_pageshift) + pe32->e32_datapage + (char*)pvBase);
     766        const char *pchPageToWrite = NULL;
     767        int         cchPageToWrite = 0;
     768        long        offPageToWrite = (paMap[iPage].o32_pagedataoffset << pe32->e32_pageshift) + pe32->e32_datapage;
     769
     770        switch (paMap[iPage].o32_pageflags)
     771        {
     772            case VALID:
     773                pchPageToWrite = pachPage;
     774                cchPageToWrite = 0x1000;
     775                if (paMap[iPage].o32_pagesize != 0x1000)
     776                {
     777                    /*
     778                     * Check that everything after pagesize is zero.
     779                     */
     780                    for (const char *pch = &pachPage[paMap[iPage].o32_pagesize]; pch < &pachPage[0x1000]; pch++)
     781                        if (*pch)
     782                            return kError::NOT_SUPPORTED;
     783                    cchPageToWrite = paMap[iPage].o32_pagesize;
     784}
     785                break;
     786
     787            case ITERDATA:
     788            case ITERDATA2:
     789            {
     790                char * pchCompressedPage = (char*)alloca(pe32->e32_pagesize+4);
     791
     792                /* remove spaces at the end of the page. */
     793                int cchPage = pe32->e32_pagesize;
     794                while (pachPage[cchPage-1] == '\0')
     795                    cchPage--;
     796
     797                /* call the compression function */
     798                if (paMap[iPage].o32_pageflags == ITERDATA)
     799                    cchPageToWrite = kFileLX::compressPage1(pchCompressedPage, pachPage, cchPage);
     800                else
     801                    cchPageToWrite = kFileLX::compressPage2(pchCompressedPage, pachPage, cchPage);
     802                //if (cchPageToWrite != paMap[iPage].o32_pagesize)
     803                //    printf("compressPageX returned %d (%x)  previous size %d (%x)\n", cchPageToWrite, cchPageToWrite, paMap[iPage].o32_pagesize, paMap[iPage].o32_pagesize);
     804                if (cchPageToWrite < 0)
     805                    return kError::NOT_SUPPORTED;
     806                #if 0
     807                int cbLeft = KMIN(2, paMap[iPage].o32_pagesize - cchPageToWrite);
     808                if (cbLeft > 0)
     809{
     810                   memset(&pchCompressedPage[cchPageToWrite], 0, cbLeft);
     811                   cchPageToWrite += cbLeft;
     812                }
     813                #else
     814                kASSERT(paMap[iPage].o32_pagesize - cchPageToWrite >= 0);
     815                memset(&pchCompressedPage[cchPageToWrite], 0, paMap[iPage].o32_pagesize - cchPageToWrite);
     816                cchPageToWrite = paMap[iPage].o32_pagesize;
     817                #endif
     818                pchPageToWrite = pchCompressedPage;
     819                break;
     820}
     821
     822            case ZEROED:
     823{
     824                /*
     825                 * If the passed in page is not a zero page we'll fail.
     826                 */
     827                for (unsigned long * pul = (unsigned long *)pachPage; (char*)pul < &pachPage[0x1000]; pul++)
     828                    if (*pul)
     829                        return kError::NOT_SUPPORTED;
     830                return 0;
     831            }
     832
     833            case INVALID:
     834                return kError::INVALID_PAGE;
     835
     836            case RANGE:
     837            default:
     838                return kError::BAD_EXE_FORMAT;
     839        }
     840
     841        /*
     842         * Write stuff to file.
     843         */
     844        pFile->setFailOnErrors();
     845        return pFile->writeAt((void*)pchPageToWrite, cchPageToWrite, offPageToWrite);
     846    }
     847    else
     848    {   /*
     849         * No, it's a zerofilled page
     850         * If the passed in page is not a zero page we'll fail.
     851         */
     852        for (unsigned long *  pul = (unsigned long *)pachPage; (char*)pul < &pachPage[0x1000]; pul++)
     853             if (*pul)
     854                 return kError::NOT_SUPPORTED;
     855}
     856
     857    return 0;
     858}
     859
     860
     861/**
     862 * Get pagesize for the file.
     863 * @returns Pagesize in bytes.
     864 */
     865int kFileLX::pageGetPageSize() const
     866{
     867    return pe32->e32_pagesize;
    565868}
    566869
     
    569872 * Expands a page compressed with the old exepack method introduced with OS/2 2.0.
    570873 * (/EXEPACK or just /EXEPACK)
    571  * @returns Successindicator.
    572  * @param   pachPage        Pointer to output page. size: PAGESIZE
     874 * @returns 0 on success. kError error code on error.
     875 * @param   pachPage        Pointer to output page. size: cchPage
    573876 *                          Upon successful return this will contain the expanded page data.
     877 * @param   cchPage         Page size.
    574878 * @param   pachSrcPage     Pointer to source data. size: cchSrcPage.
    575879 *                          This data should be compressed with EXEPACK:2!
     880 * @param   cchSrcPage      Size of compressed data.
    576881 * @sketch  Have no good idea right now.
    577882 * @status  Completely implemented.
     
    579884 * @remark
    580885 */
    581 BOOL kFileLX::expandPage1(char *pachPage, const char * pachSrcPage, int cchSrcPage)
     886int kFileLX::expandPage1(char *pachPage, int cchPage, const char * pachSrcPage, int cchSrcPage)
    582887{
    583888    struct LX_Iter *pIter = (struct LX_Iter *)pachSrcPage;
     
    585890
    586891    /* Validate size of data. */
    587     if (cchSrcPage >= PAGESIZE - 2)
    588         return FALSE;
     892    if (cchSrcPage >= cchPage - 2)
     893        return kError::BAD_ITERPAGE;
    589894
    590895    /*
    591896     * Expand the page.
    592897     */
    593     while (pIter->LX_nIter)
     898    while (pIter->LX_nIter && cchSrcPage > 0)
    594899    {
    595900        /* Check if we're out of bound. */
    596         if (    pachPage - pachDesPage + pIter->LX_nIter * pIter->LX_nBytes > PAGESIZE
     901        if (    pachPage - pachDestPage + pIter->LX_nIter * pIter->LX_nBytes > cchPage
    597902            ||  cchSrcPage <= 0)
    598             return FALSE;
     903            return kError::BAD_ITERPAGE;
     904
     905        //if (pIter->LX_nIter == 1)
     906        //    printf("get 0x%03x  stored  %3d bytes\n", pachPage - pachDestPage, pIter->LX_nBytes);
     907        //else
     908        //    printf("get 0x%03x   %3d iterations  %3d bytes\n", pachPage - pachDestPage, pIter->LX_nIter, pIter->LX_nBytes);
    599909
    600910        if (pIter->LX_nBytes == 1)
    601911        {   /* one databyte */
    602             memset(pachPage, &pIter->LX_Iterdata, pIter->LX_nIter);
    603             pchPage += pIter->LX_nIter;
    604             cchSrcPage -= pIter->LX_nIter + 4;
     912            memset(pachPage, pIter->LX_Iterdata, pIter->LX_nIter);
     913            pachPage += pIter->LX_nIter;
     914            cchSrcPage -= 4 + 1;
    605915            pIter++;
    606916        }
    607917        else
    608918        {
    609             for (int i = 0; i < pIter->LX_nIter; i++, pachPage += pIter->LX_nBytes)
     919            for (int i = pIter->LX_nIter; i > 0; i--, pachPage += pIter->LX_nBytes)
    610920                memcpy(pachPage, &pIter->LX_Iterdata, pIter->LX_nBytes);
    611921            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 }
     922            pIter   = (struct LX_Iter *)((char*)pIter + 4 + pIter->LX_nBytes);
     923        }
     924        }
     925
     926    /*
     927     * Zero remaining part of the page.
     928     */
     929    if (pachPage - pachDestPage < cchPage)
     930        memset(pachPage, 0, cchPage - (pachPage - pachDestPage));
     931
     932    return 0;
     933    }
    661934
    662935
     
    664937 * Expands a page compressed with the exepack method introduced with OS/2 Warp 3.0.
    665938 * (/EXEPACK:2)
    666  * @returns Successindicator.
     939 * @returns 0 on success. kError error code on error.
    667940 * @param   pachPage        Pointer to output page. size: PAGESIZE
    668941 *                          Upon successful return this will contain the expanded page data.
     942 * @param   cchPage         Page size.
    669943 * @param   pachSrcPage     Pointer to source data. size: cchSrcPage.
    670944 *                          This data should be compressed with EXEPACK:2!
     945 * @param   cchSrcPage      Size of compressed data.
    671946 * @sketch  Have no good idea right now.
    672  * @status  Stub.
     947 * @status  Completely implemented and tested.
    673948 * @author  knut st. osmundsen (knut.stange.osmundsen@mynd.no)
     949 * @remark  tested.
     950 */
     951int kFileLX::expandPage2(char *pachPage, int cchPage, const char * pachSrcPage, int cchSrcPage)
     952{
     953    char *          pachDestPage = pachPage; /* Store the pointer for boundrary checking. */
     954
     955    while (cchSrcPage > 0)
     956    {
     957        /*
     958         * Bit 0 and 1 is the encoding type.
     959         */
     960        switch (*pachSrcPage & 0x03)
     961        {
     962            /*
     963             *
     964             *  0  1  2  3  4  5  6  7
     965             *  type  |              |
     966             *        ----------------
     967             *             cch        <cch bytes of data>
     968             *
     969             * Bits 2-7 is, if not zero, the length of an uncompressed run
     970             *   starting at the following byte.
     971             *
     972             *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
     973             *  type  |              |  |                    | |                     |
     974             *        ----------------  ---------------------- -----------------------
     975             *             zero                 cch                char to multiply
     976             *
     977             * If the bits are zero, the following two bytes describes a
     978             *   1 byte interation run. First byte is count, second is the byte to copy.
     979             *   A count of zero is means end of data, and we simply stops. In that case
     980             *   the rest of the data should be zero.
     981             */
     982            case 0:
     983            {
     984                if (*pachSrcPage)
     985                {
     986                    int cch = *pachSrcPage >> 2;
     987                    if (cchPage  < cch || cchSrcPage < cch + 1)
     988                        return kError::BAD_COMPESSED_PAGE;
     989                    memcpy(pachPage, pachSrcPage+1, cch);
     990                    pachPage += cch, cchPage -= cch;
     991                    pachSrcPage += cch + 1, cchSrcPage -= cch + 1;
     992                    break;
     993                }
     994                if (cchSrcPage < 2)
     995                    return kError::BAD_COMPESSED_PAGE;
     996                int cch = pachSrcPage[1];
     997                if (cch)
     998    {
     999                    if (cchSrcPage < 3 || cchPage < cch)
     1000                        return kError::BAD_COMPESSED_PAGE;
     1001                    memset(pachPage, pachSrcPage[2], cch);
     1002                    pachPage += cch, cchPage -= cch;
     1003                    pachSrcPage += 3, cchSrcPage -= 3;
     1004                    break;
     1005                }
     1006                goto endloop;
     1007    }
     1008
     1009
     1010            /*
     1011             *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
     1012             *  type  |  |  |     |  |                       |
     1013             *        ----  -------  -------------------------
     1014             *        cch1  cch2 - 3          offset            <cch1 bytes of data>
     1015             *
     1016             *  Two bytes layed out as described above, followed by cch1 bytes of data to be copied.
     1017             *  The cch2(+3) and offset describes an amount of data to be copied from the expanded
     1018             *    data relative to the current position. The data copied as you would expect it to be.
     1019             */
     1020            case 1:
     1021    {
     1022                if (cchSrcPage < 2)
     1023                    return kError::BAD_COMPESSED_PAGE;
     1024                int off = *(unsigned short*)pachSrcPage >> 7;
     1025                int cch1 = *pachSrcPage >> 2 & 3;
     1026                int cch2 = (*pachSrcPage >> 4 & 7) + 3;
     1027                pachSrcPage += 2, cchSrcPage -= 2;
     1028                if (cchSrcPage < cch1 || cchPage < cch1 + cch2 || pachPage + cch1 - off < pachDestPage)
     1029                    return kError::BAD_COMPESSED_PAGE;
     1030                memcpy(pachPage, pachSrcPage, cch1);
     1031                pachPage += cch1, cchPage -= cch1;
     1032                pachSrcPage += cch1, cchSrcPage -= cch1;
     1033                memcpyb(pachPage, pachPage - off, cch2); //memmove doesn't do a good job here for some stupid reason.
     1034                pachPage += cch2, cchPage -= cch2;
     1035                break;
     1036            }
     1037
     1038
     1039            /*
     1040             *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
     1041             *  type  |  |  |                                |
     1042             *        ----  ----------------------------------
     1043             *       cch-3              offset
     1044             *
     1045             *  Two bytes layed out as described above.
     1046             *  The cch(+3) and offset describes an amount of data to be copied from the expanded
     1047             *  data relative to the current position.
     1048             *
     1049             *  If offset == 1 the data is not copied as expected, but in the memcpyw manner.
     1050             */
     1051            case 2:
     1052        {
     1053                if (cchSrcPage < 2)
     1054                    return kError::BAD_COMPESSED_PAGE;
     1055                int off = *(unsigned short*)pachSrcPage >> 4;
     1056                int cch = (*pachSrcPage >> 2 & 3) + 3;
     1057                pachSrcPage += 2, cchSrcPage -= 2;
     1058                if (cchPage < cch || pachPage - off < pachDestPage)
     1059                    return kError::BAD_COMPESSED_PAGE;
     1060                memcpyw(pachPage, pachPage - off, cch);
     1061                pachPage += cch, cchPage -= cch;
     1062                break;
     1063        }
     1064
     1065
     1066            /*
     1067             *  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
     1068             *  type  |        |  |              |  |                                |
     1069             *        ----------  ----------------  ----------------------------------
     1070             *           cch1           cch2                     offset                <cch1 bytes of data>
     1071             *
     1072             *  Three bytes layed out as described above, followed by cch1 bytes of data to be copied.
     1073             *  The cch2 and offset describes an amount of data to be copied from the expanded
     1074             *  data relative to the current position.
     1075             *
     1076             *  If offset == 1 the data is not copied as expected, but in the memcpyw manner.
     1077             */
     1078            case 3:
     1079        {
     1080                if (cchSrcPage < 3)
     1081                    return kError::BAD_COMPESSED_PAGE;
     1082                int cch1 = *pachSrcPage >> 2 & 0x000f;
     1083                int cch2 = *(unsigned short*)pachSrcPage >> 6 & 0x003f;
     1084                int off  = *(unsigned short*)(pachSrcPage+1) >> 4;
     1085                pachSrcPage += 3, cchSrcPage -= 3;
     1086                if (cchSrcPage < cch1 || cchPage < cch1 + cch2 || pachPage - off + cch1 < pachDestPage)
     1087                    return kError::BAD_COMPESSED_PAGE;
     1088                memcpy(pachPage, pachSrcPage, cch1);
     1089                pachPage += cch1, cchPage -= cch1;
     1090                pachSrcPage += cch1, cchSrcPage -= cch1;
     1091                memcpyw(pachPage, pachPage - off, cch2);
     1092                pachPage += cch2, cchPage -= cch2;
     1093                break;
     1094            }
     1095        }
     1096        }
     1097
     1098endloop:;
     1099
     1100
     1101    /*
     1102     * Zero the rest of the page.
     1103     */
     1104    if (cchPage > 0)
     1105        memset(pachPage, 0, cchPage);
     1106
     1107    return 0;
     1108        }
     1109
     1110
     1111/**
     1112 * This is a special memcpy for expandPage2 which performs a word based copy.
     1113 * The difference between this, memmove and memcpy is that we'll allways read words.
     1114 * @param   pch1    Target pointer.
     1115 * @param   pch2    Source pointer.
     1116 * @param   cch     size of memory block to copy from pch2 to pch1.
     1117 * @author  knut st. osmundsen (kosmunds@csc.com)
    6741118 * @remark
    6751119 */
    676 BOOL kFileLX::expandPage2(char *pachPage, const char * pachSrcPage, int cchSrcPage)
    677 {
    678     NOREF(pachPage);
    679     NOREF(pachSrcPage);
    680     NOREF(cchSrcPage);
    681     return FALSE;
    682 }
     1120inline void memcpyw(char *pch1, const char *pch2, size_t cch)
     1121{
     1122    /*
     1123     * Use memcpy if possible.
     1124     */
     1125    if ((pch2 > pch1 ? pch2 - pch1 : pch1 - pch2) >= 4)
     1126    {
     1127        memcpy(pch1, pch2, cch);        /* BUGBUG! ASSUMES that memcpy move NO more than 4 bytes at the time! */
     1128        return;
     1129    }
     1130
     1131    /*
     1132     * Difference is less than 3 bytes.
     1133     */
     1134    if (cch & 1)
     1135        *pch1++ = *pch2++;
     1136
     1137    #if 0 //haven't found anyone yet. (not a big surprize!)
     1138    /* Looking for a very special case! I wanna see if my theory is right. */
     1139    if ((pch2 > pch1 ? pch2 - pch1 : pch1 - pch2) <= 1)
     1140        INT3();
     1141#endif
     1142
     1143    for (cch >>= 1; cch > 0; cch--, pch1 += 2, pch2 += 2)
     1144        *(unsigned short *)pch1 = *(unsigned short *)pch2;
     1145}
     1146
     1147
     1148/**
     1149 * This is a special memcpy for expandPage2 which performs a memmove operation.
     1150 * The difference between this and memmove is that this one works.
     1151 *
     1152 * @param   pch1    Target pointer.
     1153 * @param   pch2    Source pointer.
     1154 * @param   cch     size of memory block to copy from pch2 to pch1.
     1155 * @author  knut st. osmundsen (kosmunds@csc.com)
     1156 */
     1157inline void memcpyb(char *pch1, const char *pch2, size_t cch)
     1158{
     1159    /*
     1160     * Use memcpy if possible.
     1161 */
     1162    if ((pch2 > pch1 ? pch2 - pch1 : pch1 - pch2) >= 4)
     1163{
     1164        memcpy(pch1, pch2, cch);        /* BUGBUG! ASSUMES that memcpy move NO more than 4 bytes at the time! */
     1165        return;
     1166    }
     1167
     1168    /*
     1169     * Difference is less than 3 bytes.
     1170     */
     1171    while(cch--)
     1172        *pch1++ = *pch2++;
     1173}
     1174
    6831175
    6841176
     
    6891181 *          PAGESIZE if failed to compress the page.
    6901182 *          -1 on error.
    691  * @param   pachPage        Pointer to output buffer. size: PAGESIZE.
     1183 * @param   pachPage        Pointer to output buffer. size: cchSrcPage.
    6921184 *                          This will hold the compressed page data upon return.
    693  * @param   pachSrcPage     Pointer to page to compress. size: PAGESIZE.
     1185 * @param   pachSrcPage     Pointer to page to compress. size: cchSrcPage.
     1186 * @param   cchSrcPage      Page size.
    6941187 * @sketch
    6951188 * @status  stub.
     
    6971190 * @remark  Not implemented.
    6981191 */
    699 int kFileLX::compressPage1(char *pachPage, const char * pachSrcPage)
    700 {
    701     NOREF(pachPage);
    702     NOREF(pachSrcPage);
     1192
     1193int compressPage1Search(const char *pch, const char **ppchSearch, const char *pchEnd, int *pcIterations)
     1194{
     1195    int         cch;
     1196    const char* pchStart = pch;
     1197    const char* pchSearch = *ppchSearch;
     1198
     1199//    if (pch < pchSearch)
     1200//        pch = pchSearch - 1;
     1201    while ((cch = pchSearch - pch) > 0)
     1202{
     1203        int cchLeft = pchEnd - pchSearch;
     1204        if (cchLeft < cch)
     1205            {pch++; continue;}
     1206        int cIter = 1;
     1207        const char *pchMatch = pchSearch;
     1208        while (pchMatch < pchEnd && !memcmp(pchMatch, pch, cch))
     1209            pchMatch += cch, cIter++;
     1210
     1211        int cchCost = pchStart < pch ? cch + 8 : cch + 4;
     1212        if (cIter == 1 || cIter * cch < cchCost)
     1213            {pch++; continue;}
     1214        *ppchSearch = pch;
     1215        *pcIterations = cIter;
     1216        return cch;
     1217    }
     1218
    7031219    return -1;
    7041220}
     1221
     1222int compressPage1SearchStored(const char *pchStart, const char *pchEnd, int *pcchRun)
     1223{
     1224    if (pchStart+1 == pchEnd)
     1225        return FALSE;
     1226
     1227    const char *pch = pchStart;
     1228    char ch = *pch++;
     1229    while (pch < pchEnd)
     1230        if (*pch++ != ch)
     1231            break;
     1232
     1233    if (pch == pchEnd)
     1234    {
     1235        *pcchRun = 1;
     1236        return TRUE;
     1237    }
     1238
     1239    int cch = pchEnd - pchStart;
     1240    if (cch < 4 && cch % 2 != 0)
     1241        return FALSE;
     1242
     1243    unsigned short* pus = (unsigned short*)pchStart;
     1244    unsigned short  us = *pus++;
     1245    while ((const char*)pus < pchEnd)
     1246        if (*pus++ != us)
     1247            return 0;
     1248
     1249    *pcchRun = 2;
     1250    return TRUE;
     1251}
     1252
     1253
     1254int kFileLX::compressPage1(char *pachPage, const char * pachSrcPage, int cchSrcPage)
     1255{
     1256    union
     1257    {
     1258        char           *  pch;
     1259        unsigned short *  push;
     1260        struct LX_Iter *  pIter;
     1261    } Dst;
     1262    Dst.pch = pachPage;
     1263    const char *pch = pachSrcPage;
     1264    const char *pchSearch = pch;
     1265    const char *pchEnd = pch + cchSrcPage;
     1266    while (pchSearch < pchEnd)
     1267    {
     1268        int cIterations;
     1269        int cchPattern = compressPage1Search(pch, &pchSearch, pchEnd, &cIterations);
     1270        if (cchPattern > 0)
     1271        {   /* Found pattern. */
     1272            /* make uncompressed chunk. */
     1273            if (pch < pchSearch)
     1274            {
     1275                int cchRun;
     1276                int cch = pchSearch - pch;
     1277                if (cch < 9 && cch > 1 && compressPage1SearchStored(pch, pchSearch, &cchRun))
     1278                {
     1279                    /* make compressed chunk. */
     1280                    Dst.pIter->LX_nIter = cch / cchRun;
     1281                    Dst.pIter->LX_nBytes = cchRun;
     1282                    memcpy(&Dst.pIter->LX_Iterdata, pch, cchPattern);
     1283                    //printf("put 0x%03x   %3d iterations  %3d bytes\n", pch - pachSrcPage, Dst.pIter->LX_nIter, Dst.pIter->LX_nBytes);
     1284                    Dst.pch += cchRun + 4;
     1285                }
     1286                else
     1287                {   /* make uncompressed chunk */
     1288                    Dst.pIter->LX_nIter = 1;
     1289                    Dst.pIter->LX_nBytes = cch;
     1290                    memcpy(&Dst.pIter->LX_Iterdata, pch, cch);
     1291                    //printf("put 0x%03x  stored  %3d bytes\n", pch - pachSrcPage, Dst.pIter->LX_nBytes);
     1292                    Dst.pch += cch + 4;
     1293                }
     1294                pch += cch;
     1295            }
     1296
     1297            /* make compressed chunk. */
     1298            Dst.pIter->LX_nIter = cIterations;
     1299            Dst.pIter->LX_nBytes = cchPattern;
     1300            memcpy(&Dst.pIter->LX_Iterdata, pch, cchPattern);
     1301            //printf("put 0x%03x   %3d iterations  %3d bytes\n", pch - pachSrcPage, Dst.pIter->LX_nIter, Dst.pIter->LX_nBytes);
     1302            Dst.pch += cchPattern + 4;
     1303            pchSearch = pch += cchPattern * cIterations;
     1304        }
     1305        else
     1306        {   /* No pattern - got the next byte in the source page. */
     1307            pchSearch++;
     1308        }
     1309    }
     1310
     1311    /* make final uncompressed chunk(s) */
     1312    if (pch < pchSearch)
     1313    {
     1314        int cch = pchSearch - pch;
     1315        Dst.pIter->LX_nIter = 1;
     1316        Dst.pIter->LX_nBytes = cch;
     1317        memcpy(&Dst.pIter->LX_Iterdata, pch, cch);
     1318        //printf("put 0x%03x  stored  %3d bytes %d\n", pch - pachSrcPage, Dst.pIter->LX_nBytes, cch);
     1319        Dst.pch += cch + 4;
     1320        pch += cch;
     1321    }
     1322
     1323
     1324
     1325    /* write terminating word - this is really not needed AFAIK, but it makes debugging easier. */
     1326    //*Dst.push++ = 0;
     1327    return Dst.pch - pachPage;
     1328}
     1329
    7051330
    7061331
     
    7111336 *          PAGESIZE if failed to compress the page.
    7121337 *          -1 on error.
    713  * @param   pachPage        Pointer to output buffer. size: PAGESIZE.
     1338 * @param   pachPage        Pointer to output buffer. size: cchSrcPage.
    7141339 *                          This will hold the compressed page data upon return.
    715  * @param   pachSrcPage     Pointer to page to compress. size: PAGESIZE.
     1340 * @param   pachSrcPage     Pointer to page to compress. size: cchSrcPage.
     1341 * @param   cchSrcPage      Page size.
    7161342 * @sketch  Have no idea!
    7171343 * @status  stub.
     
    7191345 * @remark  Not implemented.
    7201346 */
    721 int kFileLX::compressPage2(char *pachPage, const char * pachSrcPage)
    722 {
    723     NOREF(pachPage);
    724     NOREF(pachSrcPage);
     1347int kFileLX::compressPage2(char *pachPage, const char * pachSrcPage, int cchSrcPage)
     1348{
     1349    KNOREF(pachPage);
     1350    KNOREF(pachSrcPage);
     1351    KNOREF(cchSrcPage);
    7251352    return -1;
    7261353}
    7271354
    728 #endif
     1355
     1356/**
     1357 * Start a relocation enumeration.
     1358 * @returns TRUE:   Found relocation.
     1359 *          FALSE:  No more relocations.
     1360 * @param   ulSegment   Segment number. Special selector may be specified.
     1361 * @param   offSegment  Offset into the segment described by ulSegment.
     1362 * @param   preloc      Pointer to a relocation 'handle' structure.
     1363 *                      This is used for communicating the relocations in
     1364 *                      a generic format and for keeping track of the current position.
     1365 *                      Please, DO NOT change any members of this structure.
     1366 */
     1367KBOOL kFileLX::relocFindFirst(unsigned long ulSegment, unsigned long offSegment, kRelocEntry *preloc)
     1368{
     1369    if (ulSegment >= kRelocEntry::enmFirstSelector)
     1370        offSegment = lxSpecialSelectorToObjectOffset(offSegment, &ulSegment);
     1371
     1372    if (    lxValidateObjectOffset(ulSegment, offSegment)
     1373        &&  pe32->e32_frectab != 0
     1374        &&  pe32->e32_fpagetab != 0
     1375        )
     1376    {
     1377        PLXRELOCSTATE  pState = new LXRELOCSTATE;
     1378        pState->ulSegment = ulSegment;
     1379        pState->ulPage = paObject[ulSegment].o32_pagemap - 1;
     1380        pState->pchFixupRec = pchFixupRecs + paulFixupPageTable[pState->ulPage];
     1381        pState->usSrcOffIdx = 0;
     1382        preloc->pv1 = (void*)pState;
     1383        preloc->fFlags = 0;
     1384        preloc->Info.Name.pszModule = NULL;
     1385        preloc->Info.Name.pszName = NULL;
     1386        return relocFindNext(preloc);
     1387}
     1388
     1389    return FALSE;
     1390}
     1391
     1392
     1393/**
     1394 * Start a relocation enumeration.
     1395 * @returns TRUE:   Found relocation.
     1396 *          FALSE:  No more relocations.
     1397 * @param   ulAddress   Address to start from.
     1398 * @param   preloc      Pointer to a relocation 'handle' structure.
     1399 *                      This is used for communicating the relocations in
     1400 *                      a generic format and for keeping track of the current position.
     1401 *                      Please, DO NOT change any members of this structure.
     1402 */
     1403KBOOL kFileLX::relocFindFirst(unsigned long ulAddress, kRelocEntry *preloc)
     1404{
     1405    return relocFindFirst(kRelocEntry::enmVASelector, ulAddress, preloc);
     1406}
     1407
     1408
     1409/**
     1410 * Get the next relocation.
     1411 * @returns TRUE:   Found relocation.
     1412 *          FALSE:  No more relocations.
     1413 * @param   preloc  Pointer to a relocation 'handle' structure.
     1414 * @remark  preloc have to be opened by relocFindFirst before calling relocFindNext!
     1415 */
     1416KBOOL kFileLX::relocFindNext(kRelocEntry *preloc)
     1417{
     1418    PLXRELOCSTATE   pState = (PLXRELOCSTATE)preloc->pv1;
     1419    int             iObj = pState->ulSegment;
     1420    KBOOL           fFound = FALSE;
     1421
     1422    while (iObj < pe32->e32_objcnt)
     1423    {
     1424        int iPage = pState->ulPage;
     1425
     1426        while (iPage < paObject[iObj].o32_mapsize + paObject[iObj].o32_pagemap - 1)
     1427        {
     1428            char *  pchFixupRecEnd = pchFixupRecs + paulFixupPageTable[iPage + 1];
     1429
     1430            while (pState->pchFixupRec < pchFixupRecEnd)
     1431            {
     1432                char *  pch;            /* Fixup record walker. */
     1433                union _rel
     1434                {
     1435                    unsigned long   ul;
     1436                    char *          pch;
     1437                    struct r32_rlc *prlc;
     1438                } rel;                  /* Fixup record */
     1439
     1440                /*
     1441                 * If we're completed here we'll simply return.
     1442                 */
     1443                if (fFound)
     1444                    return TRUE;
     1445
     1446
     1447                /*
     1448                 * Do some init and cleanup.
     1449                 */
     1450                rel.pch = pState->pchFixupRec;
     1451                if (preloc->isName())
     1452                {
     1453                    delete (void*)preloc->Info.Name.pszModule;
     1454                    delete (void*)preloc->Info.Name.pszName;
     1455                    preloc->Info.Name.pszName = preloc->Info.Name.pszModule = NULL;
     1456                }
     1457
     1458
     1459                /*
     1460                 * We've got a problem! chained relocation records!
     1461                 */
     1462                switch (rel.prlc->nr_stype & NRSTYP)
     1463                {
     1464                    case NRSBYT:    preloc->fFlags = kRelocEntry::enm8      | kRelocEntry::enmOffset; break;
     1465                    case NRSSEG:    preloc->fFlags = kRelocEntry::enm16_00  | kRelocEntry::enmOffset; break;
     1466                    case NRSPTR:    preloc->fFlags = kRelocEntry::enm16_16  | kRelocEntry::enmOffset; break;
     1467                    case NRSOFF:    preloc->fFlags = kRelocEntry::enm16     | kRelocEntry::enmOffset; break;
     1468                    case NRPTR48:   preloc->fFlags = kRelocEntry::enm16_32  | kRelocEntry::enmOffset; break;
     1469                    case NROFF32:   preloc->fFlags = kRelocEntry::enm32     | kRelocEntry::enmOffset; break;
     1470                    case NRSOFF32:  preloc->fFlags = kRelocEntry::enm32     | kRelocEntry::enmRelEnd; break;
     1471                    default:
     1472                        kASSERT(FALSE);
     1473                        return FALSE;
     1474                }
     1475
     1476                /* Set endian flag. */
     1477                if (pe32->e32_border == E32LEBO && pe32->e32_border == E32LEWO)
     1478                    preloc->fFlags |= kRelocEntry::enmLittleEndian;
     1479                else if (pe32->e32_border == E32BEBO && pe32->e32_border == E32BEWO)
     1480                    preloc->fFlags |= kRelocEntry::enmBigEndian;
     1481                else
     1482                {
     1483                    kASSERT(FALSE);
     1484                    return FALSE;
     1485                }
     1486
     1487
     1488                /*
     1489                 * LX target type.
     1490                 */
     1491                pch = rel.pch + 3 + (rel.prlc->nr_stype & NRCHAIN ? 0 : 1); /* place pch at the 4th member. */
     1492                switch (rel.prlc->nr_flags & NRRTYP)
     1493                {
     1494                    case NRRINT:
     1495                        preloc->fFlags |= kRelocEntry::enmInternal;
     1496                        if (rel.prlc->nr_flags & NR16OBJMOD)
     1497                        {
     1498                            preloc->Info.Internal.ulSegment = *(unsigned short *)pch - 1;
     1499                            pch += 2;
     1500                        }
     1501                        else
     1502                        {
     1503                            preloc->Info.Internal.ulSegment = *(unsigned char *)pch - 1;
     1504                            pch += 1;
     1505                        }
     1506                        if (rel.prlc->nr_flags & NR32BITOFF)
     1507                        {
     1508                            preloc->Info.Internal.offSegment = *(unsigned long *)pch;
     1509                            pch += 4;
     1510                        }
     1511                        else
     1512                        {
     1513                            preloc->Info.Internal.offSegment = *(unsigned short *)pch;
     1514                            pch += 2;
     1515                        }
     1516                        break;
     1517
     1518                    case NRRORD:
     1519                        preloc->fFlags |= kRelocEntry::enmOrdDLL;
     1520                        if (rel.prlc->nr_flags & NR16OBJMOD)
     1521                        {
     1522                            preloc->Info.Name.pszModule = lxGetImportModuleName(*(unsigned short *)pch);
     1523                            pch += 2;
     1524                        }
     1525                        else
     1526                        {
     1527                            preloc->Info.Name.pszModule = lxGetImportModuleName(*(unsigned char *)pch);
     1528                            pch += 1;
     1529                        }
     1530                        if (rel.prlc->nr_flags & NR32BITOFF)
     1531                        {
     1532                            sprintf(preloc->Info.Name.pszName = new char[16], "#%lu", *(unsigned long *)pch);
     1533                            preloc->Info.Name.ulOrdinal = (unsigned)*(unsigned long *)pch;
     1534                            pch += 4;
     1535                        }
     1536                        else if (rel.prlc->nr_flags & NR8BITORD)
     1537                        {
     1538                            sprintf(preloc->Info.Name.pszName = new char[8], "#%u", (unsigned)*(unsigned char *)pch);
     1539                            preloc->Info.Name.ulOrdinal = (unsigned)*(unsigned char *)pch;
     1540                            pch += 1;
     1541                        }
     1542                        else
     1543                        {
     1544                            sprintf(preloc->Info.Name.pszName = new char[12], "#%u", (unsigned)*(unsigned short *)pch);
     1545                            preloc->Info.Name.ulOrdinal = (unsigned)*(unsigned short *)pch;
     1546                            pch += 2;
     1547                        }
     1548                        break;
     1549
     1550                    case NRRNAM:
     1551                        preloc->fFlags |= kRelocEntry::enmNameDLL;
     1552                        if (rel.prlc->nr_flags & NR16OBJMOD)
     1553                        {
     1554                            preloc->Info.Name.pszModule = lxGetImportModuleName(*(unsigned short *)pch);
     1555                            pch += 2;
     1556                        }
     1557                        else
     1558                        {
     1559                            preloc->Info.Name.pszModule = lxGetImportModuleName(*(unsigned char *)pch);
     1560                            pch += 1;
     1561                        }
     1562                        preloc->Info.Name.ulOrdinal = ~0UL;;
     1563                        if (rel.prlc->nr_flags & NR32BITOFF)
     1564                        {
     1565                            preloc->Info.Name.pszName = lxGetImportProcName(*(unsigned long *)pch);
     1566                            pch += 4;
     1567                        }
     1568                        else
     1569                        {
     1570                            preloc->Info.Name.pszName = lxGetImportProcName(*(unsigned short *)pch);
     1571                            pch += 2;
     1572                        }
     1573                        break;
     1574
     1575                    case NRRENT:
     1576                        preloc->fFlags |= kRelocEntry::enmInternal;
     1577                        kASSERT(!"Not Implemented");
     1578                        return FALSE;
     1579                }
     1580
     1581                /* addiative fixup? */
     1582                if (rel.prlc->nr_flags & NRADD)
     1583                {
     1584                    preloc->fFlags |= kRelocEntry::enmAdditive;
     1585                    if (rel.prlc->nr_flags & NR32BITADD)
     1586                    {
     1587                        preloc->ulAdd = *(unsigned long *)pch;
     1588                        pch += 4;
     1589                    }
     1590                    else
     1591                    {
     1592                        preloc->ulAdd = *(unsigned short *)pch;
     1593                        pch += 2;
     1594                    }
     1595                }
     1596
     1597                /*
     1598                 * obj:offset of the fixup
     1599                 * If the offset is negative we'll skip it (ie. not set the found flag).
     1600                 */
     1601                preloc->ulSegment = iObj;
     1602                preloc->offSegment = (iPage - paObject[iObj].o32_pagemap + 1) * pe32->e32_pagesize;
     1603                if (rel.prlc->nr_stype & NRCHAIN)
     1604                {
     1605                    while (pState->usSrcOffIdx < (unsigned char)rel.prlc->r32_soff)
     1606                    {
     1607                        if (!(((unsigned short *)pch)[pState->usSrcOffIdx] & 0x8000))
     1608                        {
     1609                            preloc->offSegment += ((unsigned short*)pch)[pState->usSrcOffIdx];
     1610                            fFound = TRUE;
     1611                            break;
     1612                        }
     1613                        pState->usSrcOffIdx++;
     1614                    }
     1615                }
     1616                else
     1617                {
     1618                    preloc->offSegment += rel.prlc->r32_soff;
     1619                    if (!(rel.prlc->r32_soff & 0x8000))
     1620                        fFound = TRUE;
     1621                }
     1622
     1623
     1624                /*
     1625                 * Go to the next relocation.
     1626                 */
     1627                if (rel.prlc->nr_stype & NRCHAIN)
     1628                {
     1629                    if (++pState->usSrcOffIdx >= (unsigned char)rel.prlc->r32_soff)
     1630                    {
     1631                        pState->pchFixupRec = pState->pchFixupRec + (KSIZE)pch - rel.ul + ((unsigned char)rel.prlc->r32_soff) * 2;
     1632                        pState->usSrcOffIdx = 0;
     1633                    }
     1634                }
     1635                else
     1636                    pState->pchFixupRec = pState->pchFixupRec + (KSIZE)pch - rel.ul;
     1637            }
     1638
     1639
     1640            /* next page */
     1641            pState->ulPage = ++iPage;
     1642            pState->pchFixupRec = pchFixupRecEnd;
     1643            pState->usSrcOffIdx = 0;            /* Source Offset Index */
     1644        }
     1645
     1646
     1647        /* next object */
     1648        pState->ulSegment = ++iObj;
     1649        if (iObj >= pe32->e32_objcnt)
     1650            break;
     1651        pState->ulPage = paObject[iObj].o32_pagemap - 1;
     1652        pState->pchFixupRec = pchFixupRecs + paulFixupPageTable[pState->ulPage];
     1653        pState->usSrcOffIdx = 0;                /* Source Offset Index */
     1654    }
     1655
     1656    return fFound;
     1657}
     1658
     1659
     1660/**
     1661 * Closes a relocatation search/enumeration.
     1662 * Will free any internally allocated resources.
     1663 *
     1664 * @param   preloc  The enumeration 'handel'.
     1665 * @remark  This function *must* be called to close a search/enumeration.
     1666 */
     1667void kFileLX::relocFindClose(kRelocEntry *preloc)
     1668{
     1669    /* free name storage */
     1670    if (preloc->isName())
     1671    {
     1672        delete (void*)preloc->Info.Name.pszModule;
     1673        delete (void*)preloc->Info.Name.pszName;
     1674        preloc->Info.Name.pszName = preloc->Info.Name.pszModule = NULL;
     1675    }
     1676
     1677    /* free state info */
     1678    memset(preloc->pv1, 0xff, sizeof(LXRELOCSTATE));
     1679    delete preloc->pv1;
     1680    preloc->pv1 = (void*)0xdeadbeef;
     1681}
     1682
     1683
     1684
Note: See TracChangeset for help on using the changeset viewer.