Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1803 lines
53 KiB

  1. #include <dos.h>
  2. #include <stdio.h>
  3. #include <sys\types.h>
  4. #include <sys\stat.h>
  5. #include <io.h>
  6. #include <fcntl.h>
  7. #include <string.h>
  8. #include <ctype.h>
  9. #include <malloc.h>
  10. //#include <tchar.h>
  11. #ifdef RLDOS
  12. #include "dosdefs.h"
  13. #else
  14. #include <windows.h>
  15. #include "windefs.h"
  16. #endif
  17. #include "restok.h"
  18. #include "exe2res.h"
  19. #include "newexe.h"
  20. /* ----- Function prototypes ----- */
  21. static void PrepareFiles( PSTR, PSTR, PSTR);
  22. static void ReadSegmentTable( void);
  23. static void ComputeResTableSize( void);
  24. static void ComputeStringOffsets( void);
  25. static void BuildResTable( void);
  26. static void SegsWrite( WORD);
  27. static DWORD RelocCopy( WORD);
  28. static void ResWrite( WORD);
  29. static void SetEXEHeaderFlags( void);
  30. static void RewriteTables( void);
  31. static void CopyCodeViewInfo( FILE *, FILE *);
  32. static void OutPutError( char *);
  33. static void ResTableBufferInit( WORD);
  34. static void ResTableBufferFree( void);
  35. static WORD GetAlign( DWORD, WORD);
  36. static LONG MoveFilePos( FILE *, WORD, WORD);
  37. static WORD RoundUp( LONG, WORD);
  38. static WORD AlignFilePos( FILE *, WORD, BOOL);
  39. static WORD ReadExeOldHeader( FILE *, LONG, LONG *) ;
  40. static WORD ReadExeNewHeader( FILE *, LONG, LONG, LONG *);
  41. static WORD ExtractExeResources( FILE *, FILE *, LONG , LONG);
  42. static void ExtractString( FILE *, FILE *, LONG);
  43. static WORD WriteResFromExe( FILE *,
  44. FILE *,
  45. LONG,
  46. RESNAMEINFO,
  47. RESTYPEINFO,
  48. WORD);
  49. static TYPINFO *AddResType( CHAR *, WORD);
  50. static PSTR MyMakeStr( PSTR);
  51. static SHORT MyRead( FILE *, PSTR, WORD);
  52. static SHORT MyWrite( FILE *, PSTR, WORD);
  53. static LONG MySeek( FILE *, LONG, WORD);
  54. static void MyCopy( FILE *, FILE *, DWORD);
  55. static int ProcessBinFile( void);
  56. static PSTR RcAlloc( WORD);
  57. static void AddResToResFile( TYPINFO *, RESINFO *);
  58. static void AddDefaultTypes( void);
  59. static void GetOrdOrName( unsigned int *, unsigned char *);
  60. /* ----- Version functions (added for 3.1) ----- */
  61. static void RcPutWord( unsigned int);
  62. static int RcPutString( char *);
  63. /* ----- Module variables ----- */
  64. static struct exe_hdr OldExe;
  65. static struct new_exe NewExe;
  66. static struct new_seg *pSegTable;
  67. static PSTR pResTable;
  68. static PSTR pResNext;
  69. static FILE * fhInput;
  70. static FILE * fhOutput;
  71. static FILE * fhBin;
  72. static DWORD dwMaxFilePos;
  73. static DWORD dwNewExe;
  74. static WORD wPreloadOffset;
  75. static WORD wPreloadLength;
  76. static WORD wResTableOffset;
  77. static WORD wSegTableLen;
  78. static WORD wResTableLen;
  79. static BYTE zeros[ NUMZEROS] = "";
  80. static DWORD dwExeEndFile;
  81. static WORD fMultipleDataSegs;
  82. //.........................................................................
  83. int ExtractResFromExe16A( CHAR *szInputExe, CHAR *szOutputRes, WORD wFilter)
  84. {
  85. QuitT( IDS_NO16RESWINYET, NULL, NULL);
  86. #ifdef 0
  87. WORD wResult = (WORD)-1;
  88. LONG lPosNewHdr;
  89. LONG lPosResourceTable;
  90. LONG lFileLen;
  91. FILE *fExeFile;
  92. FILE *fResFile;
  93. struct _stat ExeStats;
  94. /* initialize */
  95. wResult = IDERR_SUCCESS;
  96. /* open file for reading */
  97. if ((fExeFile = FOPEN(szInputExe, "rb" )) == NULL ) {
  98. wResult = IDERR_OPENFAIL;
  99. }
  100. if ((fResFile = FOPEN(szOutputRes, "wb" )) == NULL ) {
  101. wResult = IDERR_OPENFAIL;
  102. }
  103. /* get file length */
  104. if (wResult == IDERR_SUCCESS) {
  105. _stat(szInputExe , &ExeStats );
  106. lFileLen = ExeStats.st_size;
  107. }
  108. /* read old header, verify contents, and get positon of new header */
  109. if (wResult == IDERR_SUCCESS) {
  110. wResult = ReadExeOldHeader( fExeFile, lFileLen, &lPosNewHdr );
  111. }
  112. /* read new header, verify contents, & get position of resource table */
  113. if (wResult == IDERR_SUCCESS)
  114. wResult = ReadExeNewHeader(
  115. fExeFile,
  116. lFileLen,
  117. lPosNewHdr,
  118. &lPosResourceTable
  119. );
  120. wResult = ExtractExeResources( fExeFile , fResFile, lPosResourceTable , lFileLen);
  121. return ( wResult);
  122. #endif // 0
  123. }
  124. //....................................................................
  125. int BuildExeFromRes16A(
  126. CHAR *pstrDest,
  127. CHAR *pstrRes,
  128. CHAR *pstrSource )
  129. {
  130. QuitT( IDS_NO16WINRESYET, NULL, NULL);
  131. #ifdef 0
  132. SHORT nResTableDelta;
  133. fSortSegments = TRUE;
  134. /* Get a memory block to use for MyCopy\(\) */
  135. PrepareFiles(pstrSource, pstrDest, pstrRes);
  136. ProcessBinFile();
  137. /* Read the segment table */
  138. ReadSegmentTable();
  139. /* Compute the length of the resource table */
  140. ComputeResTableSize();
  141. /* Compute string offsets for non-ordinal type and resource names */
  142. ComputeStringOffsets();
  143. /* Build the resource table */
  144. BuildResTable();
  145. /* Now go back to the beginning */
  146. MySeek(fhInput, 0L, 0);
  147. /* Copy from input to output up to the segment table */
  148. MyCopy(fhInput, fhOutput, dwNewExe + (DWORD)NewExe.ne_segtab);
  149. /* Copy the segment table */
  150. MyCopy(fhInput, fhOutput, (long)wSegTableLen);
  151. /* Save a pointer to the start of the resource table */
  152. wResTableOffset = (unsigned)(MySeek(fhOutput, 0L, 1) - dwNewExe);
  153. /* Write our resource table out */
  154. if (wResTableLen) {
  155. MyWrite(fhOutput, pResTable, wResTableLen);
  156. }
  157. /* Now we\'re looking at the beginning of the resident name table */
  158. MySeek(fhInput, (LONG)NewExe.ne_restab + dwNewExe, 0);
  159. /* Copy all the other tables \(they must fall between the resident
  160. * names table and the non-resident names table.
  161. */
  162. MyCopy(fhInput, fhOutput,
  163. NewExe.ne_nrestab - (LONG)NewExe.ne_restab - dwNewExe);
  164. /* Copy the nonresident name table as well */
  165. MyCopy(fhInput, fhOutput, (LONG)NewExe.ne_cbnrestab);
  166. /* Compute new pointers in new exe header */
  167. NewExe.ne_rsrctab = wResTableOffset;
  168. nResTableDelta = wResTableOffset + wResTableLen - NewExe.ne_restab;
  169. NewExe.ne_restab += nResTableDelta;
  170. NewExe.ne_modtab += nResTableDelta;
  171. NewExe.ne_imptab += nResTableDelta;
  172. NewExe.ne_enttab += nResTableDelta;
  173. NewExe.ne_nrestab += nResTableDelta;
  174. #ifdef VERBOSE
  175. /* Tell the user what we\'re doing */
  176. if (fVerbose && fSortSegments) {
  177. fprintf(errfh, "Sorting preload segments and"
  178. " resources into fast-load section\n");
  179. if (fBootModule)
  180. fprintf(errfh,"This is a boot module; the .DEF file"
  181. " is assumed to be correct!\n");
  182. }
  183. #endif
  184. /* If we\'re sorting segments, write preload segments and resources
  185. * into a section separate from the load on call stuff.
  186. */
  187. if (fSortSegments) {
  188. /* Save the start of the preload section */
  189. wPreloadOffset = AlignFilePos(fhOutput, NewExe.ne_align, TRUE);
  190. /* Write PRELOAD segments and resources */
  191. SegsWrite(DO_PRELOAD);
  192. ResWrite(DO_PRELOAD);
  193. /* Compute the properly aligned length of the preload section */
  194. wPreloadLength = AlignFilePos(fhOutput, NewExe.ne_align, TRUE) -
  195. wPreloadOffset;
  196. /* Now do the LOADONCALL segs and resources */
  197. SegsWrite(DO_LOADONCALL);
  198. ResWrite(DO_LOADONCALL);
  199. }
  200. /* If we\'re not sorting segments, just write them into a common block */
  201. else {
  202. /* Write the segs and resources */
  203. SegsWrite(DO_PRELOAD | DO_LOADONCALL);
  204. ResWrite(DO_PRELOAD | DO_LOADONCALL);
  205. }
  206. #ifdef SETEXEFLAGS
  207. /* Set flags and other values in the EXE header */
  208. SetEXEHeaderFlags();
  209. #endif
  210. /* Rewrite the new exe header, segment table and resource table */
  211. RewriteTables();
  212. ResTableBufferFree();
  213. /* Handle CodeView info */
  214. CopyCodeViewInfo(fhInput, fhOutput);
  215. /* Seek to end of output file and issue truncating write */
  216. MySeek(fhOutput, 0L, 2);
  217. MyWrite(fhOutput, zeros, 0);
  218. fclose(fhInput);
  219. fclose(fhOutput);
  220. fclose(fhBin);
  221. FreePTypInfo(pTypInfo);
  222. pTypInfo=NULL;
  223. MyFree(pSegTable);
  224. pSegTable=NULL;
  225. return TRUE;
  226. #endif // 0
  227. }
  228. /*
  229. *
  230. * ReadExeOldHeader\( fExeFile, lFileLen, plPosNewHdr \) : WORD;
  231. *
  232. * fExeFile file handle of .exe file being read
  233. * lFileLen length of file
  234. * plPosNewHdr pointer to file position of new header
  235. *
  236. * This function reads the old header from an executable file, checks to be
  237. * sure that it is a valid header, and saves the position of the file\'s
  238. * new header.
  239. *
  240. * This function returns IDERR_SUCCESS if there are no errors, or a non-zero
  241. * error code if there are.
  242. *
  243. */
  244. static WORD ReadExeOldHeader(
  245. FILE *fExeFile,
  246. LONG lFileLen,
  247. LONG *plPosNewHdr )
  248. {
  249. LONG lPos;
  250. WORD cb;
  251. EXEHDR ehOldHeader;
  252. WORD wResult;
  253. /* initialize */
  254. wResult = IDERR_SUCCESS;
  255. lPos = fseek( fExeFile, 0L, SEEK_SET );
  256. if (lPos != 0L)
  257. wResult = IDERR_READFAIL;
  258. if (wResult == IDERR_SUCCESS) {
  259. cb = fread( (void *) &ehOldHeader, sizeof( EXEHDR) , 1, fExeFile );
  260. if (cb != 1 ) {
  261. wResult = IDERR_READFAIL;
  262. } else if (ehOldHeader.ehSignature != OLDEXESIGNATURE) {
  263. wResult = IDERR_FILETYPEBAD;
  264. } else if (ehOldHeader.ehPosNewHdr < sizeof(EXEHDR)) {
  265. wResult = IDERR_EXETYPEBAD;
  266. } else if ( ehOldHeader.ehPosNewHdr > (LONG)(lFileLen - sizeof(NEWHDR)) ) {
  267. wResult = IDERR_EXETYPEBAD;
  268. } else {
  269. *plPosNewHdr = ehOldHeader.ehPosNewHdr;
  270. }
  271. }
  272. return wResult;
  273. }
  274. /*
  275. *
  276. * ReadExeNewHeader\( fExeFile, lFileLen, lPosNewHdr, plPosResourceTable \) : WORD;
  277. *
  278. * fExeFile file handle of .exe file being read
  279. * lFileLen length of file
  280. * lPosNewHdr file position of new header
  281. * plPosResourceTable pointer to file position of resource table
  282. *
  283. * This function reads the new header from an executable file, checks to be
  284. * sure that it is a valid header, and saves the position of the file\'s
  285. * resource table.
  286. *
  287. * This function returns IDERR_SUCCESS if there are no errors, or a non-zero
  288. * error code if there are.
  289. *
  290. */
  291. static WORD ReadExeNewHeader(
  292. FILE *fExeFile,
  293. LONG lFileLen,
  294. long lPosNewHdr,
  295. LONG *plPosResourceTable )
  296. {
  297. WORD wResult;
  298. WORD cb;
  299. LONG lPos;
  300. NEWHDR nhNewHeader;
  301. /* initialize */
  302. wResult = IDERR_SUCCESS;
  303. fseek( fExeFile, lPosNewHdr, SEEK_SET );
  304. lPos = ftell( fExeFile );
  305. if (lPos == (long) -1 || lPos > lFileLen || lPos != lPosNewHdr) {
  306. wResult = IDERR_READFAIL;
  307. } else {
  308. cb = fread( ( void *)&nhNewHeader, sizeof(nhNewHeader) , 1, fExeFile );
  309. if (cb != 1 ) {
  310. wResult = IDERR_READFAIL;
  311. } else if (nhNewHeader.nhSignature != NEWEXESIGNATURE) {
  312. wResult = IDERR_FILETYPEBAD;
  313. } else if (nhNewHeader.nhExeType != WINDOWSEXE) {
  314. wResult = IDERR_EXETYPEBAD;
  315. } else if (nhNewHeader.nhExpVer < 0x0300) {
  316. wResult = IDERR_WINVERSIONBAD;
  317. } else if (nhNewHeader.nhoffResourceTable == 0) {
  318. wResult = IDERR_RESTABLEBAD;
  319. } else {
  320. *plPosResourceTable = lPosNewHdr + nhNewHeader.nhoffResourceTable;
  321. }
  322. }
  323. return wResult;
  324. }
  325. /*
  326. *
  327. * ReadExeTable\( fExeFile , lPosResourcTable \) : WORD;
  328. *
  329. * fExeFile file handle of .exe file being read
  330. *
  331. * This function reads through the entries in an .exe file\'s resource table,
  332. * identifies any icons in that table, and saves the file offsets of the data
  333. * for those icons. This function expects the initial file position to point
  334. * to the first entry in the resource table.
  335. *
  336. * This function returns IDERR_SUCCESS if there are no errors, or a non-zero
  337. * error code if there are.
  338. *
  339. */
  340. static WORD ExtractExeResources(
  341. FILE *fExeFile,
  342. FILE *fResFile,
  343. LONG lPosResourceTable,
  344. LONG lFileLen )
  345. {
  346. BOOL fLoop;
  347. WORD wResult;
  348. WORD cb;
  349. LONG lPos;
  350. WORD wShiftCount;
  351. wResult = IDERR_SUCCESS;
  352. // posistion file pointer at resource table
  353. fseek( fExeFile, lPosResourceTable, SEEK_SET );
  354. lPos = ftell(fExeFile);
  355. if (lPos == (LONG) -1 || lPos > lFileLen || lPos != lPosResourceTable) {
  356. return IDERR_READFAIL ;
  357. }
  358. if (wResult == IDERR_SUCCESS) {
  359. cb = fread( (void *) &wShiftCount, sizeof(wShiftCount), 1 , fExeFile );
  360. }
  361. if (cb != 1 ) {
  362. return IDERR_READFAIL;
  363. }
  364. if (wShiftCount > 16) {
  365. return IDERR_RESTABLEBAD;
  366. }
  367. /* initialize */
  368. wResult = IDERR_SUCCESS;
  369. fLoop = TRUE;
  370. /* loop through entries in resource table */
  371. while (fLoop == TRUE) {
  372. WORD cb;
  373. WORD iFile;
  374. RESTYPEINFO rt;
  375. /* read RESTYPEINFO */
  376. cb = fread( (void *)&rt, sizeof(rt), 1, fExeFile );
  377. if (cb != 1 ) {
  378. wResult = IDERR_READFAIL;
  379. break;
  380. }
  381. if ( rt.rtType == 0 )
  382. break;
  383. // now get all the resource of this type
  384. for (
  385. iFile = 0;
  386. iFile<rt.rtCount && wResult==IDERR_SUCCESS;
  387. iFile++
  388. ) {
  389. RESNAMEINFO rn;
  390. cb = fread( (void *) &rn, sizeof(rn) , 1 , fExeFile );
  391. if (cb != 1 ) {
  392. wResult = IDERR_READFAIL;
  393. }
  394. WriteResFromExe( fExeFile, fResFile,lPos, rn, rt, wShiftCount );
  395. }
  396. fLoop = (rt.rtType != 0) && (wResult == IDERR_SUCCESS);
  397. }
  398. FCLOSE(fExeFile);
  399. FCLOSE(fResFile);
  400. return wResult;
  401. }
  402. //.................................................................
  403. static WORD WriteResFromExe(
  404. FILE *fExeFile,
  405. FILE *fResFile,
  406. LONG lPos,
  407. RESNAMEINFO ResNameInfo,
  408. RESTYPEINFO ResTypeInfo,
  409. WORD wShiftCount )
  410. {
  411. LONG lCurPos;
  412. LONG lResPos;
  413. LONG wLength;
  414. LONG wTmpLength;
  415. wLength = (LONG) ResNameInfo.rnLength << wShiftCount;
  416. lCurPos = ftell( fExeFile );
  417. // position file pointer at resouce location
  418. lResPos = (LONG) ResNameInfo.rnOffset << wShiftCount;
  419. fseek( fExeFile, lResPos, SEEK_SET );
  420. if ( ResTypeInfo.rtType & 0x8000) {
  421. PutByte( fResFile, (BYTE) 0xff, NULL );
  422. PutWord( fResFile, (WORD)(ResTypeInfo.rtType & 0x7FFF), NULL);
  423. } else {
  424. ExtractString(fExeFile,fResFile,lPos+ResTypeInfo.rtType);
  425. }
  426. if ( ResNameInfo.rnID & 0x8000 ) {
  427. PutByte( fResFile, (BYTE) 0xff, NULL );
  428. PutWord( fResFile, (WORD)(ResNameInfo.rnID & 0x7fFF), NULL);
  429. } else {
  430. ExtractString(fExeFile,fResFile,lPos+ResNameInfo.rnID);
  431. }
  432. PutWord( fResFile, ResNameInfo.rnFlags , NULL );
  433. PutdWord( fResFile, (LONG) wLength, NULL );
  434. wTmpLength = wLength;
  435. // now write the actual data
  436. fseek( fExeFile, lResPos, SEEK_SET );
  437. ReadInRes( fExeFile, fResFile, &wTmpLength );
  438. fseek( fExeFile, lCurPos, SEEK_SET );
  439. return 0;
  440. }
  441. //..................................................................
  442. static void ExtractString( FILE *fExeFile, FILE *fResFile, LONG lPos)
  443. {
  444. BYTE n,b;
  445. fseek(fExeFile, lPos, SEEK_SET);
  446. n=GetByte(fExeFile, NULL);
  447. for (;n--; ) {
  448. b=GetByte(fExeFile, NULL);
  449. PutByte(fResFile, (CHAR) b, NULL);
  450. }
  451. PutByte(fResFile, (CHAR) 0, NULL);
  452. }
  453. // Modifications for RLTOOLS
  454. // Currently we dont support any dynamic flags
  455. BOOL fBootModule = FALSE;
  456. BOOL fSortSegments = TRUE;
  457. TYPINFO *pTypInfo = NULL;
  458. static void FreePTypInfo( TYPINFO *pTypInfo)
  459. {
  460. RESINFO * pRes, *pRTemp;
  461. TYPINFO * pTItemp;
  462. while (pTypInfo) {
  463. pRes = pTypInfo->pres;
  464. while (pRes) {
  465. pRTemp = pRes->next;
  466. MyFree(pRes->name);
  467. MyFree(pRes);
  468. pRes = pRTemp;
  469. }
  470. pTItemp = pTypInfo->next;
  471. MyFree(pTypInfo->type);
  472. MyFree(pTypInfo);
  473. pTypInfo = pTItemp;
  474. }
  475. }
  476. /* ----- Helper functions ----- */
  477. /* PrepareFiles
  478. * Prepares the EXE files \(new and old\) for writing and verifies
  479. * that all is well.
  480. * Exits on error, returns if processing should continue.
  481. */
  482. static void PrepareFiles(
  483. PSTR pstrSource,
  484. PSTR pstrDest,
  485. PSTR pstrRes )
  486. {
  487. /* Open the .EXE file the linker gave us */
  488. if ( (fhInput = FOPEN(pstrSource, "rb" )) == NULL ) {
  489. OutPutError("Unable to open Exe Source File");
  490. }
  491. if ((fhBin = FOPEN(pstrRes, "rb")) == NULL ) {
  492. OutPutError("Unable to open Resource File");
  493. }
  494. /* Read the old format EXE header */
  495. MyRead(fhInput, (PSTR)&OldExe, sizeof (OldExe));
  496. /* Make sure its really an EXE file */
  497. if (OldExe.e_magic != EMAGIC) {
  498. OutPutError("Invalid .EXE file" );
  499. }
  500. /* Make sure theres a new EXE header floating around somewhere */
  501. if (!(dwNewExe = OldExe.e_lfanew)) {
  502. OutPutError("Not a Microsoft Windows format .EXE file");
  503. }
  504. /* Go find the new .EXE header */
  505. MySeek(fhInput, dwNewExe, 0);
  506. MyRead(fhInput, (PSTR)&NewExe, sizeof (NewExe));
  507. /* Check version numbers */
  508. if (NewExe.ne_ver < 4) {
  509. OutPutError("File not created by LINK");
  510. }
  511. /* Were there linker errors? */
  512. if (NewExe.ne_flags & NEIERR) {
  513. OutPutError("Errors occurred when linking file.");
  514. }
  515. /* Make sure that this program\'s EXETYPE is WINDOWS \(2\) not OS/2 \(1\) */
  516. if (NewExe.ne_exetyp != 2)
  517. OutPutError("The EXETYPE of the program is not WINDOWS.\n"
  518. "(Make sure the .DEF file is correct.");
  519. #ifdef VERBOSE
  520. if (fVerbose) {
  521. fprintf(errfh, "\n");
  522. }
  523. #endif
  524. /* Open the all new executable file */
  525. if ( (fhOutput = FOPEN( pstrDest, "wb")) == NULL ) {
  526. OutPutError("Unable to create destination");
  527. }
  528. }
  529. /* ReadSegmentTable
  530. * Reads the segment table from the file.
  531. */
  532. static void ReadSegmentTable( void)
  533. {
  534. struct new_seg* pSeg;
  535. WORD i;
  536. MySeek(fhInput, (LONG)NewExe.ne_segtab + dwNewExe, 0);
  537. if ((wSegTableLen = NewExe.ne_cseg * sizeof (struct new_seg)) > 0) {
  538. pSegTable = (struct new_seg *)RcAlloc (wSegTableLen);
  539. MyRead(fhInput, (PSTR)pSegTable, wSegTableLen);
  540. /* See if we have more than one data segment */
  541. fMultipleDataSegs = 0;
  542. for (pSeg = pSegTable, i = NewExe.ne_cseg ; i ; --i, ++pSeg) {
  543. if ((pSeg->ns_flags & NSTYPE) == NSDATA) {
  544. ++fMultipleDataSegs;
  545. }
  546. }
  547. if (fMultipleDataSegs) {
  548. --fMultipleDataSegs;
  549. }
  550. } else {
  551. pSegTable = NULL;
  552. }
  553. }
  554. /* ComputeResTableSize
  555. * Computes the size of the resource table by enumerating all the
  556. * resources currently in the linked lists.
  557. */
  558. static void ComputeResTableSize( void)
  559. {
  560. TYPINFO **pPrev;
  561. TYPINFO *pType;
  562. RESINFO *pRes;
  563. /* Start with the minimum overhead size of the resource table. This
  564. * is the resource alignment count and the zero WORD terminating the
  565. * table. This is necessary so that we put the correct file offset
  566. * in for the string offsets to named resources.
  567. */
  568. wResTableLen = RESTABLEHEADER;
  569. /* Loop over type table, computing the fixed length of the
  570. * resource table, removing unused type entries.
  571. */
  572. pPrev = &pTypInfo;
  573. dwMaxFilePos = 0L;
  574. while (pType = *pPrev) {
  575. if (pRes = pType->pres) {
  576. /* Size of type entry */
  577. wResTableLen += sizeof (struct rsrc_typeinfo);
  578. while (pRes) {
  579. /* Size of resource entry */
  580. wResTableLen += sizeof (struct rsrc_nameinfo);
  581. if (pType->next || pRes->next) {
  582. dwMaxFilePos += pRes->size;
  583. }
  584. pRes = pRes->next;
  585. }
  586. pPrev = &pType->next;
  587. } else {
  588. *pPrev = pType->next;
  589. MyFree(pType->type);
  590. MyFree(pType);
  591. }
  592. }
  593. }
  594. /* ComputeStringOffsets
  595. * Computes offsets to strings from named resource and types.
  596. */
  597. static void ComputeStringOffsets( void)
  598. {
  599. TYPINFO *pType;
  600. RESINFO *pRes;
  601. /* Loop over type table, computing string offsets for non-ordinal
  602. * type and resource names.
  603. */
  604. pType = pTypInfo;
  605. while (pType) {
  606. pRes = pType->pres;
  607. /* Is there an ordinal? */
  608. if (pType->typeord) {
  609. /* Mark the ordinal */
  610. pType->typeord |= RSORDID;
  611. /* Flush the string name */
  612. MyFree(pType->type);
  613. pType->type = NULL;
  614. } else if (pType->type) { /* is there a type string? */
  615. /* Yes, compute location of the type string */
  616. pType->typeord = wResTableLen;
  617. wResTableLen += strlen(pType->type) + 1;
  618. }
  619. while (pRes) {
  620. /* Is there an ordinal? */
  621. if (pRes->nameord) {
  622. /* Mark the ordinal */
  623. pRes->nameord |= RSORDID;
  624. /* Flush the string name */
  625. MyFree(pRes->name);
  626. pRes->name = NULL;
  627. }
  628. /* Is there a resource name? */
  629. else if (pRes->name) {
  630. /* Yes, compute location of the resource string */
  631. pRes->nameord = wResTableLen;
  632. wResTableLen += strlen(pRes->name) + 1;
  633. }
  634. pRes = pRes->next;
  635. }
  636. pType = pType->next;
  637. }
  638. }
  639. /* BuildResTable
  640. * Builds the local memory image of the resource table.
  641. */
  642. static void BuildResTable( void)
  643. {
  644. TYPINFO *pType;
  645. RESINFO *pRes;
  646. /* Check to see if we have any resources. If not, just omit the table */
  647. if (wResTableLen > RESTABLEHEADER) {
  648. /* Set up the temporary resource table buffer */
  649. ResTableBufferInit(wResTableLen);
  650. /* Alignment shift count
  651. * \(we default here to the segment alignment count\)
  652. */
  653. RcPutWord(NewExe.ne_align);
  654. pType = pTypInfo;
  655. while (pType) {
  656. /* output the type and number of resources */
  657. RcPutWord(pType->typeord); /* DW type id */
  658. RcPutWord(pType->nres); /* DW #resources for this type */
  659. RcPutWord(0); /* DD type procedure */
  660. RcPutWord(0);
  661. /* output flags and space for the file offset for each resource */
  662. pRes = pType->pres;
  663. while (pRes) {
  664. pRes->poffset = (WORD *)pResNext;
  665. RcPutWord(0); /* DW file offset */
  666. RcPutWord(0); /* DW resource size */
  667. pRes->flags |= NSDPL;
  668. RcPutWord(pRes->flags ); /* DW flags */
  669. RcPutWord(pRes->nameord ); /* DW name id */
  670. RcPutWord(0); /* DW handle */
  671. RcPutWord(0); /* DW usage or minalloc */
  672. pRes = pRes->next;
  673. }
  674. pType = pType->next;
  675. }
  676. /* Null entry terminates table */
  677. RcPutWord(0);
  678. /* Output type and name strings for non-ordinal resource types
  679. * and names */
  680. pType = pTypInfo;
  681. while (pType) {
  682. /* Dump out any strings for this type */
  683. if (pType->type && !(pType->typeord & RSORDID)) {
  684. RcPutString(pType->type);
  685. }
  686. pRes = pType->pres;
  687. while (pRes) {
  688. if (pRes->name && !(pRes->nameord & RSORDID))
  689. RcPutString(pRes->name);
  690. pRes = pRes->next;
  691. }
  692. pType = pType->next;
  693. }
  694. } else
  695. wResTableLen = 0;
  696. }
  697. /* SegsWrite
  698. * Copies segments to the file. This routine will do only preload,
  699. * only the load on call, or both types of segments depending on
  700. * the flags.
  701. */
  702. static void SegsWrite( WORD wFlags)
  703. {
  704. WORD wExtraPadding;
  705. WORD i;
  706. static struct new_seg *pSeg;
  707. DWORD dwSegSize;
  708. DWORD dwWriteSize;
  709. WORD wTemp;
  710. WORD wcbDebug;
  711. /* We only need extra padding in the preload section.
  712. * Note that when wFlags == DO_PRELOAD | DO_LOADONCALL, we DON\'T
  713. * need extra padding because this is NOT a preload section.
  714. * \(hence the \'==\' instead of an \'&\'\)
  715. */
  716. wExtraPadding = (wFlags == DO_PRELOAD);
  717. /* Copy segment data for each segment, fixed and preload only */
  718. for (i = 1, pSeg = pSegTable; i <= NewExe.ne_cseg; i++, pSeg++) {
  719. /* If there\'s no data in segment, skip it here */
  720. if (!pSeg->ns_sector) {
  721. continue;
  722. }
  723. /* Force some segments to be preload if doing preload resources */
  724. if ((wFlags & DO_PRELOAD) && !fBootModule) {
  725. char *reason = NULL;
  726. /* Check various conditions that would force preloading */
  727. if (i == (unsigned)(NewExe.ne_csip >> 16)) {
  728. reason = "Entry point";
  729. }
  730. if (!(pSeg->ns_flags & NSMOVE)) {
  731. reason = "Fixed";
  732. }
  733. if (pSeg->ns_flags & NSDATA) {
  734. reason = "Data";
  735. }
  736. if (!(pSeg->ns_flags & NSDISCARD)) {
  737. reason = "Non-discardable";
  738. }
  739. /* If this segment must be preload and the segment is not already
  740. * marked as such, warn the user and set it.
  741. */
  742. if (reason && !(pSeg->ns_flags & NSPRELOAD)) {
  743. #ifdef VERBOSE
  744. fprintf(errfh,
  745. "RC: warning RW4002: %s segment %d set to PRELOAD\n",
  746. reason, i);
  747. #endif
  748. pSeg->ns_flags |= NSPRELOAD;
  749. }
  750. }
  751. /* Skip this segment if it doesn\'t match the current mode */
  752. wTemp = pSeg->ns_flags & NSPRELOAD ? DO_PRELOAD : DO_LOADONCALL;
  753. if (!(wTemp & wFlags)) {
  754. continue;
  755. }
  756. /* Get the true segment length. A zero length implies 64K */
  757. if (pSeg->ns_cbseg) {
  758. dwSegSize = pSeg->ns_cbseg;
  759. } else {
  760. dwSegSize = 0x10000L;
  761. }
  762. #ifdef VERBOSE
  763. if (fVerbose)
  764. fprintf(errfh, "Copying segment %d (%lu bytes)\n", i, dwSegSize);
  765. #endif
  766. /* Align the segment correctly and pad the file to match */
  767. MoveFilePos(fhInput, pSeg->ns_sector, NewExe.ne_align);
  768. pSeg->ns_sector = AlignFilePos(fhOutput, NewExe.ne_align,
  769. wExtraPadding);
  770. /* Copy the segment */
  771. MyCopy(fhInput, fhOutput, dwSegSize);
  772. /* Pad out all segments in the preload area to their minimum
  773. * memory allocation size so that KERNEL doesn\'t have to realloc
  774. * the segment.
  775. */
  776. if (wExtraPadding && pSeg->ns_cbseg != pSeg->ns_minalloc) {
  777. /* A minalloc size of zero implies 64K */
  778. if (!pSeg->ns_minalloc) {
  779. dwWriteSize = 0x10000L - pSeg->ns_cbseg;
  780. } else {
  781. dwWriteSize = pSeg->ns_minalloc - pSeg->ns_cbseg;
  782. }
  783. /* Add in to total size of segment */
  784. dwSegSize += dwWriteSize;
  785. /* Set the segment table size to this new size */
  786. pSeg->ns_cbseg = pSeg->ns_minalloc;
  787. /* Pad the file */
  788. while (dwWriteSize) {
  789. dwWriteSize -= MyWrite(fhOutput,
  790. zeros,
  791. (WORD)(dwWriteSize > (DWORD) NUMZEROS
  792. ? NUMZEROS : dwWriteSize));
  793. }
  794. }
  795. /* Copy the relocation information */
  796. if (pSeg->ns_flags & NSRELOC) {
  797. /* Copy the relocation stuff */
  798. dwSegSize += RelocCopy(i);
  799. /* Segment + padding + relocations can\'t be >64K for preload
  800. * segments.
  801. */
  802. if (fSortSegments && (pSeg->ns_flags & NSPRELOAD) &&
  803. dwSegSize > 65536L) {
  804. #ifdef VERBOSE
  805. fprintf(errfh,
  806. "RC : fatal error RW1031: Segment %d and its\n"
  807. " relocation information is too large for load\n"
  808. " optimization. Make the segment LOADONCALL or\n"
  809. " rerun RC using the -K switch if the segment must\n"
  810. " be preloaded.\n", i);
  811. #endif
  812. }
  813. }
  814. /* Copy any per-segment debug information */
  815. if (pSeg->ns_flags & NSDEBUG) {
  816. MyRead(fhInput, (PSTR)&wcbDebug, sizeof (WORD));
  817. MyWrite(fhOutput, (PSTR)&wcbDebug, sizeof (WORD));
  818. MyCopy(fhInput, fhOutput, (LONG)wcbDebug);
  819. }
  820. }
  821. }
  822. /* RelocCopy
  823. * Copys all the relocation records for a given segment.
  824. * Also checks for invalid fixups.
  825. */
  826. static DWORD RelocCopy( WORD wSegNum)
  827. {
  828. WORD wNumReloc;
  829. struct new_rlc RelocRec;
  830. WORD i;
  831. BYTE byFixupType;
  832. BYTE byFixupFlags;
  833. WORD wDGROUP;
  834. /* Get the number of relocations */
  835. MyRead(fhInput, (PSTR)&wNumReloc, sizeof (WORD));
  836. MyWrite(fhOutput, (PSTR)&wNumReloc, sizeof (WORD));
  837. /* Get the automatic data segment */
  838. wDGROUP = NewExe.ne_autodata;
  839. /* Copy and verify all relocations */
  840. for (i = 0 ; i < wNumReloc ; ++i) {
  841. /* Copy the record */
  842. MyRead(fhInput, (PSTR)&RelocRec, sizeof (RelocRec));
  843. MyWrite(fhOutput, (PSTR)&RelocRec, sizeof (RelocRec));
  844. /* Validate it only if necessary */
  845. if ((NewExe.ne_flags & (NENOTP | NESOLO)) ||
  846. wSegNum == wDGROUP || fMultipleDataSegs) {
  847. continue;
  848. }
  849. /* Bad fixups are fixups to DGROUP in code segments in apps
  850. * that can be multi-instanced. Since we can\'t fix up locations
  851. * that are different from instance to instance in shared code
  852. * segments, we have to warn the user. We only warn because this
  853. * may be allowable if the app only allows a single instance of
  854. * itself to run.
  855. */
  856. byFixupType = (BYTE) (RelocRec.nr_stype & NRSTYP);
  857. byFixupFlags = (BYTE) (RelocRec.nr_flags & NRRTYP);
  858. #ifdef VERBOSE
  859. if ((byFixupType == NRSSEG || byFixupType == NRSOFF) &&
  860. byFixupFlags == NRRINT &&
  861. RelocRec.nr_union.nr_intref.nr_segno == wDGROUP)
  862. fprintf(errfh,
  863. "RC : warning RW4005: Segment %d (offset %04X) contains a\n"
  864. " relocation record pointing to the automatic\n"
  865. " data segment. This will cause the program to crash\n"
  866. " if the instruction being fixed up is executed in a\n"
  867. " multi-instance application. If this fixup is\n"
  868. " necessary, the program should be restricted to run\n"
  869. " only a single instance.\n", wSegNum, RelocRec.nr_soff);
  870. #endif
  871. }
  872. return wNumReloc * sizeof (struct new_rlc);
  873. }
  874. /* ResWrite
  875. * Copies resources to the file. This routine will do only the preload,
  876. * only the load on call, or both types of resources depending on the
  877. * flags.
  878. */
  879. static void ResWrite( WORD wFlags)
  880. {
  881. WORD wExtraPadding;
  882. WORD wTemp;
  883. WORD wResAlign;
  884. TYPINFO *pType;
  885. RESINFO *pRes;
  886. /* If we have no resource table, just ignore this */
  887. if (!wResTableLen) {
  888. return;
  889. }
  890. /* We only need extra padding in the preload section.
  891. * Note that when wFlags == DO_PRELOAD | DO_LOADONCALL, we DON\'T
  892. * need extra padding because this is NOT a preload section.
  893. * \(hence the \'==\' instead of an \'&\'\)
  894. */
  895. wExtraPadding = (wFlags == DO_PRELOAD);
  896. /* Compute resource alignment. Note that the alignment is not the
  897. * same as the segment alignment ONLY IF there is no segment sorting
  898. * and some resources cannot be reached with the current segment
  899. * align count.
  900. */
  901. wResAlign = NewExe.ne_align;
  902. if (!fSortSegments) {
  903. /* Compute the needed alignment */
  904. dwMaxFilePos += MySeek(fhOutput, 0L, 2);
  905. wResAlign = GetAlign(dwMaxFilePos, NewExe.ne_align);
  906. #ifdef VERBOSE
  907. if (fVerbose)
  908. fprintf(errfh, "Resources will be aligned on %d byte boundaries\n",
  909. 1 << wResAlign);
  910. #endif
  911. /* Point back to the start of the local memory resource table */
  912. pResNext = pResTable;
  913. RcPutWord(wResAlign);
  914. }
  915. /* Output contents associated with each resource */
  916. for (pType = pTypInfo ; pType; pType = pType->next) {
  917. for (pRes = pType->pres ; pRes ; pRes = pRes->next) {
  918. /* Make sure this is the right kind of resource */
  919. wTemp = pRes->flags & RNPRELOAD ? DO_PRELOAD : DO_LOADONCALL;
  920. if (!(wTemp & wFlags)) {
  921. continue;
  922. }
  923. /* Give some info to the user */
  924. #ifdef VERBOSE
  925. if (fVerbose) {
  926. fprintf(errfh, "Writing resource ");
  927. if (pRes->name && !(pRes->nameord & RSORDID)) {
  928. fprintf(errfh, "%s", pRes->name);
  929. } else {
  930. fprintf(errfh, "%d", pRes->nameord & 0x7FFF);
  931. }
  932. if (pType->type && !(pType->typeord & RSORDID)) {
  933. fprintf(errfh, ".%s", pType->type);
  934. } else {
  935. fprintf(errfh, ".%d", pType->typeord & 0x7FFF);
  936. }
  937. fprintf(errfh, " (%lu bytes)\n", pRes->size);
  938. fflush(errfh);
  939. }
  940. #endif
  941. /* Copy the resource from the RES file to the EXE file */
  942. MySeek(fhBin, (long)pRes->BinOffset, 0);
  943. *(pRes->poffset)++ =
  944. AlignFilePos(fhOutput, wResAlign, wExtraPadding);
  945. *(pRes->poffset) = RoundUp(pRes->size, wResAlign);
  946. MyCopy(fhBin, fhOutput, pRes->size);
  947. }
  948. }
  949. /* Compute the end of the EXE file thus far for the CV info */
  950. dwExeEndFile = AlignFilePos(fhOutput, wResAlign, wExtraPadding);
  951. }
  952. #ifdef SETEXEFLAGS
  953. /* SetEXEHeaderFlags
  954. * Sets necessary flags and values in the EXE header.
  955. */
  956. static void SetEXEHeaderFlags( void)
  957. {
  958. /* Tell loader we initialized previously unused fields */
  959. if (NewExe.ne_ver == 4) {
  960. NewExe.ne_rev = 2;
  961. }
  962. /* Set command line values into the header */
  963. NewExe.ne_expver = expWinVer;
  964. NewExe.ne_swaparea = swapArea;
  965. /* Set the preload section values */
  966. if (fSortSegments) {
  967. /* Set the new fastload section values */
  968. NewExe.ne_gangstart = wPreloadOffset;
  969. NewExe.ne_ganglength = wPreloadLength;
  970. #ifdef VERBOSE
  971. if (fVerbose)
  972. fprintf(errfh, "Fastload area is %ld bytes at offset 0x%lX.\n",
  973. (LONG)wPreloadLength << NewExe.ne_align,
  974. (LONG)wPreloadOffset << NewExe.ne_align);
  975. }
  976. #endif
  977. /* Clear all the flags */
  978. NewExe.ne_flags &=
  979. ~(NELIM32|NEMULTINST|NEEMSLIB|NEPRIVLIB|NEPRELOAD);
  980. /* Set appropriate flags */
  981. if (fLim32) {
  982. NewExe.ne_flags |= NELIM32;
  983. }
  984. if (fMultInst) {
  985. NewExe.ne_flags |= NEMULTINST;
  986. }
  987. if (fEmsLibrary) {
  988. NewExe.ne_flags |= NEEMSLIB;
  989. }
  990. if (fPrivateLibrary) {
  991. NewExe.ne_flags |= NEPRIVLIB;
  992. }
  993. if (fProtOnly) {
  994. NewExe.ne_flags |= NEPROT;
  995. }
  996. if (fSortSegments && wPreloadLength) {
  997. NewExe.ne_flagsother |= NEPRELOAD;
  998. }
  999. NewExe.ne_flags |= NEWINAPI;
  1000. }
  1001. #endif
  1002. /* RewriteTables
  1003. * Rewrites the EXE header and the resource and segment tables
  1004. * with their newly-updated information.
  1005. */
  1006. static void RewriteTables( void)
  1007. {
  1008. /* Write the new EXE header */
  1009. MySeek(fhOutput, (LONG)dwNewExe, 0);
  1010. MyWrite(fhOutput, (PSTR)&NewExe, sizeof (NewExe));
  1011. /* Seek to the start of the segment table */
  1012. MySeek(fhOutput, dwNewExe + (LONG)NewExe.ne_segtab, 0);
  1013. MyWrite(fhOutput, (PSTR)pSegTable, wSegTableLen);
  1014. /* Seek to and write the resource table */
  1015. if (wResTableLen) {
  1016. MySeek(fhOutput, dwNewExe + (LONG)NewExe.ne_rsrctab, 0);
  1017. MyWrite(fhOutput, pResTable, wResTableLen);
  1018. }
  1019. }
  1020. /* CopyCodeViewInfo
  1021. * Copies CodeView info to the new EXE file and relocates it if
  1022. * necessary. This routine is designed to work with the
  1023. * DNRB-style info as well as NBxx info where x is a digit.
  1024. */
  1025. static void CopyCodeViewInfo( FILE *fhInput, FILE *fhOutput)
  1026. {
  1027. unsigned long dwcb;
  1028. unsigned int i;
  1029. CVINFO cvinfo;
  1030. CVSECTBL cvsectbl;
  1031. /* See if old format \(DNRB\) symbols present at end of input file
  1032. * If they are, relocate the table to the new file position and
  1033. * fix up the file-position dependent offsets.
  1034. */
  1035. dwcb = MySeek( fhInput, -(signed long)sizeof (CVINFO), 2);
  1036. MyRead( fhInput, (char *)&cvinfo, sizeof (cvinfo));
  1037. if (*(unsigned long *)cvinfo.signature == CV_OLD_SIG) {
  1038. dwcb -= cvinfo.secTblOffset;
  1039. MySeek( fhInput, cvinfo.secTblOffset, 0);
  1040. MyRead( fhInput, (char *)&cvsectbl, sizeof (cvsectbl));
  1041. dwcb -= sizeof (cvsectbl);
  1042. for (i = 0 ; i < 5 ; ++i) {
  1043. cvsectbl.secOffset[i] -= cvinfo.secTblOffset;
  1044. }
  1045. cvinfo.secTblOffset = dwExeEndFile;
  1046. for (i = 0 ; i < 5 ; ++i) {
  1047. cvsectbl.secOffset[i] += cvinfo.secTblOffset;
  1048. }
  1049. MySeek( fhOutput, cvinfo.secTblOffset, 0);
  1050. MyWrite( fhOutput, (char *)&cvsectbl, sizeof (cvsectbl));
  1051. MyCopy( fhInput, fhOutput, dwcb);
  1052. MyWrite( fhOutput, (char *)&cvinfo, sizeof (cvinfo));
  1053. }
  1054. /* Check for new format \(NBxx\) symbols. Since these symbols are
  1055. * file-position independent, just copy them over; no need to
  1056. * fix them up as with the old format symbols.
  1057. */
  1058. else if (*(unsigned short int *)cvinfo.signature == CV_SIGNATURE &&
  1059. isdigit(cvinfo.signature[2]) && isdigit(cvinfo.signature[3])) {
  1060. MySeek( fhOutput, 0L, 2);
  1061. MySeek( fhInput, -cvinfo.secTblOffset, 2);
  1062. MyCopy( fhInput, fhOutput, cvinfo.secTblOffset);
  1063. }
  1064. }
  1065. /* OutPutError
  1066. * Outputs a fatal error message and exits.
  1067. */
  1068. static void OutPutError( char *szMessage)
  1069. {
  1070. QuitA( 0, szMessage, NULL);
  1071. }
  1072. /* ResTableBufferInit
  1073. * Creates the resource table buffer and points global pointers
  1074. * to it. This table is written to so that we can modifiy it
  1075. * before writing it out to the EXE file.
  1076. */
  1077. static void ResTableBufferInit( WORD wLen)
  1078. {
  1079. /* Allocate local storage for resource table */
  1080. pResTable = RcAlloc (wLen);
  1081. /* Point to the start of the table for the PutXXXX\(\) */
  1082. pResNext = pResTable;
  1083. }
  1084. /* ResTableBufferFree
  1085. * Frees the temporary storage for resource table
  1086. */
  1087. static void ResTableBufferFree( void)
  1088. {
  1089. /* Nuke the table */
  1090. MyFree(pResTable);
  1091. }
  1092. /* GetAlign
  1093. * Computes the alignment value needed for the given maximum file
  1094. * position passed in. This is done by computing the number of
  1095. * bits to be shifted left in order to represent the maximum
  1096. * file position in 16 bits.
  1097. */
  1098. static WORD GetAlign( DWORD dwMaxpos, WORD wAlign)
  1099. {
  1100. DWORD dwMask;
  1101. WORD i;
  1102. /* Compute the initial mask based on the input align value */
  1103. dwMask = 0xFFFFL;
  1104. for (i = 0; i < wAlign ; ++i) {
  1105. dwMask <<= 1;
  1106. dwMask |= 1;
  1107. }
  1108. /* See if we need to increase the default mask to reach the maximum
  1109. * file position.
  1110. */
  1111. while (dwMaxpos > dwMask) {
  1112. dwMask <<= 1;
  1113. dwMask |= 1;
  1114. ++wAlign;
  1115. }
  1116. /* Return the new alignment */
  1117. return wAlign;
  1118. }
  1119. /* MoveFilePos
  1120. * Moves the file pointer to the position indicated by wPos, using the
  1121. * align shift count wAlign. This converts the WORD value wPos
  1122. * into a LONG value by shifting left wAlign bits.
  1123. */
  1124. static LONG MoveFilePos( FILE *fh, WORD wPos, WORD wAlign)
  1125. {
  1126. return MySeek(fh, ((LONG)wPos) << wAlign, 0);
  1127. }
  1128. /* RoundUp
  1129. * Computes the value that should go into a 16 bit entry in an EXE
  1130. * table by rounding up to the next boundary determined by the
  1131. * passed in alignment value.
  1132. */
  1133. static WORD RoundUp( LONG lValue, WORD wAlign)
  1134. {
  1135. LONG lMask;
  1136. /* Get all the default mask of all ones except in the bits below the
  1137. * alignment value.
  1138. */
  1139. lMask = -1L;
  1140. lMask <<= wAlign;
  1141. /* Now round up using this mask */
  1142. lValue += ~lMask;
  1143. lValue &= lMask;
  1144. /* Return as a 16 bit value */
  1145. return ((WORD) (lValue >> (LONG) wAlign));
  1146. }
  1147. /* AlignFilePos
  1148. * Computes a correctly aligned file position based on the current
  1149. * alignment.
  1150. */
  1151. static WORD AlignFilePos( FILE *fh, WORD wAlign, BOOL fPreload)
  1152. {
  1153. LONG lCurPos;
  1154. LONG lNewPos;
  1155. LONG lMask;
  1156. WORD nbytes;
  1157. WORD wNewAlign;
  1158. /* If we\'re in the preload section, we have tougher alignment
  1159. * restrictions: We have to be at least 32-byte aligned and have
  1160. * at least 32 bytes between objects for arena headers. It turns
  1161. * out that this feature is not really used in KERNEL but could be
  1162. * implemented someday.
  1163. */
  1164. if (fPreload && wAlign < PRELOAD_ALIGN) {
  1165. wNewAlign = PRELOAD_ALIGN;
  1166. } else {
  1167. wNewAlign = wAlign;
  1168. }
  1169. /* Get the current file position */
  1170. lCurPos = MySeek(fh, 0L, 1);
  1171. /* Compute the new position by rounding up to the align value */
  1172. lMask = -1L;
  1173. lMask <<= wNewAlign;
  1174. lNewPos = lCurPos + ~lMask;
  1175. lNewPos &= lMask;
  1176. /* We have to have at least 32 bytes between objects in the preload
  1177. * section.
  1178. */
  1179. if (fPreload) {
  1180. while (lNewPos - lCurPos < PRELOAD_MINPADDING) {
  1181. lNewPos += 1 << wNewAlign;
  1182. }
  1183. }
  1184. /* Check to see if it\'s representable in 16 bits */
  1185. if (lNewPos >= (0x10000L << wAlign)) {
  1186. OutPutError(".EXE file too large; relink with higher /ALIGN value");
  1187. }
  1188. /* Write stuff out to file until new position reached */
  1189. if (lNewPos > lCurPos) {
  1190. /* Compute number of bytes to write out and write them out */
  1191. nbytes = (WORD) (lNewPos - lCurPos);
  1192. while (nbytes) {
  1193. nbytes -= MyWrite( fh,
  1194. zeros,
  1195. (WORD)(nbytes > NUMZEROS ? NUMZEROS : nbytes));
  1196. }
  1197. }
  1198. /* Seek to and return this new position */
  1199. return (WORD)(MySeek(fh, lNewPos, (WORD) 0) >> (LONG) wAlign);
  1200. }
  1201. /*--------------------------------------------------------------------------*/
  1202. /* */
  1203. /* AddResType\(\) - */
  1204. /* */
  1205. /*--------------------------------------------------------------------------*/
  1206. static TYPINFO *AddResType( CHAR *s, WORD n )
  1207. {
  1208. TYPINFO *pType;
  1209. if (pType = pTypInfo) {
  1210. while (TRUE) {
  1211. /* search for resource type, return if already exists */
  1212. if ((s && !strcmp(s, pType->type)) || (!s && n && pType->typeord == n)) {
  1213. return (pType);
  1214. } else if (!pType->next) {
  1215. break;
  1216. } else {
  1217. pType = pType->next;
  1218. }
  1219. }
  1220. /* if not in list, add space for it */
  1221. pType->next = (TYPINFO *) RcAlloc(sizeof(TYPINFO));
  1222. pType = pType->next;
  1223. } else {
  1224. /* allocate space for resource list */
  1225. pTypInfo = (TYPINFO *)RcAlloc (sizeof(TYPINFO));
  1226. pType = pTypInfo;
  1227. }
  1228. /* fill allocated space with name and ordinal, and clear the resources
  1229. of this type */
  1230. pType->type = MyMakeStr(s);
  1231. pType->typeord = n;
  1232. pType->nres = 0;
  1233. pType->pres = NULL;
  1234. pType->next = NULL;
  1235. return (pType);
  1236. }
  1237. /*--------------------------------------------------------------------------*/
  1238. /* */
  1239. /* GetOrdOrName\(\) - */
  1240. /* */
  1241. /*--------------------------------------------------------------------------*/
  1242. static void GetOrdOrName( unsigned int *pint, unsigned char *szstr)
  1243. {
  1244. unsigned char c1;
  1245. /* read the first character of the identifier */
  1246. MyRead(fhBin, &c1, sizeof(unsigned char));
  1247. /* if the first character is 0xff, the id is an ordinal, else a string */
  1248. if (c1 == 0xFF) {
  1249. MyRead(fhBin, (PSTR)pint, sizeof (int));
  1250. } else { /* string */
  1251. *pint = 0;
  1252. *szstr++ = c1;
  1253. do {
  1254. MyRead( fhBin, szstr, 1);
  1255. }
  1256. while (*szstr++ != 0);
  1257. }
  1258. }
  1259. /*--------------------------------------------------------------------------*/
  1260. /* */
  1261. /* AddDefaultTypes\(\) - */
  1262. /* */
  1263. /*--------------------------------------------------------------------------*/
  1264. static void AddDefaultTypes( void)
  1265. {
  1266. AddResType( "CURSOR", ID_RT_GROUP_CURSOR);
  1267. AddResType( "ICON", ID_RT_GROUP_ICON);
  1268. AddResType( "BITMAP", ID_RT_BITMAP);
  1269. AddResType( "MENU", ID_RT_MENU);
  1270. AddResType( "DIALOG", ID_RT_DIALOG);
  1271. AddResType( "STRINGTABLE", ID_RT_STRING);
  1272. AddResType( "FONTDIR", ID_RT_FONTDIR);
  1273. AddResType( "FONT", ID_RT_FONT);
  1274. AddResType( "ACCELERATORS", ID_RT_ACCELERATORS);
  1275. AddResType( "RCDATA", ID_RT_RCDATA);
  1276. AddResType( "VERSIONINFO", ID_RT_VERSION);
  1277. }
  1278. /*--------------------------------------------------------------------------*/
  1279. /* */
  1280. /* ProcessBinFile\(\) - */
  1281. /* */
  1282. /*--------------------------------------------------------------------------*/
  1283. static int ProcessBinFile( void)
  1284. {
  1285. unsigned int ord;
  1286. unsigned char tokstr[64];
  1287. RESINFO *pRes;
  1288. TYPINFO *pType;
  1289. long curloc;
  1290. long eofloc;
  1291. WORD wResType;
  1292. /* initialize for reading .RES file */
  1293. AddDefaultTypes();
  1294. eofloc = MySeek(fhBin, 0L, 2); /* get file size */
  1295. curloc = MySeek(fhBin, 0L, 0); /* go to beginning of file */
  1296. /* while there are more resources in the .RES file */
  1297. while (curloc < eofloc) {
  1298. #ifdef VERBOSE
  1299. if (fVerbose) {
  1300. fprintf(errfh, ".");
  1301. fflush(errfh);
  1302. }
  1303. #endif
  1304. /* find the resource type of the next resource */
  1305. GetOrdOrName(&ord, tokstr);
  1306. if (!ord) {
  1307. pType = AddResType(tokstr, 0);
  1308. } else {
  1309. pType = AddResType(NULL, (WORD)ord);
  1310. }
  1311. if (!pType) {
  1312. break;
  1313. }
  1314. /* Save the type number so we can see if we want to skip it later */
  1315. wResType = ord;
  1316. /* find the identifier \(name\) of the resource */
  1317. GetOrdOrName(&ord, tokstr);
  1318. pRes = (RESINFO *)RcAlloc (sizeof(RESINFO));
  1319. if (!ord) {
  1320. pRes->name = MyMakeStr(tokstr);
  1321. } else {
  1322. pRes->nameord = ord;
  1323. }
  1324. /* read the flag bits */
  1325. MyRead(fhBin, (PSTR)&pRes->flags, sizeof(int));
  1326. /* Clear the old DISCARD bits. */
  1327. pRes->flags &= 0x1FFF;
  1328. /* find the size of the resource */
  1329. MyRead(fhBin, (PSTR)&pRes->size, sizeof(long));
  1330. /* save the position of the resource for when we add it to the .EXE */
  1331. pRes->BinOffset = (long)MySeek(fhBin, 0L, 1);
  1332. /* skip the resource to the next resource header */
  1333. curloc = MySeek(fhBin, (long)pRes->size, 1);
  1334. /* add the resource to the resource lists. We don\'t add name
  1335. * tables. They are an unnecessary 3.0 artifact.
  1336. */
  1337. if (wResType != ID_RT_NAMETABLE) {
  1338. AddResToResFile(pType, pRes);
  1339. } else {
  1340. MyFree(pRes->name);
  1341. MyFree(pRes);
  1342. }
  1343. }
  1344. return 1;
  1345. }
  1346. /*--------------------------------------------------------------------------*/
  1347. /* */
  1348. /* AddResToResFile\(pType, pRes\) */
  1349. /* */
  1350. /* Parameters: */
  1351. /* pType : Pointer to Res Type */
  1352. /* pRes : Pointer to resource */
  1353. /* */
  1354. /*--------------------------------------------------------------------------*/
  1355. static void AddResToResFile( TYPINFO *pType, RESINFO *pRes)
  1356. {
  1357. RESINFO *p;
  1358. p = pType->pres;
  1359. /* add resource to end of resource list for this type */
  1360. if (p) {
  1361. while (p->next) {
  1362. p = p->next;
  1363. }
  1364. p->next = pRes;
  1365. p->next->next = NULL;
  1366. } else {
  1367. pType->pres = pRes;
  1368. pType->pres->next = NULL;
  1369. }
  1370. /* keep track of number of resources and types */
  1371. pType->nres++;
  1372. }
  1373. /* MyMakeStr
  1374. * Makes a duplicate string from the string passed in. The new string
  1375. * should be freed when it is no longer useful.
  1376. */
  1377. static PSTR MyMakeStr( PSTR s)
  1378. {
  1379. PSTR s1;
  1380. if (s) {
  1381. s1 = RcAlloc( (WORD)(strlen(s) + 1)); /* allocate buffer */
  1382. strcpy(s1, s); /* copy string */
  1383. } else {
  1384. s1 = s;
  1385. }
  1386. return s1;
  1387. }
  1388. static SHORT MyRead( FILE *fh, PSTR p, WORD n)
  1389. {
  1390. size_t n1;
  1391. if ( (n1 = fread( p, 1, n, fh)) != n )
  1392. ; // quit\("RC : fatal error RW1021: I/O error reading file."\);
  1393. else
  1394. return ( n1);
  1395. }
  1396. /* MyWrite
  1397. * Replaces calls to write\(\) and does error checking.
  1398. */
  1399. static SHORT MyWrite( FILE *fh, PSTR p, WORD n)
  1400. {
  1401. size_t n1;
  1402. if ( (n1 = fwrite( p, 1, n, fh)) != n )
  1403. ; // quit\("RC : fatal error RW1022: I/O error writing file."\);
  1404. else
  1405. return ( n1);
  1406. }
  1407. /* MySeek
  1408. * Replaces calls to lseek\(\) and does error checking
  1409. */
  1410. static LONG MySeek( FILE *fh, LONG pos, WORD cmd)
  1411. {
  1412. if ( (pos = fseek( fh, pos, cmd)) != 0 ) {
  1413. OutPutError ("RC : fatal error RW1023: I/O error seeking in file");
  1414. }
  1415. return ( pos);
  1416. }
  1417. /* MyCopy
  1418. * Copies dwSize bytes from source to dest in fixed size chunks.
  1419. */
  1420. static void MyCopy( FILE *srcfh, FILE *dstfh, DWORD dwSize)
  1421. {
  1422. WORD n;
  1423. static char chCopyBuffer[ BUFSIZE];
  1424. while ( dwSize ) {
  1425. n = MyRead( srcfh, chCopyBuffer, sizeof( chCopyBuffer));
  1426. MyWrite( dstfh, chCopyBuffer, n);
  1427. dwSize -= n;
  1428. }
  1429. }
  1430. static void RcPutWord( unsigned int w)
  1431. {
  1432. *((WORD *)pResNext) = w;
  1433. pResNext++;
  1434. pResNext++;
  1435. }
  1436. /* PutStringWord
  1437. * Writes a string to the static resource buffer pointed to by pResNext.
  1438. * The string is stored in Pascal-format \(leading byte first\).
  1439. * Returns the number of characters written.
  1440. */
  1441. static int RcPutString( char *pstr)
  1442. {
  1443. int i;
  1444. /* Make sure we have a valid string */
  1445. if (!pstr || !(i = strlen(pstr))) {
  1446. return 0;
  1447. }
  1448. /* Write the length byte */
  1449. *pResNext++ = (char) i;
  1450. /* Write all the characters */
  1451. while (*pstr) {
  1452. *pResNext++ = *pstr++;
  1453. }
  1454. /* Return the length */
  1455. return (i + 1);
  1456. }
  1457. static PSTR RcAlloc( WORD nbytes)
  1458. {
  1459. PSTR ps = NULL;
  1460. if ( ps = (PSTR)MyAlloc( nbytes)) {
  1461. return ( ps);
  1462. }
  1463. }