Ignore:
Timestamp:
Jan 8, 2002, 7:29:57 PM (24 years ago)
Author:
umoeller
Message:

Executable updates, mostly.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/helpers/dosh2.c

    r127 r129  
    350350
    351351    return (arc);       // V0.9.9 (2001-04-04) [umoeller]
    352 }
    353 
    354 /*
    355  *@@category: Helpers\Control program helpers\Executable info
    356  *      these functions can retrieve BLDLEVEL information,
    357  *      imported modules information, exported functions information,
    358  *      and resources information from any executable module. See
    359  *      doshExecOpen.
    360  */
    361 
    362 /********************************************************************
    363  *
    364  *   Executable functions
    365  *
    366  ********************************************************************/
    367 
    368 /*
    369  *@@ doshExecOpen:
    370  *      this opens the specified executable file
    371  *      (which can be an .EXE, .COM, .DLL, or
    372  *      driver file) for use with the other
    373  *      doshExec* functions.
    374  *
    375  *      If no error occurs, NO_ERROR is returned
    376  *      and a pointer to a new EXECUTABLE structure
    377  *      is stored in *ppExec. Consider this pointer a
    378  *      handle and pass it to doshExecClose to clean
    379  *      up.
    380  *
    381  *      If NO_ERROR is returned, all the fields through
    382  *      ulOS are set in EXECUTABLE. The psz* fields
    383  *      which follow afterwards require an additional
    384  *      call to doshExecQueryBldLevel.
    385  *
    386  *      NOTE: If NO_ERROR is returned, the executable
    387  *      file has been opened by this function. It will
    388  *      only be closed when you call doshExecClose.
    389  *
    390  *      If errors occur, this function returns the
    391  *      following error codes:
    392  *
    393  *      -- ERROR_NOT_ENOUGH_MEMORY: malloc() failed.
    394  *
    395  *      -- ERROR_INVALID_EXE_SIGNATURE (191): header is
    396  *              neither plain DOS, nor NE, nor LX, nor PE.
    397  *              The given file probably isn't even an
    398  *              executable. This you will get if you
    399  *              pass in COM, BAT, or CMD files.
    400  *
    401  *      -- ERROR_BAD_EXE_FORMAT (193): header was
    402  *              recognized, but the header data was
    403  *              not understood.
    404  *
    405  *      -- ERROR_INVALID_PARAMETER: ppExec is NULL.
    406  *
    407  *      plus those of DosOpen, DosSetFilePtr, and
    408  *      DosRead.
    409  *
    410  *      The following executable types are supported
    411  *      (see EXECUTABLE for details):
    412  *
    413  *      --  Plain DOS 3.x executable without new header.
    414  *
    415  *      --  New Executable (NE), used by Win16 and
    416  *          16-bit OS/2 and still many of today's drivers.
    417  *
    418  *      --  Linear Executable (LX), OS/2 2.x and above.
    419  *
    420  *      --  Portable Executable (PE), used by Win32.
    421  *
    422  *      V0.9.12 adds support for NOSTUB executables,
    423  *      which are new-style executables (NE or LX)
    424  *      without a leading DOS header. The executable
    425  *      then starts directly with the NE or LX header.
    426  *      I am not sure whether PE supports such things
    427  *      as well... if so, it should be supported too.
    428  *
    429  *      @@todo:
    430  *
    431  *          win95 \WINDOWS\extract.exe is NE with a non-standard format
    432  *          win16 \WINDOWS\EXPAND.EXE
    433  *          win16 \WINDOWS\MSD.EXE"
    434  *
    435  *@@added V0.9.0 [umoeller]
    436  *@@changed V0.9.1 (2000-02-13) [umoeller]: fixed 32-bits flag
    437  *@@changed V0.9.7 (2000-12-20) [lafaix]: fixed ulNewHeaderOfs
    438  *@@changed V0.9.10 (2001-04-08) [lafaix]: added PE support
    439  *@@changed V0.9.10 (2001-04-08) [umoeller]: now setting ppExec only if NO_ERROR is returned
    440  *@@changed V0.9.12 (2001-05-03) [umoeller]: added support for NOSTUB newstyle executables
    441  *@@changed V0.9.16 (2001-12-08) [umoeller]: now using OPEN_SHARE_DENYWRITE
    442  *@@changed V0.9.16 (2001-12-08) [umoeller]: fLibrary was never set, works for LX and NE now
    443  *@@changed V0.9.16 (2001-12-08) [umoeller]: some speed optimizations, changed some return codes
    444  *@@changed V0.9.16 (2002-01-04) [umoeller]: added fixes for COM, BAT, CMD extensions
    445  */
    446 
    447 APIRET doshExecOpen(const char* pcszExecutable,
    448                     PEXECUTABLE* ppExec)
    449 {
    450     APIRET      arc = NO_ERROR;
    451 
    452     PEXECUTABLE pExec = NULL;
    453 
    454     PXFILE      pFile = NULL;
    455     ULONG       cbFile = 0;
    456     PCSZ        pExt;
    457     BOOL        fOpenFile = FALSE;
    458 
    459     if (!ppExec)
    460         return (ERROR_INVALID_PARAMETER);
    461 
    462     if (!(pExec = (PEXECUTABLE)malloc(sizeof(EXECUTABLE))))
    463         return (ERROR_NOT_ENOUGH_MEMORY);
    464 
    465     memset(pExec, 0, sizeof(EXECUTABLE));
    466 
    467     // check some of the default extensions
    468     // V0.9.16 (2002-01-04) [umoeller]
    469     if (pExt = doshGetExtension(pcszExecutable))
    470     {
    471         if (!stricmp(pExt, "COM"))
    472         {
    473             // I am not willing to find out more about the
    474             // .COM executable format, so for this one case,
    475             // let OS/2 determine what we have here
    476             ULONG ulDosAppType = 0;
    477             if (!(arc = DosQueryAppType((PSZ)pcszExecutable, &ulDosAppType)))
    478             {
    479                 if (ulDosAppType & FAPPTYP_DOS)           // 0x20
    480                     pExec->ulOS = EXEOS_DOS3;
    481                 else
    482                     pExec->ulOS = EXEOS_OS2;
    483 
    484                 pExec->ulExeFormat = EXEFORMAT_COM;
    485             }
    486         }
    487         else if (!stricmp(pExt, "BAT"))
    488         {
    489             pExec->ulOS = EXEOS_DOS3;
    490             pExec->ulExeFormat = EXEFORMAT_TEXT_BATCH;
    491         }
    492         else if (!stricmp(pExt, "CMD"))
    493         {
    494             pExec->ulOS = EXEOS_OS2;
    495             pExec->ulExeFormat = EXEFORMAT_TEXT_CMD;
    496         }
    497         else
    498             fOpenFile = TRUE;
    499     }
    500 
    501     if (    (fOpenFile)
    502          && (!(arc = doshOpen((PSZ)pcszExecutable,
    503                               XOPEN_READ_EXISTING,
    504                               &cbFile,
    505                               &pFile)))
    506        )
    507     {
    508         // file opened successfully:
    509         pExec->pFile = pFile;
    510 
    511         // read old DOS EXE header
    512         if (!(pExec->pDosExeHeader = (PDOSEXEHEADER)malloc(sizeof(DOSEXEHEADER))))
    513             arc = ERROR_NOT_ENOUGH_MEMORY;
    514         else
    515         {
    516             pExec->cbDosExeHeader = sizeof(DOSEXEHEADER);
    517             if (!(arc = doshReadAt(pFile,
    518                                    0,
    519                                    &pExec->cbDosExeHeader,      // in/out
    520                                    (PBYTE)pExec->pDosExeHeader)))
    521             {
    522                 ULONG ulNewHeaderOfs = 0;       // V0.9.12 (2001-05-03) [umoeller]
    523                 BOOL  fLoadNewHeader = FALSE;
    524 
    525                 // now check if we really have a DOS header
    526                 if (pExec->pDosExeHeader->usDosExeID != 0x5a4d)
    527                 {
    528                     // arc = ERROR_INVALID_EXE_SIGNATURE;
    529 
    530                     // V0.9.12 (2001-05-03) [umoeller]
    531                     // try loading new header directly; there are
    532                     // drivers which were built with NOSTUB, and
    533                     // the exe image starts out with the NE or LX
    534                     // image directly
    535                     fLoadNewHeader = TRUE;
    536                             // ulNewHeaderOfs is 0 now
    537 
    538                     // remove the DOS header info, since we have none
    539                     // V0.9.12 (2001-05-03) [umoeller]
    540                     FREE(pExec->pDosExeHeader);
    541                 }
    542                 else
    543                 {
    544                     // we have a DOS header:
    545                     if (pExec->pDosExeHeader->usRelocTableOfs < 0x40)
    546                     {
    547                         // neither LX nor PE nor NE:
    548                         pExec->ulOS = EXEOS_DOS3;
    549                         pExec->ulExeFormat = EXEFORMAT_OLDDOS;
    550                     }
    551                     else
    552                     {
    553                         // we have a new header offset:
    554                         fLoadNewHeader = TRUE;
    555                         ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
    556                     }
    557                 }
    558 
    559                 if (fLoadNewHeader)
    560                 {
    561                     // either LX or PE or NE:
    562                     // read in new header...
    563                     // ulNewHeaderOfs is now either 0 (if no DOS header
    564                     // was found) or pDosExeHeader->ulNewHeaderOfs
    565                     // V0.9.12 (2001-05-03) [umoeller]
    566                     ULONG   cbRead;
    567                     PBYTE   pbHeader;
    568 
    569                     // now, we used to read in the first two chars
    570                     // to check out if we have PE or LX or NE and
    571                     // then read the header accordingly... but
    572                     // that wasn't terribly efficient. So load
    573                     // a chunk of data and then do a realloc()
    574                     // instead.
    575 
    576                     // take the largest of LXHEADER and NEHEADER and PEHEADER
    577                     cbRead = sizeof(LXHEADER);
    578                     if (sizeof(NEHEADER) > cbRead)
    579                         cbRead = sizeof(NEHEADER);
    580                     if (sizeof(PEHEADER) > cbRead)
    581                         cbRead = sizeof(PEHEADER);
    582 
    583                     if (!(pbHeader = (PBYTE)malloc(cbRead)))
    584                         arc = ERROR_NOT_ENOUGH_MEMORY;
    585                     else if (!(arc = doshReadAt(pFile,
    586                                                 ulNewHeaderOfs,
    587                                                 &cbRead,
    588                                                 pbHeader)))
    589                     {
    590                         PBYTE   pbCheckOS = NULL;
    591 
    592                         PSZ     achNewHeaderType = (PSZ)pbHeader;
    593 
    594                         if (!memcmp(achNewHeaderType, "NE", 2))
    595                         {
    596                             // New Executable:
    597                             pExec->ulExeFormat = EXEFORMAT_NE;
    598 
    599                             if (cbRead < sizeof(NEHEADER))
    600                             {
    601                                 arc = ERROR_BAD_EXE_FORMAT;
    602                                 FREE(pbHeader);
    603                             }
    604                             else
    605                             {
    606                                 pExec->pNEHeader = (PNEHEADER)realloc(pbHeader,
    607                                                                       sizeof(NEHEADER));
    608                                 pExec->cbNEHeader = sizeof(NEHEADER);
    609                                 pbCheckOS = &pExec->pNEHeader->bTargetOS;
    610                                 // set library flag V0.9.16 (2001-12-08) [umoeller]
    611                                 if (pExec->pNEHeader->usFlags & 0x8000)
    612                                     // library:
    613                                     pExec->fLibrary = TRUE;
    614                             }
    615                         }
    616                         else if (    (!memcmp(achNewHeaderType, "LX", 2))
    617                                   || (!memcmp(achNewHeaderType, "LE", 2))
    618                                             // this is used by SMARTDRV.EXE
    619                                 )
    620                         {
    621                             // OS/2 Linear Executable:
    622                             pExec->ulExeFormat = EXEFORMAT_LX;
    623 
    624                             if (cbRead < sizeof(LXHEADER))
    625                             {
    626                                 arc = ERROR_BAD_EXE_FORMAT;
    627                                 FREE(pbHeader);
    628                             }
    629                             else
    630                             {
    631                                 pExec->pLXHeader = (PLXHEADER)realloc(pbHeader,
    632                                                                       sizeof(LXHEADER));
    633                                 // read in LX header
    634                                 pExec->cbLXHeader = sizeof(LXHEADER);
    635                                 pbCheckOS = (PBYTE)(&pExec->pLXHeader->usTargetOS);
    636                                 // set library flag V0.9.16 (2001-12-08) [umoeller]
    637                                 if (pExec->pLXHeader->ulFlags & 0x8000)
    638                                     // library:
    639                                     pExec->fLibrary = TRUE;
    640                             }
    641                         }
    642                         else if (!memcmp(achNewHeaderType, "PE", 2))
    643                         {
    644                             pExec->ulExeFormat = EXEFORMAT_PE;
    645 
    646                             if (cbRead < sizeof(PEHEADER))
    647                             {
    648                                 arc = ERROR_BAD_EXE_FORMAT;
    649                                 FREE(pbHeader);
    650                             }
    651                             else
    652                             {
    653                                 // PE has a standard header of 24 bytes
    654                                 // plus an extended header, so check what
    655                                 // we've got
    656                                 ULONG cbPE =   sizeof(PEHEADER); // 24
    657                                    //           + ((PPEHEADER)pbHeader)->usHeaderSize;
    658                                 pExec->pPEHeader = (PPEHEADER)realloc(pbHeader,
    659                                                                       cbPE);
    660 
    661                                 pExec->cbPEHeader = cbPE;
    662                                 pExec->ulOS = EXEOS_WIN32;
    663                                 pExec->f32Bits = TRUE;
    664 
    665                                 /*
    666                                 // we have the first 24 bytes already, so
    667                                 // go for the next chunk, if this is more
    668                                 // than we have in PEHEADER
    669                                 if (    (cbRead < cbPE)
    670                                      && (cbRead = pExec->pPEHeader->usHeaderSize)
    671                                    )
    672                                 {
    673                                     _Pmpf(("  usHdrSize %d, sizeof(PEHEADER) %d, cbRead %d, cbPE %d --> reading extended header",
    674                                            pExec->pPEHeader->usHeaderSize,
    675                                            sizeof(PEHEADER),
    676                                            cbRead,
    677                                            cbPE));
    678                                     if (!(arc = doshReadAt(hFile,
    679                                                            ulNewHeaderOfs + 24,
    680                                                            FILE_BEGIN,
    681                                                            &cbRead,
    682                                                            (PBYTE)pExec->pPEHeader + 24)))
    683                                     {
    684                                     }
    685                                     else
    686                                     {
    687                                         arc = ERROR_BAD_EXE_FORMAT;
    688                                         FREE(pExec->pPEHeader);
    689                                     }
    690                                 }
    691                                 else
    692                                     _Pmpf(("  already got extended header"));
    693                                 */
    694                             }
    695                         }
    696                         else
    697                         {
    698                             // strange type:
    699                             arc = ERROR_INVALID_EXE_SIGNATURE;
    700                             FREE(pbHeader);
    701                         }
    702 
    703                         if ((!arc) && (pbCheckOS))
    704                         {
    705                             // BYTE to check for operating system
    706                             // (NE and LX):
    707                             switch (*pbCheckOS)
    708                             {
    709                                 case NEOS_OS2:
    710                                     pExec->ulOS = EXEOS_OS2;
    711                                     if (pExec->ulExeFormat == EXEFORMAT_LX)
    712                                         pExec->f32Bits = TRUE;
    713                                 break;
    714 
    715                                 case NEOS_WIN16:
    716                                     pExec->ulOS = EXEOS_WIN16;
    717                                 break;
    718 
    719                                 case NEOS_DOS4:
    720                                     pExec->ulOS = EXEOS_DOS4;
    721                                 break;
    722 
    723                                 case NEOS_WIN386:
    724                                     pExec->ulOS = EXEOS_WIN386;
    725                                     pExec->f32Bits = TRUE;
    726                                 break;
    727                             }
    728                         }
    729                     } // end if (!(arc = doshReadAt(hFile,
    730                 } // end if (fLoadNewHeader)
    731             } // end if (!(arc = doshReadAt(hFile,
    732         } // end else if (!(pExec->pDosExeHeader = (PDOSEXEHEADER)malloc(sizeof(DOSEXEHEADER))))
    733 
    734     } // end if (!(arc = DosOpen((PSZ)pcszExecutable,
    735 
    736     if (arc != NO_ERROR)
    737         // error: clean up
    738         doshExecClose(&pExec);
    739     else
    740         *ppExec = pExec;
    741 
    742     return (arc);
    743 }
    744 
    745 /*
    746  *@@ ParseBldLevel:
    747  *      called from doshExecQueryBldLevel to parse
    748  *      the BLDLEVEL string.
    749  *
    750  *      On entry, caller has copied the string into
    751  *      pExec->pszDescription. The string is
    752  *      null-terminated.
    753  *
    754  *      The BLDLEVEL string comes in two flavors.
    755  *
    756  *      --  The standard format is:
    757  *
    758  +              @#VENDOR:VERSION#@DESCRIPTION
    759  *
    760  *          DESCRIPTION can have leading spaces, but
    761  *          need to have them.
    762  *
    763  *      --  However, there is an extended version
    764  *          in that the DESCRIPTION field is split
    765  *          up even more. The marker for this seems
    766  *          to be that the description starts out
    767  *          with "##1##".
    768  *
    769  +              ##1## DATETIME BUILDMACHINE:ASD:LANG:CTRY:REVISION:UNKNOWN:FIXPAK@@DESCRIPTION
    770  *
    771  *          The problem is that the DATETIME field comes
    772  *          in several flavors. IBM uses things like
    773  *
    774  +              "Thu Nov 30 15:30:37 2000 BWBLD228"
    775  *
    776  *          while DANIS506.ADD has
    777  *
    778  +              "15.12.2000 18:22:57      Nachtigall"
    779  *
    780  *          Looks like the date/time string is standardized
    781  *          to have 24 characters then.
    782  *
    783  *@@added V0.9.12 (2001-05-18) [umoeller]
    784  *@@changed V0.9.12 (2001-05-19) [umoeller]: added extended BLDLEVEL support
    785  */
    786 
    787 VOID ParseBldLevel(PEXECUTABLE pExec)
    788 {
    789     const char  // *pStartOfAuthor = 0,
    790                 *pStartOfVendor = 0;
    791 
    792     // @#VENDOR:VERSION#@ DESCRIPTION
    793     // but skip the first byte, which has the string length
    794     pStartOfVendor = strstr(pExec->pszDescription,
    795                             "@#");
    796     if (pStartOfVendor)
    797     {
    798         const char *pStartOfInfo = strstr(pStartOfVendor + 2,
    799                                           "#@");
    800         if (pStartOfInfo)
    801         {
    802             const char *pEndOfVendor = strchr(pStartOfVendor + 2,
    803                                               ':');
    804             if (pEndOfVendor)
    805             {
    806                 pExec->pszVendor = strhSubstr(pStartOfVendor + 2,
    807                                               pEndOfVendor);
    808                 pExec->pszVersion = strhSubstr(pEndOfVendor + 1,
    809                                                pStartOfInfo);
    810                 // skip "@#" in DESCRIPTION string
    811                 pStartOfInfo += 2;
    812 
    813                 // now check if we have extended DESCRIPTION V0.9.12 (2001-05-19) [umoeller]
    814                 if (    (strlen(pStartOfInfo) > 6)
    815                      && (!memcmp(pStartOfInfo, "##1##", 5))
    816                    )
    817                 {
    818                     // yes: parse that beast
    819                     const char *p = pStartOfInfo + 5;
    820 
    821                     // get build date/time
    822                     if (strlen(p) > 24)
    823                     {
    824                         // date/time seems to be fixed 24 chars in length
    825                         if (pExec->pszBuildDateTime = (PSZ)malloc(25))
    826                         {
    827                             memcpy(pExec->pszBuildDateTime,
    828                                    p,
    829                                    24);
    830                             pExec->pszBuildDateTime[24] = '\0';
    831 
    832                             p += 24;
    833 
    834                             // now we're at the colon-separated
    835                             // strings, first of which is the
    836                             // build machine;
    837                             // skip leading spaces
    838                             while (*p == ' ')
    839                                 p++;
    840 
    841                             if (*p)
    842                             {
    843                                 char **papsz[] =
    844                                     {
    845                                         &pExec->pszBuildMachine,
    846                                         &pExec->pszASD,
    847                                         &pExec->pszLanguage,
    848                                         &pExec->pszCountry,
    849                                         &pExec->pszRevision,
    850                                         &pExec->pszUnknown,
    851                                         &pExec->pszFixpak
    852                                     };
    853                                 ULONG ul;
    854 
    855                                 for (ul = 0;
    856                                      ul < sizeof(papsz) / sizeof(papsz[0]);
    857                                      ul++)
    858                                 {
    859                                     BOOL fStop = FALSE;
    860                                     const char *pNextColon = strchr(p, ':'),
    861                                                *pDoubleAt = strstr(p, "@@");
    862                                     if (!pNextColon)
    863                                     {
    864                                         // last item:
    865                                         if (pDoubleAt)
    866                                             pNextColon = pDoubleAt;
    867                                         else
    868                                             pNextColon = p + strlen(p);
    869 
    870                                         fStop = TRUE;
    871                                     }
    872 
    873                                     if (    (fStop)
    874                                          || (    (pNextColon)
    875                                               && (    (!pDoubleAt)
    876                                                    || (pNextColon < pDoubleAt)
    877                                                  )
    878                                             )
    879                                        )
    880                                     {
    881                                         if (pNextColon > p + 1)
    882                                             *(papsz[ul]) = strhSubstr(p, pNextColon);
    883                                     }
    884                                     else
    885                                         break;
    886 
    887                                     if (fStop)
    888                                         break;
    889 
    890                                     p = pNextColon + 1;
    891                                 }
    892                             }
    893                         }
    894                     }
    895 
    896                     pStartOfInfo = strstr(p,
    897                                           "@@");
    898                     if (pStartOfInfo)
    899                         pStartOfInfo += 2;
    900                 }
    901 
    902                 // -- if we had no extended DESCRIPTION,
    903                 //    pStartOfInfo points to regular description now
    904                 // -- if we parse the extended DESCRIPTION above,
    905                 //    pStartOfInfo points to after @@ now
    906                 // -- if we had an error, pStartOfInfo is NULL
    907                 if (pStartOfInfo)
    908                 {
    909                     // add the regular DESCRIPTION then
    910                     // skip leading spaces in info string
    911                     while (*pStartOfInfo == ' ')
    912                         pStartOfInfo++;
    913                     if (*pStartOfInfo)  // V0.9.9 (2001-04-04) [umoeller]
    914                         // and copy until end of string
    915                         pExec->pszInfo = strdup(pStartOfInfo);
    916                 }
    917             }
    918         }
    919     }
    920 }
    921 
    922 /*
    923  *@@ doshExecQueryBldLevel:
    924  *      this retrieves buildlevel information for an
    925  *      LX or NE executable previously opened with
    926  *      doshExecOpen.
    927  *
    928  *      BuildLevel information must be contained in the
    929  *      DESCRIPTION field of an executable's module
    930  *      definition (.DEF) file. In order to be readable
    931  *      by BLDLEVEL.EXE (which ships with OS/2), this
    932  *      string must have the following format:
    933  *
    934  +          Description '@#AUTHOR:VERSION#@ DESCRIPTION'
    935  *
    936  *      Example:
    937  *
    938  +          Description '@#Ulrich M”ller:0.9.0#@ XWorkplace Sound Support Module'
    939  *
    940  *      The "Description" entry always ends up as the
    941  *      very first entry in the non-resident name table
    942  *      in LX and NE executables. So this is what we retrieve
    943  *      here.
    944  *
    945  *      If the first entry in that table exists, NO_ERROR is
    946  *      returned and at least the pszDescription field in
    947  *      EXECUTABLE is set to that information.
    948  *
    949  *      If that string is in IBM BLDLEVEL format, the string
    950  *      is automatically parsed, and the pszVendor, pszVersion,
    951  *      and pszInfo fields are also set. In the above examples,
    952  *      this would return the following information:
    953  +          pszVendor = "Ulrich M”ller"
    954  +          pszVersion = "0.9.0"
    955  +          pszInfo = "XWorkplace Sound Support Module"
    956  *
    957  *      If that string is not in BLDLEVEL format, only pszDescription
    958  *      will be set. The other fields remain NULL.
    959  *
    960  *      This returns the following errors:
    961  *
    962  *      -- ERROR_INVALID_PARAMETER: pExec invalid
    963  *
    964  *      -- ERROR_INVALID_EXE_SIGNATURE (191): pExec is not in LX or NE format
    965  *
    966  *      -- ERROR_INVALID_DATA (13): non-resident name table not found.
    967  *
    968  *      -- ERROR_NOT_ENOUGH_MEMORY: malloc() failed.
    969  *
    970  *      plus the error codes of DosSetFilePtr and DosRead.
    971  *
    972  *@@added V0.9.0 [umoeller]
    973  *@@changed V0.9.0 (99-10-22) [umoeller]: NE format now supported
    974  *@@changed V0.9.1 (99-12-06): fixed memory leak
    975  *@@changed V0.9.9 (2001-04-04) [umoeller]: added more error checking
    976  *@@changed V0.9.12 (2001-05-18) [umoeller]: extracted ParseBldLevel
    977  */
    978 
    979 APIRET doshExecQueryBldLevel(PEXECUTABLE pExec)
    980 {
    981     APIRET      arc = NO_ERROR;
    982 
    983     if (!pExec)
    984         arc = ERROR_INVALID_PARAMETER;
    985     else
    986     {
    987         PXFILE      pFile = pExec->pFile;
    988 
    989         ULONG       ulNRNTOfs = 0;
    990 
    991         if (pExec->ulExeFormat == EXEFORMAT_LX)
    992         {
    993             // OK, LX format:
    994             // check if we have a non-resident name table
    995             if (pExec->pLXHeader == NULL)
    996                 arc = ERROR_INVALID_DATA;
    997             else if (pExec->pLXHeader->ulNonResdNameTblOfs == 0)
    998                 arc = ERROR_INVALID_DATA;
    999             else
    1000                 ulNRNTOfs = pExec->pLXHeader->ulNonResdNameTblOfs;
    1001         }
    1002         else if (pExec->ulExeFormat == EXEFORMAT_NE)
    1003         {
    1004             // OK, NE format:
    1005             // check if we have a non-resident name table
    1006             if (pExec->pNEHeader == NULL)
    1007                 arc = ERROR_INVALID_DATA;
    1008             else if (pExec->pNEHeader->ulNonResdTblOfs == 0)
    1009                 arc = ERROR_INVALID_DATA;
    1010             else
    1011                 ulNRNTOfs = pExec->pNEHeader->ulNonResdTblOfs;
    1012         }
    1013         else
    1014             // neither LX nor NE: stop
    1015             arc = ERROR_INVALID_EXE_SIGNATURE;
    1016 
    1017         if (    (!arc)
    1018              && (ulNRNTOfs)
    1019            )
    1020         {
    1021             ULONG       ulLocal = 0,
    1022                         ulBytesRead = 0;
    1023 
    1024             // move EXE file pointer to offset of non-resident name table
    1025             // (from LX header)
    1026             if (!(arc = DosSetFilePtr(pFile->hf,     // file is still open
    1027                                       ulNRNTOfs,      // ofs determined above
    1028                                       FILE_BEGIN,
    1029                                       &ulLocal)))
    1030             {
    1031                 // allocate memory as necessary
    1032                 PSZ pszNameTable = (PSZ)malloc(2001); // should suffice, because each entry
    1033                                                       // may only be 255 bytes in length
    1034                 if (!pszNameTable)
    1035                     arc = ERROR_NOT_ENOUGH_MEMORY;
    1036                 else
    1037                 {
    1038                     if (!(arc = DosRead(pFile->hf,
    1039                                         pszNameTable,
    1040                                         2000,
    1041                                         &ulBytesRead)))
    1042                     {
    1043                         if (*pszNameTable == 0)
    1044                             // first byte (length byte) is null:
    1045                             arc = ERROR_INVALID_DATA;
    1046                         else
    1047                         {
    1048                             // now copy the string, which is in Pascal format
    1049                             pExec->pszDescription = (PSZ)malloc((*pszNameTable) + 1);    // addt'l null byte
    1050                             if (!pExec->pszDescription)
    1051                                 arc = ERROR_NOT_ENOUGH_MEMORY;
    1052                             else
    1053                             {
    1054                                 memcpy(pExec->pszDescription,
    1055                                        pszNameTable + 1,        // skip length byte
    1056                                        *pszNameTable);          // length byte
    1057                                 // terminate string
    1058                                 *(pExec->pszDescription + (*pszNameTable)) = 0;
    1059 
    1060                                 ParseBldLevel(pExec);
    1061                             }
    1062                         }
    1063                     }
    1064 
    1065                     free(pszNameTable);
    1066                 } // end if PSZ pszNameTable = (PSZ)malloc(2001);
    1067             }
    1068         }
    1069     } // end if (!pExec)
    1070 
    1071     return (arc);
    1072 }
    1073 
    1074 /*
    1075  *@@ doshExecQueryImportedModules:
    1076  *      returns an array of FSYSMODULE structure describing all
    1077  *      imported modules.
    1078  *
    1079  *      *pcModules receives the # of items in the array (not the
    1080  *      array size!).  Use doshFreeImportedModules to clean up.
    1081  *
    1082  *      This returns a standard OS/2 error code, which might be
    1083  *      any of the codes returned by DosSetFilePtr and DosRead.
    1084  *      In addition, this may return:
    1085  *
    1086  *      --  ERROR_NOT_ENOUGH_MEMORY
    1087  *
    1088  *      --  ERROR_INVALID_EXE_SIGNATURE: exe is in a format other
    1089  *          than LX or NE, which is not understood by this function.
    1090  *
    1091  *      Even if NO_ERROR is returned, the array pointer might still
    1092  *      be NULL if the module contains no such data.
    1093  *
    1094  *@@added V0.9.9 (2001-03-11) [lafaix]
    1095  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
    1096  *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
    1097  *@@changed V0.9.10 (2001-04-10) [lafaix]: added Win16 and Win386 support
    1098  *@@changed V0.9.10 (2001-04-13) [lafaix]: removed 127 characters limit
    1099  *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
    1100  */
    1101 
    1102 APIRET doshExecQueryImportedModules(PEXECUTABLE pExec,
    1103                                     PFSYSMODULE *ppaModules,    // out: modules array
    1104                                     PULONG pcModules)           // out: array item count
    1105 {
    1106     if (    (pExec)
    1107          && (    (pExec->ulOS == EXEOS_OS2)
    1108               || (pExec->ulOS == EXEOS_WIN16)
    1109               || (pExec->ulOS == EXEOS_WIN386)
    1110             )
    1111        )
    1112     {
    1113         ENSURE_BEGIN;
    1114         ULONG       cModules = 0;
    1115         PFSYSMODULE paModules = NULL;
    1116         int i;
    1117         HFILE hfExe = pExec->pFile->hf;
    1118 
    1119         ULONG ulNewHeaderOfs = 0;       // V0.9.12 (2001-05-03) [umoeller]
    1120 
    1121         if (pExec->pDosExeHeader)
    1122             // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
    1123             ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
    1124 
    1125         if (pExec->ulExeFormat == EXEFORMAT_LX)
    1126         {
    1127             // 32-bit OS/2 executable:
    1128             cModules = pExec->pLXHeader->ulImportModTblCnt;
    1129 
    1130             if (cModules)
    1131             {
    1132                 ULONG   cb = sizeof(FSYSMODULE) * cModules; // V0.9.9 (2001-04-03) [umoeller]
    1133                 ULONG   ulDummy;
    1134 
    1135                 paModules = (PFSYSMODULE)malloc(cb);
    1136                 if (!paModules)
    1137                     ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY); // V0.9.9 (2001-04-03) [umoeller]
    1138 
    1139                 memset(paModules, 0, cb);   // V0.9.9 (2001-04-03) [umoeller]
    1140 
    1141                 ENSURE_SAFE(DosSetFilePtr(hfExe,
    1142                                           pExec->pLXHeader->ulImportModTblOfs
    1143                                             + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
    1144                                           FILE_BEGIN,
    1145                                           &ulDummy));
    1146 
    1147                 for (i = 0; i < cModules; i++)
    1148                 {
    1149                     BYTE bLen = 0;
    1150 
    1151                     // reading the length of the module name
    1152                     ENSURE_SAFE(DosRead(hfExe, &bLen, 1, &ulDummy));
    1153 
    1154                     // reading the module name
    1155                     ENSURE_SAFE(DosRead(hfExe,
    1156                                         paModules[i].achModuleName,
    1157                                         bLen,
    1158                                         &ulDummy));
    1159 
    1160                     // module names are not null terminated, so we must
    1161                     // do it now
    1162                     paModules[i].achModuleName[bLen] = 0;
    1163                 } // end for
    1164             }
    1165         } // end LX
    1166         else if (pExec->ulExeFormat == EXEFORMAT_NE)
    1167         {
    1168             // 16-bit executable:
    1169             cModules = pExec->pNEHeader->usModuleTblEntries;
    1170 
    1171             if (cModules)
    1172             {
    1173                 ULONG cb = sizeof(FSYSMODULE) * cModules;
    1174 
    1175                 paModules = (PFSYSMODULE)malloc(cb);
    1176                 if (!paModules)
    1177                     ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);  // V0.9.9 (2001-04-03) [umoeller]
    1178 
    1179                 memset(paModules, 0, cb);   // V0.9.9 (2001-04-03) [umoeller]
    1180 
    1181                 for (i = 0; i < cModules; i ++)
    1182                 {
    1183                     BYTE bLen;
    1184                     USHORT usOfs;
    1185                     ULONG ulDummy;
    1186 
    1187                     // the module reference table contains offsets
    1188                     // relative to the import table; we hence read
    1189                     // the offset in the module reference table, and
    1190                     // then we read the name in the import table
    1191 
    1192                     ENSURE_SAFE(DosSetFilePtr(hfExe,
    1193                                               pExec->pNEHeader->usModRefTblOfs
    1194                                                 + ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]
    1195                                                 + sizeof(usOfs) * i,
    1196                                               FILE_BEGIN,
    1197                                               &ulDummy));
    1198 
    1199                     ENSURE_SAFE(DosRead(hfExe, &usOfs, 2, &ulDummy));
    1200 
    1201                     ENSURE_SAFE(DosSetFilePtr(hfExe,
    1202                                               pExec->pNEHeader->usImportTblOfs
    1203                                                 + ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]
    1204                                                 + usOfs,
    1205                                               FILE_BEGIN,
    1206                                               &ulDummy));
    1207 
    1208                     ENSURE_SAFE(DosRead(hfExe, &bLen, 1, &ulDummy));
    1209 
    1210                     ENSURE_SAFE(DosRead(hfExe,
    1211                                         paModules[i].achModuleName,
    1212                                         bLen,
    1213                                         &ulDummy));
    1214 
    1215                     paModules[i].achModuleName[bLen] = 0;
    1216                 } // end for
    1217             }
    1218         } // end NE
    1219         else
    1220             ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
    1221 
    1222         // no error: output data
    1223         *ppaModules = paModules;
    1224         *pcModules = cModules;
    1225 
    1226         ENSURE_FINALLY;
    1227             // if we had an error above, clean up
    1228             free(paModules);
    1229         ENSURE_END;
    1230     }
    1231     else
    1232         ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
    1233 
    1234     ENSURE_OK;
    1235 }
    1236 
    1237 /*
    1238  *@@ doshExecFreeImportedModules:
    1239  *      frees resources allocated by doshExecQueryImportedModules.
    1240  *
    1241  *@@added V0.9.9 (2001-03-11)
    1242  */
    1243 
    1244 APIRET doshExecFreeImportedModules(PFSYSMODULE paModules)
    1245 {
    1246     free(paModules);
    1247     return (NO_ERROR);
    1248 }
    1249 
    1250 /*
    1251  *@@ ScanLXEntryTable:
    1252  *      returns the number of exported entries in the entry table.
    1253  *
    1254  *      If paFunctions is not NULL, then successive entries are
    1255  *      filled with the found type and ordinal values.
    1256  *
    1257  *@@added V0.9.9 (2001-03-30) [lafaix]
    1258  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
    1259  *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
    1260  *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
    1261  */
    1262 
    1263 APIRET ScanLXEntryTable(PEXECUTABLE pExec,
    1264                         PFSYSFUNCTION paFunctions,
    1265                         PULONG pcEntries)        // out: entry table entry count; ptr can be NULL
    1266 {
    1267     ULONG  ulDummy;
    1268     USHORT usOrdinal = 1,
    1269            usCurrent = 0;
    1270     int    i;
    1271 
    1272     ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]
    1273     HFILE hfExe = pExec->pFile->hf;
    1274 
    1275     if (pExec->pDosExeHeader)
    1276         // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
    1277         ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
    1278 
    1279     ENSURE(DosSetFilePtr(hfExe,
    1280                          pExec->pLXHeader->ulEntryTblOfs
    1281                            + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
    1282                          FILE_BEGIN,
    1283                          &ulDummy));
    1284 
    1285     while (TRUE)
    1286     {
    1287         BYTE   bCnt,
    1288                bType,
    1289                bFlag;
    1290 
    1291         ENSURE(DosRead(hfExe, &bCnt, 1, &ulDummy));
    1292 
    1293         if (bCnt == 0)
    1294             // end of the entry table
    1295             break;
    1296 
    1297         ENSURE(DosRead(hfExe, &bType, 1, &ulDummy));
    1298 
    1299         switch (bType & 0x7F)
    1300         {
    1301             /*
    1302              * unused entries
    1303              *
    1304              */
    1305 
    1306             case 0:
    1307                 usOrdinal += bCnt;
    1308             break;
    1309 
    1310             /*
    1311              * 16-bit entries
    1312              *
    1313              * the bundle type is followed by the object number
    1314              * and by bCnt bFlag+usOffset entries
    1315              *
    1316              */
    1317 
    1318             case 1:
    1319                 ENSURE(DosSetFilePtr(hfExe,
    1320                                      sizeof(USHORT),
    1321                                      FILE_CURRENT,
    1322                                      &ulDummy));
    1323 
    1324                 for (i = 0; i < bCnt; i ++)
    1325                 {
    1326                     ENSURE(DosRead(hfExe, &bFlag, 1, &ulDummy));
    1327 
    1328                     if (bFlag & 0x01)
    1329                     {
    1330                         if (paFunctions)
    1331                         {
    1332                             paFunctions[usCurrent].ulOrdinal = usOrdinal;
    1333                             paFunctions[usCurrent].ulType = 1;
    1334                             paFunctions[usCurrent].achFunctionName[0] = 0;
    1335                         }
    1336                         usCurrent++;
    1337                     }
    1338 
    1339                     usOrdinal++;
    1340 
    1341                     ENSURE(DosSetFilePtr(hfExe,
    1342                                          sizeof(USHORT),
    1343                                          FILE_CURRENT,
    1344                                          &ulDummy));
    1345 
    1346                 } // end for
    1347             break;
    1348 
    1349             /*
    1350              * 286 call gate entries
    1351              *
    1352              * the bundle type is followed by the object number
    1353              * and by bCnt bFlag+usOffset+usCallGate entries
    1354              *
    1355              */
    1356 
    1357             case 2:
    1358                 ENSURE(DosSetFilePtr(hfExe,
    1359                                      sizeof(USHORT),
    1360                                      FILE_CURRENT,
    1361                                      &ulDummy));
    1362 
    1363                 for (i = 0; i < bCnt; i ++)
    1364                 {
    1365                     ENSURE(DosRead(hfExe, &bFlag, 1, &ulDummy));
    1366 
    1367                     if (bFlag & 0x01)
    1368                     {
    1369                         if (paFunctions)
    1370                         {
    1371                             paFunctions[usCurrent].ulOrdinal = usOrdinal;
    1372                             paFunctions[usCurrent].ulType = 2;
    1373                             paFunctions[usCurrent].achFunctionName[0] = 0;
    1374                         }
    1375                         usCurrent++;
    1376                     }
    1377 
    1378                     usOrdinal++;
    1379 
    1380                     ENSURE(DosSetFilePtr(hfExe,
    1381                                          sizeof(USHORT) + sizeof(USHORT),
    1382                                          FILE_CURRENT,
    1383                                          &ulDummy));
    1384 
    1385                 } // end for
    1386             break;
    1387 
    1388             /*
    1389              * 32-bit entries
    1390              *
    1391              * the bundle type is followed by the object number
    1392              * and by bCnt bFlag+ulOffset entries
    1393              *
    1394              */
    1395 
    1396             case 3:
    1397                 ENSURE(DosSetFilePtr(hfExe,
    1398                                      sizeof(USHORT),
    1399                                      FILE_CURRENT,
    1400                                      &ulDummy));
    1401 
    1402                 for (i = 0; i < bCnt; i ++)
    1403                 {
    1404                     ENSURE(DosRead(hfExe, &bFlag, 1, &ulDummy));
    1405 
    1406                     if (bFlag & 0x01)
    1407                     {
    1408                         if (paFunctions)
    1409                         {
    1410                             paFunctions[usCurrent].ulOrdinal = usOrdinal;
    1411                             paFunctions[usCurrent].ulType = 3;
    1412                             paFunctions[usCurrent].achFunctionName[0] = 0;
    1413                         }
    1414                         usCurrent++;
    1415                     }
    1416 
    1417                     usOrdinal++;
    1418 
    1419                     ENSURE(DosSetFilePtr(hfExe,
    1420                                          sizeof(ULONG),
    1421                                          FILE_CURRENT,
    1422                                          &ulDummy));
    1423                 } // end for
    1424             break;
    1425 
    1426             /*
    1427              * forwarder entries
    1428              *
    1429              * the bundle type is followed by a reserved word
    1430              * and by bCnt bFlag+usModOrd+ulOffsOrdNum entries
    1431              *
    1432              */
    1433 
    1434             case 4:
    1435                 ENSURE(DosSetFilePtr(hfExe,
    1436                                      sizeof(USHORT),
    1437                                      FILE_CURRENT,
    1438                                      &ulDummy));
    1439 
    1440                 for (i = 0; i < bCnt; i ++)
    1441                 {
    1442                     ENSURE(DosSetFilePtr(hfExe,
    1443                                          sizeof(BYTE) + sizeof(USHORT) + sizeof(ULONG),
    1444                                          FILE_CURRENT,
    1445                                          &ulDummy));
    1446 
    1447                     if (paFunctions)
    1448                     {
    1449                         paFunctions[usCurrent].ulOrdinal = usOrdinal;
    1450                         paFunctions[usCurrent].ulType = 4;
    1451                         paFunctions[usCurrent].achFunctionName[0] = 0;
    1452                     }
    1453                     usCurrent++;
    1454 
    1455                     usOrdinal++;
    1456                 } // end for
    1457             break;
    1458 
    1459             /*
    1460              * unknown bundle type
    1461              *
    1462              * we don't know how to handle this bundle, so we must
    1463              * stop parsing the entry table here (as we don't know the
    1464              * bundle size); if paFunctions is not null, we fill it with
    1465              * informative data
    1466              */
    1467 
    1468             default:
    1469                 if (paFunctions)
    1470                 {
    1471                     paFunctions[usCurrent].ulOrdinal = usOrdinal;
    1472                     paFunctions[usCurrent].ulType = bType;
    1473                     sprintf(paFunctions[usCurrent].achFunctionName,
    1474                             "Unknown bundle type encountered (%d).  Aborting entry table scan.",
    1475                             bType);
    1476 
    1477                     usCurrent++;
    1478                 }
    1479                 ENSURE_FAIL(ERROR_INVALID_LIST_FORMAT);
    1480                     // whatever
    1481                     // V0.9.9 (2001-04-03) [umoeller]
    1482         } // end switch (bType & 0x7F)
    1483     } // end while (TRUE)
    1484 
    1485     if (pcEntries)
    1486        *pcEntries = usCurrent;
    1487 
    1488     ENSURE_OK;
    1489 }
    1490 
    1491 /*
    1492  *@@ ScanNEEntryTable:
    1493  *      returns the number of exported entries in the entry table.
    1494  *
    1495  *      if paFunctions is not NULL, then successive entries are
    1496  *      filled with the found type and ordinal values.
    1497  *
    1498  *@@added V0.9.9 (2001-03-30) [lafaix]
    1499  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
    1500  *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
    1501  *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
    1502  */
    1503 
    1504 APIRET ScanNEEntryTable(PEXECUTABLE pExec,
    1505                         PFSYSFUNCTION paFunctions,
    1506                         PULONG pcEntries)        // out: entry table entry count; ptr can be NULL
    1507 {
    1508     ULONG  ulDummy;
    1509     USHORT usOrdinal = 1,
    1510            usCurrent = 0;
    1511     int    i;
    1512 
    1513     ULONG ulNewHeaderOfs = 0;
    1514     HFILE hfExe = pExec->pFile->hf;
    1515 
    1516     if (pExec->pDosExeHeader)
    1517         // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
    1518         ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
    1519 
    1520     ENSURE(DosSetFilePtr(hfExe,
    1521                          pExec->pNEHeader->usEntryTblOfs
    1522                            + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
    1523                          FILE_BEGIN,
    1524                          &ulDummy));
    1525 
    1526     while (TRUE)
    1527     {
    1528         BYTE bCnt,
    1529              bType,
    1530              bFlag;
    1531 
    1532         ENSURE(DosRead(hfExe, &bCnt, 1, &ulDummy));
    1533 
    1534         if (bCnt == 0)
    1535             // end of the entry table
    1536             break;
    1537 
    1538         ENSURE(DosRead(hfExe, &bType, 1, &ulDummy));
    1539 
    1540         if (bType)
    1541         {
    1542             for (i = 0; i < bCnt; i++)
    1543             {
    1544                 ENSURE(DosRead(hfExe,
    1545                                &bFlag,
    1546                                1,
    1547                                &ulDummy));
    1548 
    1549                 if (bFlag & 0x01)
    1550                 {
    1551                     if (paFunctions)
    1552                     {
    1553                         paFunctions[usCurrent].ulOrdinal = usOrdinal;
    1554                         paFunctions[usCurrent].ulType = 1; // 16-bit entry
    1555                         paFunctions[usCurrent].achFunctionName[0] = 0;
    1556                     }
    1557                     usCurrent++;
    1558                 }
    1559 
    1560                 usOrdinal++;
    1561 
    1562                 if (bType == 0xFF)
    1563                 {
    1564                     // moveable segment
    1565                     ENSURE(DosSetFilePtr(hfExe,
    1566                                          5,
    1567                                          FILE_CURRENT,
    1568                                          &ulDummy));
    1569                 }
    1570                 else
    1571                 {
    1572                     // fixed segment or constant (0xFE)
    1573                     ENSURE(DosSetFilePtr(hfExe,
    1574                                          2,
    1575                                          FILE_CURRENT,
    1576                                          &ulDummy));
    1577                 }
    1578 
    1579             } // end for
    1580         }
    1581         else
    1582             usOrdinal += bCnt;
    1583     } // end while (TRUE)
    1584 
    1585     if (pcEntries)
    1586         *pcEntries = usCurrent;
    1587 
    1588     ENSURE_OK;
    1589 }
    1590 
    1591 /*
    1592  *@@ Compare:
    1593  *      binary search helper
    1594  *
    1595  *@@added V0.9.9 (2001-04-01) [lafaix]
    1596  *@@changed V0.9.9 (2001-04-07) [umoeller]: added _Optlink, or this won't compile as C++
    1597  */
    1598 
    1599 int _Optlink Compare(const void *key,
    1600                      const void *element)
    1601 {
    1602     USHORT        usOrdinal = *((PUSHORT) key);
    1603     PFSYSFUNCTION pFunction = (PFSYSFUNCTION)element;
    1604 
    1605     if (usOrdinal > pFunction->ulOrdinal)
    1606         return (1);
    1607     else if (usOrdinal < pFunction->ulOrdinal)
    1608         return (-1);
    1609     else
    1610         return (0);
    1611 }
    1612 
    1613 /*
    1614  *@@ ScanNameTable:
    1615  *      scans a resident or non-resident name table, and fills the
    1616  *      appropriate paFunctions entries when it encounters exported
    1617  *      entries names.
    1618  *
    1619  *      This functions works for both NE and LX executables.
    1620  *
    1621  *@@added V0.9.9 (2001-03-30) [lafaix]
    1622  *@@changed V0.9.9 (2001-04-02) [lafaix]: the first entry is special
    1623  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
    1624  *@@changed V0.9.9 (2001-04-05) [lafaix]: removed the 127 char limit
    1625  *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
    1626  */
    1627 
    1628 APIRET ScanNameTable(PEXECUTABLE pExec,
    1629                      ULONG cFunctions,
    1630                      PFSYSFUNCTION paFunctions)
    1631 {
    1632     ULONG   ulDummy;
    1633 
    1634     USHORT        usOrdinal;
    1635     PFSYSFUNCTION pFunction;
    1636     HFILE hfExe = pExec->pFile->hf;
    1637 
    1638     while (TRUE)
    1639     {
    1640         BYTE   bLen;
    1641         CHAR   achName[256];
    1642         // int    i;
    1643 
    1644         ENSURE(DosRead(hfExe, &bLen, 1, &ulDummy));
    1645 
    1646         if (bLen == 0)
    1647             // end of the name table
    1648             break;
    1649 
    1650         ENSURE(DosRead(hfExe, &achName, bLen, &ulDummy));
    1651         achName[bLen] = 0;
    1652 
    1653         ENSURE(DosRead(hfExe, &usOrdinal, sizeof(USHORT), &ulDummy));
    1654 
    1655         if ((pFunction = (PFSYSFUNCTION)bsearch(&usOrdinal,
    1656                                                 paFunctions,
    1657                                                 cFunctions,
    1658                                                 sizeof(FSYSFUNCTION),
    1659                                                 Compare)))
    1660         {
    1661             memcpy(pFunction->achFunctionName,
    1662                    achName,
    1663                    bLen+1);
    1664         }
    1665     }
    1666 
    1667     ENSURE_OK;
    1668 }
    1669 
    1670 /*
    1671  *@@ doshExecQueryExportedFunctions:
    1672  *      returns an array of FSYSFUNCTION structure describing all
    1673  *      exported functions.
    1674  *
    1675  *      *pcFunctions receives the # of items in the array (not the
    1676  *      array size!).  Use doshFreeExportedFunctions to clean up.
    1677  *
    1678  *      Note that the returned array only contains entry for exported
    1679  *      functions.  Empty export entries are _not_ included.
    1680  *
    1681  *      This returns a standard OS/2 error code, which might be
    1682  *      any of the codes returned by DosSetFilePtr and DosRead.
    1683  *      In addition, this may return:
    1684  *
    1685  *      --  ERROR_NOT_ENOUGH_MEMORY
    1686  *
    1687  *      --  ERROR_INVALID_EXE_SIGNATURE: exe is in a format other
    1688  *          than LX or NE, which is not understood by this function.
    1689  *
    1690  *      --  If ERROR_INVALID_LIST_FORMAT is returned, the format of an
    1691  *          export entry wasn't understood here.
    1692  *
    1693  *      Even if NO_ERROR is returned, the array pointer might still
    1694  *      be NULL if the module contains no such data.
    1695  *
    1696  *@@added V0.9.9 (2001-03-11) [lafaix]
    1697  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
    1698  *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
    1699  *@@changed V0.9.10 (2001-04-10) [lafaix]: added Win16 and Win386 support
    1700  *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
    1701  */
    1702 
    1703 APIRET doshExecQueryExportedFunctions(PEXECUTABLE pExec,
    1704                                       PFSYSFUNCTION *ppaFunctions,  // out: functions array
    1705                                       PULONG pcFunctions)           // out: array item count
    1706 {
    1707     if (    (pExec)
    1708          && (    (pExec->ulOS == EXEOS_OS2)
    1709               || (pExec->ulOS == EXEOS_WIN16)
    1710               || (pExec->ulOS == EXEOS_WIN386)
    1711             )
    1712        )
    1713     {
    1714         ENSURE_BEGIN;
    1715         ULONG         cFunctions = 0;
    1716         PFSYSFUNCTION paFunctions = NULL;
    1717 
    1718         ULONG ulDummy;
    1719 
    1720         HFILE hfExe = pExec->pFile->hf;
    1721         ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]
    1722 
    1723         if (pExec->pDosExeHeader)
    1724             // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
    1725             ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
    1726 
    1727         if (pExec->ulExeFormat == EXEFORMAT_LX)
    1728         {
    1729             // It's a 32bit OS/2 executable
    1730 
    1731             // the number of exported entry points is not stored
    1732             // in the executable header; we have to count them in
    1733             // the entry table
    1734 
    1735             ENSURE(ScanLXEntryTable(pExec, NULL, &cFunctions));
    1736 
    1737             // we now have the number of exported entries; let us
    1738             // build them
    1739 
    1740             if (cFunctions)
    1741             {
    1742                 ULONG cb = sizeof(FSYSFUNCTION) * cFunctions;
    1743 
    1744                 paFunctions = (PFSYSFUNCTION)malloc(cb);
    1745                 if (!paFunctions)
    1746                     ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
    1747 
    1748                 // we rescan the entry table (the cost is not as bad
    1749                 // as it may seem, due to disk caching)
    1750 
    1751                 ENSURE_SAFE(ScanLXEntryTable(pExec, paFunctions, NULL));
    1752 
    1753                 // we now scan the resident name table entries
    1754 
    1755                 ENSURE_SAFE(DosSetFilePtr(hfExe,
    1756                                           pExec->pLXHeader->ulResdNameTblOfs
    1757                                             + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
    1758                                           FILE_BEGIN,
    1759                                           &ulDummy));
    1760 
    1761                 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
    1762 
    1763                 // we now scan the non-resident name table entries,
    1764                 // whose offset is _from the begining of the file_
    1765 
    1766                 ENSURE_SAFE(DosSetFilePtr(hfExe,
    1767                                           pExec->pLXHeader->ulNonResdNameTblOfs,
    1768                                           FILE_BEGIN,
    1769                                           &ulDummy));
    1770 
    1771                 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
    1772             } // end if (cFunctions)
    1773         }
    1774         else if (pExec->ulExeFormat == EXEFORMAT_NE)
    1775         {
    1776             // it's a "new" segmented 16bit executable
    1777 
    1778             // here too the number of exported entry points
    1779             // is not stored in the executable header; we
    1780             // have to count them in the entry table
    1781 
    1782             ENSURE(ScanNEEntryTable(pExec, NULL, &cFunctions));
    1783 
    1784             // we now have the number of exported entries; let us
    1785             // build them
    1786 
    1787             if (cFunctions)
    1788             {
    1789                 // USHORT usOrdinal = 1;
    1790                        // usCurrent = 0;
    1791 
    1792                 paFunctions = (PFSYSFUNCTION)malloc(sizeof(FSYSFUNCTION) * cFunctions);
    1793                 if (!paFunctions)
    1794                     ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
    1795 
    1796                 // we rescan the entry table (the cost is not as bad
    1797                 // as it may seem, due to disk caching)
    1798 
    1799                 ENSURE_SAFE(ScanNEEntryTable(pExec, paFunctions, NULL));
    1800 
    1801                 // we now scan the resident name table entries
    1802 
    1803                 ENSURE_SAFE(DosSetFilePtr(hfExe,
    1804                                           pExec->pNEHeader->usResdNameTblOfs
    1805                                             + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
    1806                                           FILE_BEGIN,
    1807                                           &ulDummy));
    1808 
    1809                 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
    1810 
    1811                 // we now scan the non-resident name table entries,
    1812                 // whose offset is _from the begining of the file_
    1813 
    1814                 ENSURE_SAFE(DosSetFilePtr(hfExe,
    1815                                           pExec->pNEHeader->ulNonResdTblOfs,
    1816                                           FILE_BEGIN,
    1817                                           &ulDummy));
    1818 
    1819                 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
    1820             }
    1821         }
    1822         else
    1823             ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
    1824 
    1825         // no error: output data
    1826         *ppaFunctions = paFunctions;
    1827         *pcFunctions = cFunctions;
    1828 
    1829         ENSURE_FINALLY;
    1830             // if we had an error above, clean up
    1831             free(paFunctions);
    1832         ENSURE_END;
    1833     }
    1834     else
    1835         ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
    1836 
    1837     ENSURE_OK;
    1838 }
    1839 
    1840 /*
    1841  *@@ doshExecFreeExportedFunctions:
    1842  *      frees resources allocated by doshExecQueryExportedFunctions.
    1843  *
    1844  *@@added V0.9.9 (2001-03-11)
    1845  */
    1846 
    1847 APIRET doshExecFreeExportedFunctions(PFSYSFUNCTION paFunctions)
    1848 {
    1849     free(paFunctions);
    1850 
    1851     return (NO_ERROR);
    1852 }
    1853 
    1854 /*
    1855  *@@ doshExecQueryResources:
    1856  *      returns an array of FSYSRESOURCE structures describing all
    1857  *      available resources in the module.
    1858  *
    1859  *      *pcResources receives the no. of items in the array
    1860  *      (not the array size!). Use doshExecFreeResources to clean up.
    1861  *
    1862  *      This returns a standard OS/2 error code, which might be
    1863  *      any of the codes returned by DosSetFilePtr and DosRead.
    1864  *      In addition, this may return:
    1865  *
    1866  *      --  ERROR_NOT_ENOUGH_MEMORY
    1867  *
    1868  *      --  ERROR_INVALID_EXE_SIGNATURE: exe is in a format other
    1869  *          than LX or NE, which is not understood by this function.
    1870  *
    1871  *      Even if NO_ERROR is returned, the array pointer might still
    1872  *      be NULL if the module contains no such data.
    1873  *
    1874  *@@added V0.9.7 (2000-12-18) [lafaix]
    1875  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
    1876  *@@changed V0.9.10 (2001-04-10) [lafaix]: added Win16 and Win386 support
    1877  *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support
    1878  */
    1879 
    1880 APIRET doshExecQueryResources(PEXECUTABLE pExec,     // in: executable from doshExecOpen
    1881                               PFSYSRESOURCE *ppaResources,   // out: res's array
    1882                               PULONG pcResources)    // out: array item count
    1883 {
    1884     if (    (pExec)
    1885          && (    (pExec->ulOS == EXEOS_OS2)
    1886               || (pExec->ulOS == EXEOS_WIN16)
    1887               || (pExec->ulOS == EXEOS_WIN386)
    1888             )
    1889        )
    1890     {
    1891         ENSURE_BEGIN;
    1892         ULONG           cResources = 0;
    1893         PFSYSRESOURCE   paResources = NULL;
    1894 
    1895         HFILE hfExe = pExec->pFile->hf;
    1896         ULONG           ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]
    1897 
    1898         if (pExec->pDosExeHeader)
    1899             // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
    1900             ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
    1901 
    1902         if (pExec->ulExeFormat == EXEFORMAT_LX)
    1903         {
    1904             // 32-bit OS/2 executable:
    1905             PLXHEADER pLXHeader = pExec->pLXHeader;
    1906             if (cResources = pLXHeader->ulResTblCnt)
    1907             {
    1908                 #pragma pack(1)     // V0.9.9 (2001-04-02) [umoeller]
    1909                 struct rsrc32               // Resource Table Entry
    1910                 {
    1911                     unsigned short  type;   // Resource type
    1912                     unsigned short  name;   // Resource name
    1913                     unsigned long   cb;     // Resource size
    1914                     unsigned short  obj;    // Object number
    1915                     unsigned long   offset; // Offset within object
    1916                 } rs;
    1917 
    1918                 struct o32_obj                    // Flat .EXE object table entry
    1919                 {
    1920                     unsigned long   o32_size;     // Object virtual size
    1921                     unsigned long   o32_base;     // Object base virtual address
    1922                     unsigned long   o32_flags;    // Attribute flags
    1923                     unsigned long   o32_pagemap;  // Object page map index
    1924                     unsigned long   o32_mapsize;  // Number of entries in object page map
    1925                     unsigned long   o32_reserved; // Reserved
    1926                 } ot;
    1927                 #pragma pack() // V0.9.9 (2001-04-03) [umoeller]
    1928 
    1929                 ULONG cb = sizeof(FSYSRESOURCE) * cResources;
    1930                 ULONG ulDummy;
    1931                 int i;
    1932                 ULONG ulCurOfs;
    1933 
    1934                 paResources = (PFSYSRESOURCE)malloc(cb);
    1935                 if (!paResources)
    1936                     ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
    1937 
    1938                 memset(paResources, 0, cb); // V0.9.9 (2001-04-03) [umoeller]
    1939 
    1940                 ENSURE_SAFE(DosSetFilePtr(hfExe,
    1941                                           pLXHeader->ulResTblOfs
    1942                                             + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
    1943                                           FILE_BEGIN,
    1944                                           &ulDummy));
    1945 
    1946                 for (i = 0; i < cResources; i++)
    1947                 {
    1948                     ENSURE_SAFE(DosRead(hfExe, &rs, 14, &ulDummy));
    1949 
    1950                     paResources[i].ulID = rs.name;
    1951                     paResources[i].ulType = rs.type;
    1952                     paResources[i].ulSize = rs.cb;
    1953                     paResources[i].ulFlag = rs.obj; // Temp storage for Object
    1954                                                     // number.  Will be filled
    1955                                                     // with resource flag
    1956                                                     // later.
    1957                 }
    1958 
    1959                 for (i = 0; i < cResources; i++)
    1960                 {
    1961                     ULONG ulOfsThis =   pLXHeader->ulObjTblOfs
    1962                                       + ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]
    1963                                       + (   sizeof(ot)
    1964                                           * (paResources[i].ulFlag - 1));
    1965 
    1966                     ENSURE_SAFE(DosSetFilePtr(hfExe,
    1967                                               ulOfsThis,
    1968                                               FILE_BEGIN,
    1969                                               &ulDummy));
    1970 
    1971                     ENSURE_SAFE(DosRead(hfExe, &ot, sizeof(ot), &ulDummy));
    1972 
    1973                     paResources[i].ulFlag  = ((ot.o32_flags & OBJWRITE)
    1974                                                     ? 0
    1975                                                     : RNPURE);
    1976                     paResources[i].ulFlag |= ((ot.o32_flags & OBJDISCARD)
    1977                                                     ? 4096
    1978                                                     : 0);
    1979                     paResources[i].ulFlag |= ((ot.o32_flags & OBJSHARED)
    1980                                                     ? RNMOVE
    1981                                                     : 0);
    1982                     paResources[i].ulFlag |= ((ot.o32_flags & OBJPRELOAD)
    1983                                                     ? RNPRELOAD
    1984                                                     : 0);
    1985                 } // end for
    1986             } // end if (cResources)
    1987         } // end if (pExec->ulExeFormat == EXEFORMAT_LX)
    1988         else if (pExec->ulExeFormat == EXEFORMAT_NE)
    1989         {
    1990             PNEHEADER pNEHeader = pExec->pNEHeader;
    1991 
    1992             if (pExec->ulOS == EXEOS_OS2)
    1993             {
    1994                 // 16-bit OS/2 executable:
    1995                 cResources = pNEHeader->usResSegmCount;
    1996 
    1997                 if (cResources)
    1998                 {
    1999                     #pragma pack(1)     // V0.9.9 (2001-04-02) [umoeller]
    2000                     struct {unsigned short type; unsigned short name;} rti;
    2001                     struct new_seg                          // New .EXE segment table entry
    2002                     {
    2003                         unsigned short      ns_sector;      // File sector of start of segment
    2004                         unsigned short      ns_cbseg;       // Number of bytes in file
    2005                         unsigned short      ns_flags;       // Attribute flags
    2006                         unsigned short      ns_minalloc;    // Minimum allocation in bytes
    2007                     } ns;
    2008                     #pragma pack()
    2009 
    2010                     ULONG cb = sizeof(FSYSRESOURCE) * cResources;
    2011                     ULONG ulDummy;
    2012                     int i;
    2013 
    2014                     paResources = (PFSYSRESOURCE)malloc(cb);
    2015                     if (!paResources)
    2016                         ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
    2017 
    2018                     memset(paResources, 0, cb);     // V0.9.9 (2001-04-03) [umoeller]
    2019 
    2020                     // we first read the resources IDs and types
    2021 
    2022                     ENSURE_SAFE(DosSetFilePtr(hfExe,
    2023                                               pNEHeader->usResTblOfs
    2024                                                 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
    2025                                               FILE_BEGIN,
    2026                                               &ulDummy));
    2027 
    2028                     for (i = 0; i < cResources; i++)
    2029                     {
    2030                         ENSURE_SAFE(DosRead(hfExe, &rti, sizeof(rti), &ulDummy));
    2031 
    2032                         paResources[i].ulID = rti.name;
    2033                         paResources[i].ulType = rti.type;
    2034                     }
    2035 
    2036                     // we then read their sizes and flags
    2037 
    2038                     for (i = 0; i < cResources; i++)
    2039                     {
    2040                         ENSURE_SAFE(DosSetFilePtr(hfExe,
    2041                                                   ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]
    2042                                                     + pNEHeader->usSegTblOfs
    2043                                                     + (sizeof(ns)
    2044                                                     * (  pNEHeader->usSegTblEntries
    2045                                                        - pNEHeader->usResSegmCount
    2046                                                        + i)),
    2047                                                     FILE_BEGIN,
    2048                                                     &ulDummy));
    2049 
    2050                         ENSURE_SAFE(DosRead(hfExe, &ns, sizeof(ns), &ulDummy));
    2051 
    2052                         paResources[i].ulSize = ns.ns_cbseg;
    2053 
    2054                         paResources[i].ulFlag  = (ns.ns_flags & OBJPRELOAD) ? RNPRELOAD : 0;
    2055                         paResources[i].ulFlag |= (ns.ns_flags & OBJSHARED) ? RNPURE : 0;
    2056                         paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? RNMOVE : 0;
    2057                         paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? 4096 : 0;
    2058                     }
    2059                 } // end if (cResources)
    2060             }
    2061             else
    2062             {
    2063                 // 16-bit Windows executable
    2064                 USHORT usAlignShift;
    2065                 ULONG  ulDummy;
    2066 
    2067                 ENSURE(DosSetFilePtr(hfExe,
    2068                                      pNEHeader->usResTblOfs
    2069                                        + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]
    2070                                      FILE_BEGIN,
    2071                                      &ulDummy));
    2072 
    2073                 ENSURE(DosRead(hfExe,
    2074                                &usAlignShift,
    2075                                sizeof(usAlignShift),
    2076                                &ulDummy));
    2077 
    2078                 while (TRUE)
    2079                 {
    2080                     USHORT usTypeID;
    2081                     USHORT usCount;
    2082 
    2083                     ENSURE(DosRead(hfExe,
    2084                                    &usTypeID,
    2085                                    sizeof(usTypeID),
    2086                                    &ulDummy));
    2087 
    2088                     if (usTypeID == 0)
    2089                         break;
    2090 
    2091                     ENSURE(DosRead(hfExe,
    2092                                    &usCount,
    2093                                    sizeof(usCount),
    2094                                    &ulDummy));
    2095 
    2096                     ENSURE(DosSetFilePtr(hfExe,
    2097                                          sizeof(ULONG),
    2098                                          FILE_CURRENT,
    2099                                          &ulDummy));
    2100 
    2101                     cResources += usCount;
    2102 
    2103                     // first pass, skip NAMEINFO table
    2104                     ENSURE(DosSetFilePtr(hfExe,
    2105                                          usCount*6*sizeof(USHORT),
    2106                                          FILE_CURRENT,
    2107                                          &ulDummy));
    2108                 }
    2109 
    2110                 if (cResources)
    2111                 {
    2112                     USHORT usCurrent = 0;
    2113                     ULONG cb = sizeof(FSYSRESOURCE) * cResources;
    2114 
    2115                     paResources = (PFSYSRESOURCE)malloc(cb);
    2116                     if (!paResources)
    2117                         ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
    2118 
    2119                     memset(paResources, 0, cb);
    2120 
    2121                     ENSURE_SAFE(DosSetFilePtr(hfExe,
    2122                                               pNEHeader->usResTblOfs
    2123                                                 + ulNewHeaderOfs,
    2124                                               FILE_BEGIN,
    2125                                               &ulDummy));
    2126 
    2127                     ENSURE_SAFE(DosRead(hfExe,
    2128                                         &usAlignShift,
    2129                                         sizeof(usAlignShift),
    2130                                         &ulDummy));
    2131 
    2132                     while (TRUE)
    2133                     {
    2134                         USHORT usTypeID;
    2135                         USHORT usCount;
    2136                         int i;
    2137 
    2138                         ENSURE_SAFE(DosRead(hfExe,
    2139                                             &usTypeID,
    2140                                             sizeof(usTypeID),
    2141                                             &ulDummy));
    2142 
    2143                         if (usTypeID == 0)
    2144                             break;
    2145 
    2146                         ENSURE_SAFE(DosRead(hfExe,
    2147                                             &usCount,
    2148                                             sizeof(usCount),
    2149                                             &ulDummy));
    2150 
    2151                         ENSURE_SAFE(DosSetFilePtr(hfExe,
    2152                                                   sizeof(ULONG),
    2153                                                   FILE_CURRENT,
    2154                                                   &ulDummy));
    2155 
    2156                         // second pass, read NAMEINFO table
    2157                         for (i = 0; i < usCount; i++)
    2158                         {
    2159                             USHORT usLength,
    2160                                    usFlags,
    2161                                    usID;
    2162 
    2163                             ENSURE_SAFE(DosSetFilePtr(hfExe,
    2164                                                       sizeof(USHORT),
    2165                                                       FILE_CURRENT,
    2166                                                       &ulDummy));
    2167 
    2168                             ENSURE_SAFE(DosRead(hfExe,
    2169                                                 &usLength,
    2170                                                 sizeof(USHORT),
    2171                                                 &ulDummy));
    2172                             ENSURE_SAFE(DosRead(hfExe,
    2173                                                 &usFlags,
    2174                                                 sizeof(USHORT),
    2175                                                 &ulDummy));
    2176                             ENSURE_SAFE(DosRead(hfExe,
    2177                                                 &usID,
    2178                                                 sizeof(USHORT),
    2179                                                 &ulDummy));
    2180 
    2181                             ENSURE_SAFE(DosSetFilePtr(hfExe,
    2182                                                       2*sizeof(USHORT),
    2183                                                       FILE_CURRENT,
    2184                                                       &ulDummy));
    2185 
    2186                             // !!! strings ids and types not handled yet
    2187                             // !!! 15th bit is used to denotes strings
    2188                             // !!! offsets [lafaix]
    2189                             paResources[usCurrent].ulType = usTypeID ^ 0x8000;
    2190                             paResources[usCurrent].ulID = usID ^ 0x8000;
    2191                             paResources[usCurrent].ulSize = usLength << usAlignShift;
    2192                             paResources[usCurrent].ulFlag = usFlags & 0x70;
    2193 
    2194                             usCurrent++;
    2195                         }
    2196                     }
    2197                 }
    2198             }
    2199         } // end else if (pExec->ulExeFormat == EXEFORMAT_NE)
    2200         else
    2201             ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
    2202 
    2203         *ppaResources = paResources;
    2204         *pcResources = cResources;
    2205 
    2206         ENSURE_FINALLY;
    2207             // if we had an error above, clean up
    2208             free(paResources);
    2209         ENSURE_END;
    2210     }
    2211     else
    2212         ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
    2213 
    2214     ENSURE_OK;
    2215 }
    2216 
    2217 /*
    2218  *@@ doshExecFreeResources:
    2219  *      frees resources allocated by doshExecQueryResources.
    2220  *
    2221  *@@added V0.9.7 (2000-12-18) [lafaix]
    2222  */
    2223 
    2224 APIRET doshExecFreeResources(PFSYSRESOURCE paResources)
    2225 {
    2226     free(paResources);
    2227     return (NO_ERROR);
    2228 }
    2229 
    2230 /*
    2231  *@@ doshLoadLXMaps:
    2232  *      loads the three main LX maps into the given
    2233  *      EXECUTABLE structure.
    2234  *
    2235  *      This loads:
    2236  *
    2237  *      1)  the LX resource table;
    2238  *
    2239  *      2)  the LX object table;
    2240  *
    2241  *      3)  the LX object _page_ table (object map).
    2242  *
    2243  *      Note that this is not automatically called
    2244  *      by doshExecOpen to save time, since the LX
    2245  *      maps are not needed for all the other exe
    2246  *      functions.
    2247  *
    2248  *      This returns:
    2249  *
    2250  *      --  NO_ERROR: all three LX maps were loaded,
    2251  *          and pExec->fLXMapsLoaded was set to TRUE.
    2252  *
    2253  *      --  ERROR_INVALID_PARAMETER
    2254  *
    2255  *      --  ERROR_INVALID_EXE_SIGNATURE: pExec does
    2256  *          not specify an LX executable.
    2257  *
    2258  *      --  ERROR_NO_DATA: at least one of the structs
    2259  *          does not exist.
    2260  *
    2261  *      --  ERROR_NOT_ENOUGH_MEMORY
    2262  *
    2263  *      plus the error codes of doshReadAt.
    2264  *
    2265  *      Call doshFreeLXMaps to clean up explicitly, but
    2266  *      that func automatically gets called by doshExecClose.
    2267  *
    2268  *@@added V0.9.16 (2001-12-08) [umoeller]
    2269  */
    2270 
    2271 APIRET doshLoadLXMaps(PEXECUTABLE pExec)
    2272 {
    2273     APIRET arc;
    2274 
    2275     PLXHEADER pLXHeader;
    2276 
    2277     if (!pExec)
    2278         arc = ERROR_INVALID_PARAMETER;
    2279     else if (pExec->fLXMapsLoaded)
    2280         // already loaded:
    2281         arc = NO_ERROR;
    2282     else if (    (pExec->ulExeFormat != EXEFORMAT_LX)
    2283               || (!(pLXHeader = pExec->pLXHeader))
    2284             )
    2285         arc = ERROR_INVALID_EXE_SIGNATURE;
    2286     else
    2287     {
    2288         PXFILE pFile = pExec->pFile;
    2289         ULONG ulNewHeaderOfs = 0;
    2290         ULONG cb;
    2291 
    2292         if (pExec->pDosExeHeader)
    2293             // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
    2294             ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
    2295 
    2296         // resource table
    2297         if (    (!(arc = doshAllocArray(pLXHeader->ulResTblCnt,
    2298                                         sizeof(RESOURCETABLEENTRY),
    2299                                         (PBYTE*)&pExec->pRsTbl,
    2300                                         &cb)))
    2301              && (!(arc = doshReadAt(pFile,
    2302                                     pLXHeader->ulResTblOfs
    2303                                       + ulNewHeaderOfs,
    2304                                     &cb,
    2305                                     (PBYTE)pExec->pRsTbl)))
    2306             )
    2307         {
    2308             // object table
    2309             if (    (!(arc = doshAllocArray(pLXHeader->ulObjCount,
    2310                                             sizeof(OBJECTTABLEENTRY),
    2311                                             (PBYTE*)&pExec->pObjTbl,
    2312                                             &cb)))
    2313                  && (!(arc = doshReadAt(pFile,
    2314                                         pLXHeader->ulObjTblOfs
    2315                                           + ulNewHeaderOfs,
    2316                                         &cb,
    2317                                         (PBYTE)pExec->pObjTbl)))
    2318                )
    2319             {
    2320                 // object page table
    2321                 if (    (!(arc = doshAllocArray(pLXHeader->ulPageCount,
    2322                                                 sizeof(OBJECTPAGETABLEENTRY),
    2323                                                 (PBYTE*)&pExec->pObjPageTbl,
    2324                                                 &cb)))
    2325                      && (!(arc = doshReadAt(pFile,
    2326                                             pLXHeader->ulObjPageTblOfs
    2327                                               + ulNewHeaderOfs,
    2328                                             &cb,
    2329                                             (PBYTE)pExec->pObjPageTbl)))
    2330                    )
    2331                 {
    2332                 }
    2333             }
    2334         }
    2335 
    2336         if (!arc)
    2337             pExec->fLXMapsLoaded = TRUE;
    2338         else
    2339             doshFreeLXMaps(pExec);
    2340     }
    2341 
    2342     return (arc);
    2343 }
    2344 
    2345 /*
    2346  *@@ doshFreeLXMaps:
    2347  *      frees only the LX maps allocated by doshLoadLXMaps.
    2348  *      This gets called automatically by doshExecClose.
    2349  *
    2350  *@@added V0.9.16 (2001-12-08) [umoeller]
    2351  */
    2352 
    2353 VOID doshFreeLXMaps(PEXECUTABLE pExec)
    2354 {
    2355     FREE(pExec->pRsTbl);
    2356     FREE(pExec->pObjTbl);
    2357     FREE(pExec->pObjPageTbl);
    2358     pExec->fLXMapsLoaded = FALSE;
    2359 }
    2360 
    2361 /*
    2362  *@@ doshLoadOS2NEMaps:
    2363  *
    2364  *      This works only if
    2365  *
    2366  *      --  ulExeFormat == EXEFORMAT_NE and
    2367  *
    2368  *      --  ulOS == EXEOS_OS2,
    2369  *
    2370  *      but not with Win16 NE executables.
    2371  *
    2372  *@@added V0.9.16 (2001-12-08) [umoeller]
    2373  */
    2374 
    2375 APIRET doshLoadOS2NEMaps(PEXECUTABLE pExec)
    2376 {
    2377     APIRET arc;
    2378 
    2379     PNEHEADER pNEHeader;
    2380 
    2381     if (!pExec)
    2382         arc = ERROR_INVALID_PARAMETER;
    2383     else if (pExec->fOS2NEMapsLoaded)
    2384         // already loaded:
    2385         arc = NO_ERROR;
    2386     else if (    (pExec->ulExeFormat != EXEFORMAT_NE)
    2387               || (pExec->ulOS != EXEOS_OS2)
    2388               || (!(pNEHeader = pExec->pNEHeader))
    2389             )
    2390         arc = ERROR_INVALID_EXE_SIGNATURE;
    2391     else
    2392     {
    2393         PXFILE pFile = pExec->pFile;
    2394         ULONG ulNewHeaderOfs = 0;
    2395         ULONG cb;
    2396 
    2397         if (pExec->pDosExeHeader)
    2398             // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]
    2399             ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;
    2400 
    2401         // resource table
    2402         if (    (!(arc = doshAllocArray(pNEHeader->usResSegmCount,
    2403                                         sizeof(OS2NERESTBLENTRY),
    2404                                         (PBYTE*)&pExec->paOS2NEResTblEntry,
    2405                                         &cb)))
    2406              && (!(arc = doshReadAt(pFile,
    2407                                     pNEHeader->usResTblOfs
    2408                                       + ulNewHeaderOfs,
    2409                                     &cb,
    2410                                     (PBYTE)pExec->paOS2NEResTblEntry)))
    2411             )
    2412         {
    2413             // resource segments
    2414             if (    (!(arc = doshAllocArray(pNEHeader->usResSegmCount,
    2415                                             sizeof(OS2NESEGMENT),
    2416                                             (PBYTE*)&pExec->paOS2NESegments,
    2417                                             &cb)))
    2418                  && (!(arc = doshReadAt(pFile,
    2419                                         pNEHeader->usResTblOfs
    2420                                           + ulNewHeaderOfs
    2421                                           - cb, // pNEHeader->usResSegmCount * sizeof(struct new_seg)
    2422                                         &cb,
    2423                                         (PBYTE)pExec->paOS2NESegments)))
    2424                 )
    2425             {
    2426             }
    2427         }
    2428 
    2429         if (!arc)
    2430             pExec->fOS2NEMapsLoaded = TRUE;
    2431         else
    2432             doshFreeNEMaps(pExec);
    2433     }
    2434 
    2435     return (arc);
    2436 }
    2437 
    2438 /*
    2439  *@@ doshFreeNEMaps:
    2440  *
    2441  *@@added V0.9.16 (2001-12-08) [umoeller]
    2442  */
    2443 
    2444 VOID doshFreeNEMaps(PEXECUTABLE pExec)
    2445 {
    2446     FREE(pExec->paOS2NEResTblEntry);
    2447     FREE(pExec->paOS2NESegments);
    2448     pExec->fOS2NEMapsLoaded = FALSE;
    2449 }
    2450 
    2451 /*
    2452  *@@ doshExecClose:
    2453  *      this closes an executable opened with doshExecOpen.
    2454  *      Always call this function if NO_ERROR was returned by
    2455  *      doshExecOpen.
    2456  *
    2457  *      This automaticall calls doshFreeLXMaps.
    2458  *
    2459  *@@added V0.9.0 [umoeller]
    2460  *@@changed V0.9.16 (2001-12-08) [umoeller]: fixed memory leaks
    2461  *@@changed V0.9.16 (2001-12-08) [umoeller]: changed prototype to null the pExec ptr
    2462  */
    2463 
    2464 APIRET doshExecClose(PEXECUTABLE *ppExec)
    2465 {
    2466     APIRET arc = NO_ERROR;
    2467     PEXECUTABLE pExec;
    2468     if (    (ppExec)
    2469          && (pExec = *ppExec)
    2470        )
    2471     {
    2472         char **papsz[] =
    2473             {
    2474                 (char**)&pExec->pDosExeHeader,
    2475                 (char**)&pExec->pNEHeader,
    2476                 (char**)&pExec->pLXHeader,
    2477                 (char**)&pExec->pPEHeader,
    2478 
    2479                 &pExec->pszDescription,
    2480                 &pExec->pszVendor,
    2481                 &pExec->pszVersion,
    2482                 &pExec->pszInfo,
    2483 
    2484                 &pExec->pszBuildDateTime,
    2485                 &pExec->pszBuildMachine,
    2486                 &pExec->pszASD,
    2487                 &pExec->pszLanguage,
    2488                 &pExec->pszCountry,
    2489                 &pExec->pszRevision,
    2490                 &pExec->pszUnknown,
    2491                 &pExec->pszFixpak
    2492             };
    2493         ULONG ul;
    2494 
    2495         doshFreeLXMaps(pExec);
    2496         doshFreeNEMaps(pExec);
    2497 
    2498         // fixed the memory leaks with the missing fields,
    2499         // turned this into a loop
    2500         for (ul = 0;
    2501              ul < sizeof(papsz) / sizeof(papsz[0]);
    2502              ul++)
    2503         {
    2504             PSZ pThis;
    2505             if (pThis = *papsz[ul])
    2506             {
    2507                 free(pThis);
    2508                 pThis = NULL;
    2509             }
    2510         }
    2511 
    2512         doshClose(&pExec->pFile);
    2513 
    2514         free(pExec);
    2515         *ppExec = NULL;
    2516     }
    2517     else
    2518         arc = ERROR_INVALID_PARAMETER;
    2519 
    2520     return (arc);
    2521352}
    2522353
Note: See TracChangeset for help on using the changeset viewer.