Source code of Windows XP (NT5)
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.

2485 lines
81 KiB

  1. /******************************************************************************
  2. PROGRAM: updres.c
  3. PURPOSE: Contains API Entry points and routines for updating resource
  4. sections in exe/dll
  5. FUNCTIONS:
  6. EndUpdateResource(HANDLE, BOOL) - end update, write changes
  7. UpdateResource(HANDLE, LPSTR, LPSTR, WORD, PVOID)
  8. - update individual resource
  9. BeginUpdateResource(LPSTR) - begin update
  10. *******************************************************************************/
  11. #include "precomp.h"
  12. #include "updres.h"
  13. #define cbPadMax 16L
  14. char *pchPad = "PADDINGXXPADDING";
  15. char *pchZero = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  16. /****************************************************************************
  17. **
  18. ** API entry points
  19. **
  20. ****************************************************************************/
  21. HANDLE BeginUpdateResourceInternalW(LPCWSTR pwch, BOOL bDeleteExistingResources)
  22. /*++
  23. Routine Description
  24. Begins an update of resources. Save away the name
  25. and current resources in a list, using EnumResourceXxx
  26. api set.
  27. Parameters:
  28. lpFileName - Supplies the name of the executable file that the
  29. resource specified by lpType/lpName/language will be updated
  30. in. This file must be able to be opened for writing (ie, not
  31. currently executing, etc.) The file may be fully qualified,
  32. or if not, the current directory is assumed. It must be a
  33. valid Windows executable file.
  34. bDeleteExistingResources - if TRUE, existing resources are
  35. deleted, and only new resources will appear in the result.
  36. Otherwise, all resources in the input file will be in the
  37. output file unless specifically deleted or replaced.
  38. Return Value:
  39. NULL - The file specified was not able to be opened for writing.
  40. Either it was not an executable image, the executable image is
  41. already loaded, or the filename did not exist. More information may
  42. be available via GetLastError api.
  43. HANDLE - A handle to be passed to the UpdateResource and
  44. EndUpdateResources function.
  45. --*/
  46. {
  47. HMODULE hModule;
  48. PUPDATEDATA pUpdate;
  49. HANDLE hUpdate;
  50. LPWSTR pFileName;
  51. DWORD attr;
  52. SetLastError(NO_ERROR);
  53. if (pwch == NULL)
  54. {
  55. SetLastError(ERROR_INVALID_PARAMETER);
  56. return NULL;
  57. }
  58. hUpdate = GlobalAlloc(GHND, sizeof(UPDATEDATA));
  59. if (hUpdate == NULL)
  60. {
  61. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  62. return NULL;
  63. }
  64. pUpdate = (PUPDATEDATA)GlobalLock(hUpdate);
  65. if (pUpdate == NULL)
  66. {
  67. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  68. return NULL;
  69. }
  70. pUpdate->Status = NO_ERROR;
  71. pUpdate->hFileName = GlobalAlloc(GHND, (gwcslen(pwch)+1)*sizeof(WCHAR));
  72. if (pUpdate->hFileName == NULL)
  73. {
  74. GlobalUnlock(hUpdate);
  75. GlobalFree(hUpdate);
  76. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  77. return NULL;
  78. }
  79. pFileName = (LPWSTR)GlobalLock(pUpdate->hFileName);
  80. if (pFileName == NULL)
  81. {
  82. GlobalUnlock(hUpdate);
  83. GlobalFree(hUpdate);
  84. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  85. return NULL;
  86. }
  87. gwcscpy(pFileName, pwch);
  88. GlobalUnlock(pUpdate->hFileName);
  89. attr = GetFileAttributesW(pFileName);
  90. if (attr == 0xffffffff)
  91. {
  92. GlobalUnlock(hUpdate);
  93. GlobalFree(hUpdate);
  94. return NULL;
  95. }
  96. else if (attr & (FILE_ATTRIBUTE_READONLY |
  97. FILE_ATTRIBUTE_SYSTEM |
  98. FILE_ATTRIBUTE_HIDDEN |
  99. FILE_ATTRIBUTE_DIRECTORY))
  100. {
  101. GlobalUnlock(hUpdate);
  102. GlobalFree(hUpdate);
  103. SetLastError(ERROR_WRITE_PROTECT);
  104. return NULL;
  105. }
  106. if (!bDeleteExistingResources)
  107. {
  108. hModule = LoadLibraryExW(pwch, NULL,LOAD_LIBRARY_AS_DATAFILE| DONT_RESOLVE_DLL_REFERENCES);
  109. if (hModule == NULL)
  110. {
  111. GlobalUnlock(hUpdate);
  112. GlobalFree(hUpdate);
  113. if (GetLastError() == NO_ERROR)
  114. SetLastError(ERROR_BAD_EXE_FORMAT);
  115. return NULL;
  116. }
  117. else
  118. EnumResourceTypesW(hModule, (ENUMRESTYPEPROCW)EnumTypesFunc, (LONG)pUpdate);
  119. FreeLibrary(hModule);
  120. }
  121. if (pUpdate->Status != NO_ERROR)
  122. {
  123. GlobalUnlock(hUpdate);
  124. GlobalFree(hUpdate);
  125. // return code set by enum functions
  126. return NULL;
  127. }
  128. GlobalUnlock(hUpdate);
  129. return hUpdate;
  130. }
  131. BOOL UpdateResourceInternalW(HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName,
  132. WORD language, LPVOID lpData, ULONG cb)
  133. /*++
  134. Routine Description
  135. This routine adds, deletes or modifies the input resource
  136. in the list initialized by BeginUpdateResource. The modify
  137. case is simple, the add is easy, the delete is hard.
  138. The ASCII entry point converts inputs to UNICODE.
  139. Parameters:
  140. hUpdateFile - The handle returned by the BeginUpdateResources
  141. function.
  142. lpType - Points to a null-terminated character string that
  143. represents the type name of the resource to be updated or
  144. added. May be an integer value passed to MAKEINTRESOURCE
  145. macro. For predefined resource types, the lpType parameter
  146. should be one of the following values:
  147. RT_ACCELERATOR - Accelerator table
  148. RT_BITMAP - Bitmap resource
  149. RT_DIALOG - Dialog box
  150. RT_FONT - Font resource
  151. RT_FONTDIR - Font directory resource
  152. RT_MENU - Menu resource
  153. RT_RCDATA - User-defined resource (raw data)
  154. RT_VERSION - Version resource
  155. RT_ICON - Icon resource
  156. RT_CURSOR - Cursor resource
  157. lpName - Points to a null-terminated character string that
  158. represents the name of the resource to be updated or added.
  159. May be an integer value passed to MAKEINTRESOURCE macro.
  160. language - Is the word value that specifies the language of the
  161. resource to be updated. A complete list of values is
  162. available in winnls.h.
  163. lpData - A pointer to the raw data to be inserted into the
  164. executable image's resource table and data. If the data is
  165. one of the predefined types, it must be valid and properly
  166. aligned. If lpData is NULL, the specified resource is to be
  167. deleted from the executable image.
  168. cb - count of bytes in the data.
  169. Return Value:
  170. TRUE - The resource specified was successfully replaced in, or added
  171. to, the specified executable image.
  172. FALSE/NULL - The resource specified was not successfully added to or
  173. updated in the executable image. More information may be available
  174. via GetLastError api.
  175. --*/
  176. {
  177. PUPDATEDATA pUpdate;
  178. PSDATA Type;
  179. PSDATA Name;
  180. PVOID lpCopy;
  181. LONG fRet;
  182. SetLastError(0);
  183. pUpdate = (PUPDATEDATA)GlobalLock(hUpdate);
  184. Name = AddStringOrID(lpName, pUpdate);
  185. if (Name == NULL)
  186. {
  187. pUpdate->Status = ERROR_NOT_ENOUGH_MEMORY;
  188. GlobalUnlock(hUpdate);
  189. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  190. return FALSE;
  191. }
  192. Type = AddStringOrID(lpType, pUpdate);
  193. if (Type == NULL)
  194. {
  195. pUpdate->Status = ERROR_NOT_ENOUGH_MEMORY;
  196. GlobalUnlock(hUpdate);
  197. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  198. return FALSE;
  199. }
  200. if (cb == 0)
  201. {
  202. lpCopy = NULL;
  203. }
  204. else
  205. {
  206. lpCopy = GodotHeapAlloc(cb);
  207. if (lpCopy == NULL)
  208. {
  209. pUpdate->Status = ERROR_NOT_ENOUGH_MEMORY;
  210. GlobalUnlock(hUpdate);
  211. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  212. return FALSE;
  213. }
  214. RtlCopyMemory(lpCopy, lpData, cb);
  215. }
  216. fRet = AddResource(Type, Name, language, pUpdate, lpCopy, cb);
  217. GlobalUnlock(hUpdate);
  218. if (fRet == NO_ERROR)
  219. return TRUE;
  220. else
  221. {
  222. SetLastError(fRet);
  223. if (lpData != NULL)
  224. GodotHeapFree(lpData);
  225. return FALSE;
  226. }
  227. }
  228. /*++
  229. Routine Description
  230. Finishes the UpdateResource action. Copies the
  231. input file to a temporary, adds the resources left
  232. in the list (hUpdate) to the exe.
  233. Parameters:
  234. hUpdateFile - The handle returned by the BeginUpdateResources
  235. function.
  236. fDiscard - If TRUE, discards all the updates, frees all memory.
  237. Return Value:
  238. FALSE - The file specified was not able to be written. More
  239. information may be available via GetLastError api.
  240. TRUE - The accumulated resources specified by UpdateResource calls
  241. were written to the executable file specified by the hUpdateFile
  242. handle.
  243. --*/
  244. BOOL EndUpdateResourceInternalW(HANDLE hUpdate, BOOL fDiscard)
  245. {
  246. LPWSTR pFileName;
  247. PUPDATEDATA pUpdate;
  248. WCHAR pTempFileName[MAX_PATH];
  249. INT cch;
  250. LPWSTR p;
  251. LONG rc;
  252. DWORD LastError = 0;
  253. SetLastError(0);
  254. pUpdate = (PUPDATEDATA)GlobalLock(hUpdate);
  255. if (fDiscard)
  256. {
  257. rc = NO_ERROR;
  258. }
  259. else
  260. {
  261. pFileName = (LPWSTR)GlobalLock(pUpdate->hFileName);
  262. gwcscpy(pTempFileName, pFileName);
  263. cch = gwcslen(pTempFileName);
  264. p = pTempFileName + cch;
  265. while (*p != L'\\' && p >= pTempFileName)
  266. p--;
  267. *(p+1) = 0;
  268. rc = GetTempFileNameW(pTempFileName, L"RCX", 0, pTempFileName);
  269. if (rc == 0)
  270. {
  271. rc = GetTempPathW(MAX_PATH, pTempFileName);
  272. if (rc == 0)
  273. {
  274. pTempFileName[0] = L'.';
  275. pTempFileName[1] = L'\\';
  276. pTempFileName[2] = 0;
  277. }
  278. rc = GetTempFileNameW(pTempFileName, L"RCX", 0, pTempFileName);
  279. if (rc == 0)
  280. {
  281. rc = GetLastError();
  282. }
  283. else
  284. {
  285. rc = WriteResFile(hUpdate, pTempFileName);
  286. if (rc == NO_ERROR)
  287. {
  288. DeleteFileW(pFileName);
  289. MoveFileW(pTempFileName, pFileName);
  290. }
  291. else
  292. {
  293. LastError = rc;
  294. DeleteFileW(pTempFileName);
  295. }
  296. }
  297. }
  298. else
  299. {
  300. rc = WriteResFile(hUpdate, pTempFileName);
  301. if (rc == NO_ERROR)
  302. {
  303. DeleteFileW(pFileName);
  304. MoveFileW(pTempFileName, pFileName);
  305. }
  306. else
  307. {
  308. LastError = rc;
  309. DeleteFileW(pTempFileName);
  310. }
  311. }
  312. GlobalUnlock(pUpdate->hFileName);
  313. GlobalFree(pUpdate->hFileName);
  314. }
  315. FreeData(pUpdate);
  316. GlobalUnlock(hUpdate);
  317. GlobalFree(hUpdate);
  318. SetLastError(LastError);
  319. return(rc ? FALSE : TRUE);
  320. }
  321. /**********************************************************************
  322. **
  323. ** End of API entry points.
  324. **
  325. ** Beginning of private entry points for worker routines to do the
  326. ** real work.
  327. **
  328. ***********************************************************************/
  329. BOOL EnumTypesFunc(HANDLE hModule, LPWSTR lpType, LONG lParam)
  330. {
  331. EnumResourceNamesW(hModule, lpType, (ENUMRESNAMEPROCW)EnumNamesFunc, lParam);
  332. return TRUE;
  333. }
  334. BOOL EnumNamesFunc(HANDLE hModule, LPWSTR lpType, LPWSTR lpName, LONG lParam)
  335. {
  336. EnumResourceLanguagesW(hModule, lpType, lpName, (ENUMRESLANGPROCW)EnumLangsFunc, lParam);
  337. return TRUE;
  338. }
  339. BOOL EnumLangsFunc(HANDLE hModule, LPWSTR lpType, LPWSTR lpName, WORD language, LONG lParam)
  340. {
  341. HANDLE hResInfo;
  342. LONG fError;
  343. PSDATA Type;
  344. PSDATA Name;
  345. ULONG cb;
  346. PVOID lpData;
  347. HANDLE hResource;
  348. PVOID lpResource;
  349. hResInfo = FindResourceExW(hModule, lpType, lpName, language);
  350. if (hResInfo == NULL)
  351. {
  352. return FALSE;
  353. }
  354. else
  355. {
  356. Type = AddStringOrID(lpType, (PUPDATEDATA)lParam);
  357. if (Type == NULL)
  358. {
  359. ((PUPDATEDATA)lParam)->Status = ERROR_NOT_ENOUGH_MEMORY;
  360. return FALSE;
  361. }
  362. Name = AddStringOrID(lpName, (PUPDATEDATA)lParam);
  363. if (Name == NULL)
  364. {
  365. ((PUPDATEDATA)lParam)->Status = ERROR_NOT_ENOUGH_MEMORY;
  366. return FALSE;
  367. }
  368. cb = SizeofResource(hModule, hResInfo);
  369. if (cb == 0)
  370. {
  371. return FALSE;
  372. }
  373. lpData = GodotHeapAlloc(cb);
  374. if (lpData == NULL)
  375. {
  376. return FALSE;
  377. }
  378. RtlZeroMemory(lpData, cb);
  379. hResource = LoadResource(hModule, hResInfo);
  380. if (hResource == NULL)
  381. {
  382. GodotHeapFree(lpData);
  383. return FALSE;
  384. }
  385. lpResource = (PVOID)LockResource(hResource);
  386. if (lpResource == NULL)
  387. {
  388. GodotHeapFree(lpData);
  389. return FALSE;
  390. }
  391. RtlCopyMemory(lpData, lpResource, cb);
  392. (VOID)UnlockResource(hResource);
  393. (VOID)FreeResource(hResource);
  394. fError = AddResource(Type, Name, language, (PUPDATEDATA)lParam, lpData, cb);
  395. if (fError != NO_ERROR)
  396. {
  397. ((PUPDATEDATA)lParam)->Status = ERROR_NOT_ENOUGH_MEMORY;
  398. return FALSE;
  399. }
  400. }
  401. return TRUE;
  402. }
  403. VOID FreeOne(PRESNAME pRes)
  404. {
  405. GodotHeapFree((PVOID)pRes->OffsetToDataEntry);
  406. if (IS_ID == pRes->Name->discriminant)
  407. {
  408. GodotHeapFree((PVOID)pRes->Name);
  409. }
  410. if (IS_ID == pRes->Type->discriminant)
  411. {
  412. GodotHeapFree((PVOID)pRes->Type);
  413. }
  414. GodotHeapFree((PVOID)pRes);
  415. }
  416. VOID FreeData(PUPDATEDATA pUpd)
  417. {
  418. PRESTYPE pType;
  419. PRESNAME pRes;
  420. PSDATA pstring, pStringTmp;
  421. for (pType=pUpd->ResTypeHeadID ; pUpd->ResTypeHeadID ; pType=pUpd->ResTypeHeadID)
  422. {
  423. pUpd->ResTypeHeadID = pUpd->ResTypeHeadID->pnext;
  424. for (pRes=pType->NameHeadID ; pType->NameHeadID ; pRes=pType->NameHeadID )
  425. {
  426. pType->NameHeadID = pType->NameHeadID->pnext;
  427. FreeOne(pRes);
  428. }
  429. for (pRes=pType->NameHeadName ; pType->NameHeadName ; pRes=pType->NameHeadName )
  430. {
  431. pType->NameHeadName = pType->NameHeadName->pnext;
  432. FreeOne(pRes);
  433. }
  434. GodotHeapFree((PVOID)pType);
  435. }
  436. for (pType=pUpd->ResTypeHeadName ; pUpd->ResTypeHeadName ; pType=pUpd->ResTypeHeadName)
  437. {
  438. pUpd->ResTypeHeadName = pUpd->ResTypeHeadName->pnext;
  439. for (pRes=pType->NameHeadID ; pType->NameHeadID ; pRes=pType->NameHeadID )
  440. {
  441. pType->NameHeadID = pType->NameHeadID->pnext;
  442. FreeOne(pRes);
  443. }
  444. for (pRes=pType->NameHeadName ; pType->NameHeadName ; pRes=pType->NameHeadName )
  445. {
  446. pType->NameHeadName = pType->NameHeadName->pnext;
  447. FreeOne(pRes);
  448. }
  449. GodotHeapFree((PVOID)pType);
  450. }
  451. pstring = pUpd->StringHead;
  452. while (pstring != NULL)
  453. {
  454. pStringTmp = pstring->uu.ss.pnext;
  455. if (pstring->discriminant == IS_STRING)
  456. GodotHeapFree((PVOID)pstring->szStr);
  457. GodotHeapFree((PVOID)pstring);
  458. pstring = pStringTmp;
  459. }
  460. return;
  461. }
  462. /*+++
  463. Routines to register strings
  464. ---*/
  465. //
  466. // Resources are DWORD aligned and may be in any order.
  467. //
  468. #define TABLE_ALIGN 4
  469. #define DATA_ALIGN 4L
  470. PSDATA AddStringOrID(LPCWSTR lp, PUPDATEDATA pupd)
  471. {
  472. USHORT cb;
  473. PSDATA pstring;
  474. PPSDATA ppstring;
  475. if (((ULONG)lp & 0xFFFF0000) == 0)
  476. {
  477. //
  478. // an ID
  479. //
  480. pstring = (PSDATA)GodotHeapAlloc(sizeof(SDATA));
  481. if (pstring == NULL)
  482. return NULL;
  483. RtlZeroMemory((PVOID)pstring, sizeof(SDATA));
  484. pstring->discriminant = IS_ID;
  485. pstring->uu.Ordinal = (WORD)((ULONG)lp & 0x0000ffff);
  486. }
  487. else
  488. {
  489. //
  490. // a string
  491. //
  492. cb = gwcslen(lp) + 1;
  493. ppstring = &pupd->StringHead;
  494. while ((pstring = *ppstring) != NULL)
  495. {
  496. if (!gwcsncmp(pstring->szStr, lp, cb))
  497. break;
  498. ppstring = &(pstring->uu.ss.pnext);
  499. }
  500. if (!pstring)
  501. {
  502. //
  503. // allocate a new one
  504. //
  505. pstring = (PSDATA)GodotHeapAlloc(sizeof(SDATA));
  506. if (pstring == NULL)
  507. return NULL;
  508. RtlZeroMemory((PVOID)pstring, sizeof(SDATA));
  509. pstring->szStr = (WCHAR*)GodotHeapAlloc(cb*sizeof(WCHAR));
  510. if (pstring->szStr == NULL)
  511. {
  512. GodotHeapFree((PVOID)pstring);
  513. return NULL;
  514. }
  515. pstring->discriminant = IS_STRING;
  516. pstring->OffsetToString = pupd->cbStringTable;
  517. pstring->cbData = sizeof(pstring->cbsz) + cb * sizeof(WCHAR);
  518. pstring->cbsz = cb - 1; /* don't include zero terminator */
  519. RtlCopyMemory(pstring->szStr, lp, cb*sizeof(WCHAR));
  520. pupd->cbStringTable += pstring->cbData;
  521. pstring->uu.ss.pnext=NULL;
  522. *ppstring=pstring;
  523. }
  524. }
  525. return(pstring);
  526. }
  527. LONG AddResource(IN PSDATA Type, IN PSDATA Name, IN WORD Language,
  528. IN PUPDATEDATA pupd, IN PVOID lpData, IN ULONG cb)
  529. //
  530. // add a resource into the resource directory hiearchy
  531. //
  532. {
  533. PRESTYPE pType;
  534. PPRESTYPE ppType;
  535. PRESNAME pName;
  536. PRESNAME pNameM;
  537. PPRESNAME ppName = NULL;
  538. BOOL fTypeID=(Type->discriminant == IS_ID);
  539. BOOL fNameID=(Name->discriminant == IS_ID);
  540. BOOL fSame=FALSE;
  541. //
  542. // figure out which list to store it in
  543. //
  544. ppType = fTypeID ? &pupd->ResTypeHeadID : &pupd->ResTypeHeadName;
  545. //
  546. // Try to find the Type in the list
  547. //
  548. while ((pType=*ppType) != NULL)
  549. {
  550. if (pType->Type->uu.Ordinal == Type->uu.Ordinal)
  551. {
  552. ppName = fNameID ? &pType->NameHeadID : &pType->NameHeadName;
  553. break;
  554. }
  555. if (fTypeID)
  556. {
  557. if (Type->uu.Ordinal < pType->Type->uu.Ordinal)
  558. break;
  559. }
  560. else
  561. {
  562. if (gwcsncmp(Type->szStr, pType->Type->szStr, Type->cbsz) < 0)
  563. break;
  564. }
  565. ppType = &(pType->pnext);
  566. }
  567. //
  568. // Create a new type if needed
  569. //
  570. if (ppName == NULL)
  571. {
  572. pType = (PRESTYPE)GodotHeapAlloc(sizeof(RESTYPE));
  573. if (pType == NULL)
  574. return ERROR_NOT_ENOUGH_MEMORY;
  575. RtlZeroMemory((PVOID)pType, sizeof(RESTYPE));
  576. pType->pnext = *ppType;
  577. *ppType = pType;
  578. pType->Type = Type;
  579. ppName = fNameID ? &pType->NameHeadID : &pType->NameHeadName;
  580. }
  581. //
  582. // Find proper place for name
  583. //
  584. while ( (pName = *ppName) != NULL)
  585. {
  586. if (fNameID)
  587. {
  588. if (Name->uu.Ordinal == pName->Name->uu.Ordinal)
  589. {
  590. fSame = TRUE;
  591. break;
  592. }
  593. if (Name->uu.Ordinal < pName->Name->uu.Ordinal)
  594. break;
  595. }
  596. else
  597. {
  598. if (gwcsncmp(Name->szStr, pName->Name->szStr, Name->cbsz) == 0)
  599. {
  600. fSame = TRUE;
  601. break;
  602. }
  603. if (gwcsncmp(Name->szStr, pName->Name->szStr, Name->cbsz) < 0)
  604. break;
  605. }
  606. ppName = &(pName->pnext);
  607. }
  608. //
  609. // check for delete/modify
  610. //
  611. if (fSame) /* same name, new language */
  612. {
  613. if (pName->NumberOfLanguages == 1) /* one language currently ? */
  614. {
  615. if (Language == pName->LanguageId) /* REPLACE || DELETE */
  616. {
  617. pName->DataSize = cb;
  618. if (lpData == NULL) /* DELETE */
  619. {
  620. return DeleteResourceFromList(pupd, pType, pName, Language, fTypeID, fNameID);
  621. }
  622. GodotHeapFree((PVOID)pName->OffsetToDataEntry);
  623. if (IS_ID == Type->discriminant)
  624. {
  625. GodotHeapFree((PVOID)Type);
  626. }
  627. if (IS_ID == Name->discriminant)
  628. {
  629. GodotHeapFree((PVOID)Name);
  630. }
  631. (PVOID)pName->OffsetToDataEntry = lpData;
  632. return NO_ERROR;
  633. }
  634. else
  635. {
  636. if (lpData == NULL) /* no data but new? */
  637. {
  638. return ERROR_INVALID_PARAMETER; /* badness */
  639. }
  640. return InsertResourceIntoLangList(pupd, Type, Name, pType, pName,
  641. Language, fNameID, cb, lpData);
  642. }
  643. }
  644. else /* many languages currently */
  645. {
  646. pNameM = pName; /* save head of lang list */
  647. while ( (pName = *ppName) != NULL) /* find insertion point */
  648. {
  649. if (!(fNameID ? pName->Name->uu.Ordinal == (*ppName)->Name->uu.Ordinal :
  650. !gwcscmp(pName->Name->uu.ss.sz, (*ppName)->Name->uu.ss.sz)) ||
  651. Language <= pName->LanguageId) /* here? */
  652. break; /* yes */
  653. ppName = &(pName->pnext); /* traverse language list */
  654. }
  655. if (pName && Language == pName->LanguageId) /* language found? */
  656. {
  657. if (lpData == NULL) /* DELETE */
  658. {
  659. return DeleteResourceFromList(pupd, pType, pName, Language, fTypeID, fNameID);
  660. }
  661. pName->DataSize = cb; /* REPLACE */
  662. GodotHeapFree((PVOID)pName->OffsetToDataEntry);
  663. if (IS_ID == Type->discriminant)
  664. {
  665. GodotHeapFree((PVOID)Type);
  666. }
  667. if (IS_ID == Name->discriminant)
  668. {
  669. GodotHeapFree((PVOID)Name);
  670. }
  671. (PVOID)pName->OffsetToDataEntry = lpData;
  672. return NO_ERROR;
  673. }
  674. else /* add new language */
  675. {
  676. return InsertResourceIntoLangList(pupd, Type, Name, pType, pNameM, Language, fNameID, cb, lpData);
  677. }
  678. }
  679. }
  680. else /* unique name */
  681. {
  682. if (lpData == NULL) /* can't delete new name */
  683. {
  684. return ERROR_INVALID_PARAMETER;
  685. }
  686. }
  687. //
  688. // add new name/language
  689. //
  690. if (!fSame)
  691. {
  692. if (fNameID)
  693. pType->NumberOfNamesID++;
  694. else
  695. pType->NumberOfNamesName++;
  696. }
  697. pName = (PRESNAME)GodotHeapAlloc(sizeof(RESNAME));
  698. if (pName == NULL)
  699. return ERROR_NOT_ENOUGH_MEMORY;
  700. RtlZeroMemory((PVOID)pName, sizeof(RESNAME));
  701. pName->pnext = *ppName;
  702. *ppName = pName;
  703. pName->Name = Name;
  704. pName->Type = Type;
  705. pName->NumberOfLanguages = 1;
  706. pName->LanguageId = Language;
  707. pName->DataSize = cb;
  708. (PVOID)pName->OffsetToDataEntry = lpData;
  709. return NO_ERROR;
  710. }
  711. BOOL DeleteResourceFromList(PUPDATEDATA pUpd, PRESTYPE pType, PRESNAME pName,
  712. INT Language, INT fType, INT fName)
  713. {
  714. PPRESTYPE ppType;
  715. PPRESNAME ppName;
  716. PRESNAME pNameT;
  717. /* find previous type node */
  718. ppType = fType ? &pUpd->ResTypeHeadID : &pUpd->ResTypeHeadName;
  719. while (*ppType != pType)
  720. {
  721. ppType = &((*ppType)->pnext);
  722. }
  723. /* find previous type node */
  724. ppName = fName ? &pType->NameHeadID : &pType->NameHeadName;
  725. pNameT = NULL;
  726. while (*ppName != pName)
  727. {
  728. if (pNameT == NULL) /* find first Name in lang list */
  729. {
  730. if (fName)
  731. {
  732. if ((*ppName)->Name->uu.Ordinal == pName->Name->uu.Ordinal)
  733. {
  734. pNameT = *ppName;
  735. }
  736. }
  737. else
  738. {
  739. if (gwcsncmp((*ppName)->Name->szStr, pName->Name->szStr, (*ppName)->Name->cbsz) == 0)
  740. {
  741. pNameT = *ppName;
  742. }
  743. }
  744. }
  745. ppName = &((*ppName)->pnext);
  746. }
  747. if (pNameT == NULL) /* first of this name? */
  748. {
  749. pNameT = pName->pnext; /* then (possibly) make next head of lang */
  750. if (pNameT != NULL)
  751. {
  752. if (fName)
  753. {
  754. if (pNameT->Name->uu.Ordinal == pName->Name->uu.Ordinal)
  755. {
  756. pNameT->NumberOfLanguages = pName->NumberOfLanguages - 1;
  757. }
  758. }
  759. else
  760. {
  761. if (gwcsncmp(pNameT->Name->szStr, pName->Name->szStr, pNameT->Name->cbsz) == 0)
  762. {
  763. pNameT->NumberOfLanguages = pName->NumberOfLanguages - 1;
  764. }
  765. }
  766. }
  767. }
  768. else
  769. pNameT->NumberOfLanguages--;
  770. if (pNameT)
  771. {
  772. if (pNameT->NumberOfLanguages == 0)
  773. {
  774. if (fName)
  775. pType->NumberOfNamesID -= 1;
  776. else
  777. pType->NumberOfNamesName -= 1;
  778. }
  779. }
  780. *ppName = pName->pnext; /* link to next */
  781. GodotHeapFree( (PVOID)pName->OffsetToDataEntry);
  782. GodotHeapFree( pName); /* and free */
  783. if (*ppName == NULL) /* type list completely empty? */
  784. {
  785. *ppType = pType->pnext; /* link to next */
  786. GodotHeapFree( pType); /* and free */
  787. }
  788. return NO_ERROR;
  789. }
  790. BOOL InsertResourceIntoLangList(PUPDATEDATA pUpd, PSDATA Type, PSDATA Name, PRESTYPE pType,
  791. PRESNAME pName, INT Language, INT fName, INT cb, PVOID lpData)
  792. {
  793. PRESNAME pNameM;
  794. PRESNAME pNameNew;
  795. PPRESNAME ppName;
  796. pNameNew = (PRESNAME)GodotHeapAlloc(sizeof(RESNAME));
  797. if (pNameNew == NULL)
  798. return ERROR_NOT_ENOUGH_MEMORY;
  799. RtlZeroMemory((PVOID)pNameNew, sizeof(RESNAME));
  800. pNameNew->Name = Name;
  801. pNameNew->Type = Type;
  802. pNameNew->LanguageId = (WORD)Language;
  803. pNameNew->DataSize = cb;
  804. (PVOID)pNameNew->OffsetToDataEntry = lpData;
  805. if (Language < pName->LanguageId) /* have to add to the front */
  806. {
  807. pNameNew->NumberOfLanguages = pName->NumberOfLanguages + 1;
  808. pName->NumberOfLanguages = 1;
  809. ppName = fName ? &pType->NameHeadID : &pType->NameHeadName;
  810. /* don't have to look for NULL at end of list !!! */
  811. while (pName != *ppName) /* find insertion point */
  812. {
  813. ppName = &((*ppName)->pnext); /* traverse language list */
  814. }
  815. pNameNew->pnext = *ppName; /* insert */
  816. *ppName = pNameNew;
  817. }
  818. else
  819. {
  820. pNameM = pName;
  821. pName->NumberOfLanguages += 1;
  822. while((pName != NULL) &&
  823. (fName ? Name->uu.Ordinal == pName->Name->uu.Ordinal :
  824. !gwcscmp(Name->uu.ss.sz, pName->Name->uu.ss.sz))) /* find insertion point */
  825. {
  826. if (Language <= pName->LanguageId) /* here? */
  827. break; /* yes */
  828. pNameM = pName;
  829. pName = pName->pnext; /* traverse language list */
  830. }
  831. pName = pNameM->pnext;
  832. pNameM->pnext = pNameNew;
  833. pNameNew->pnext = pName;
  834. }
  835. return NO_ERROR;
  836. }
  837. /*
  838. * Utility routines
  839. */
  840. ULONG FilePos(int fh)
  841. {
  842. return _llseek(fh, 0L, SEEK_CUR);
  843. }
  844. ULONG MuMoveFilePos(INT fh, ULONG pos)
  845. {
  846. return _llseek( fh, pos, SEEK_SET );
  847. }
  848. ULONG MuWrite(INT fh, UCHAR*p, ULONG n)
  849. {
  850. ULONG n1;
  851. if ((n1 = _lwrite(fh, p, n)) != n)
  852. {
  853. return n1;
  854. }
  855. else
  856. return 0;
  857. }
  858. ULONG MuRead(INT fh, UCHAR*p, ULONG n)
  859. {
  860. ULONG n1;
  861. if ((n1 = _lread( fh, p, n )) != n)
  862. {
  863. return n1;
  864. }
  865. else
  866. return 0;
  867. }
  868. BOOL MuCopy(INT srcfh, INT dstfh, ULONG nbytes)
  869. {
  870. ULONG n;
  871. ULONG cb=0L;
  872. PUCHAR pb;
  873. pb = (PUCHAR)GodotHeapAlloc(BUFSIZE);
  874. if (pb == NULL)
  875. return 0;
  876. RtlZeroMemory((PVOID)pb, BUFSIZE);
  877. while (nbytes)
  878. {
  879. if (nbytes <= BUFSIZE)
  880. n = nbytes;
  881. else
  882. n = BUFSIZE;
  883. nbytes -= n;
  884. if (!MuRead( srcfh, pb, n ))
  885. {
  886. cb += n;
  887. MuWrite( dstfh, pb, n );
  888. }
  889. else
  890. {
  891. GodotHeapFree( pb);
  892. return cb;
  893. }
  894. }
  895. GodotHeapFree( pb);
  896. return cb;
  897. }
  898. VOID SetResdata(PIMAGE_RESOURCE_DATA_ENTRY pResData, ULONG offset, ULONG size)
  899. {
  900. pResData->OffsetToData = offset;
  901. pResData->Size = size;
  902. pResData->CodePage = DEFAULT_CODEPAGE;
  903. pResData->Reserved = 0L;
  904. }
  905. VOID SetRestab(PIMAGE_RESOURCE_DIRECTORY pRestab, LONG time, WORD cNamed, WORD cId)
  906. {
  907. pRestab->Characteristics = 0L;
  908. pRestab->TimeDateStamp = time;
  909. pRestab->MajorVersion = MAJOR_RESOURCE_VERSION;
  910. pRestab->MinorVersion = MINOR_RESOURCE_VERSION;
  911. pRestab->NumberOfNamedEntries = cNamed;
  912. pRestab->NumberOfIdEntries = cId;
  913. }
  914. PIMAGE_SECTION_HEADER FindSection(PIMAGE_SECTION_HEADER pObjBottom,
  915. PIMAGE_SECTION_HEADER pObjTop, LPSTR pName)
  916. {
  917. while (pObjBottom < pObjTop)
  918. {
  919. if (strcmp(pObjBottom->Name, pName) == 0)
  920. return pObjBottom;
  921. pObjBottom++;
  922. }
  923. return NULL;
  924. }
  925. ULONG AssignResourceToSection(PRESNAME *ppRes, ULONG ExtraSectionOffset,
  926. ULONG Offset, LONG Size, PLONG pSizeRsrc1)
  927. {
  928. ULONG cb;
  929. /* Assign this res to this section */
  930. cb = ROUNDUP((*ppRes)->DataSize, CBLONG);
  931. if (Offset < ExtraSectionOffset && Offset + cb > (ULONG)Size)
  932. {
  933. *pSizeRsrc1 = Offset;
  934. Offset = ExtraSectionOffset;
  935. }
  936. (*ppRes)->OffsetToData = Offset;
  937. *ppRes = (*ppRes)->pnext;
  938. return Offset + cb;
  939. }
  940. /***************************** Main Worker Function ***************************
  941. * LONG PEWriteResFile
  942. *
  943. * This function writes the resources to the named executable file.
  944. * It assumes that resources have no fixups (even any existing resources
  945. * that it removes from the executable.) It places all the resources into
  946. * one or two sections. The resources are packed tightly into the section,
  947. * being aligned on dword boundaries. Each section is padded to a file
  948. * sector size (no invalid or zero-filled pages), and each
  949. * resource is padded to the afore-mentioned dword boundary. This
  950. * function uses the capabilities of the NT system to enable it to easily
  951. * manipulate the data: to wit, it assumes that the system can allocate
  952. * any sized piece of data, in particular the section and resource tables.
  953. * If it did not, it might have to deal with temporary files (the system
  954. * may have to grow the swap file, but that's what the system is for.)
  955. *
  956. * Return values are:
  957. * TRUE - file was written succesfully.
  958. * FALSE - file was not written succesfully.
  959. *
  960. * Effects:
  961. *
  962. * History:
  963. * Thur Apr 27, 1989 by Floyd Rogers [floydr]
  964. * Created.
  965. * 12/8/89 sanfords Added multiple section support.
  966. * 12/11/90 floydr Modified for new (NT) Linear Exe format
  967. * 1/18/92 vich Modified for new (NT) Portable Exe format
  968. * 5/8/92 bryant General cleanup so resonexe can work with unicode
  969. * 6/9/92 floydr incorporate bryan's changes
  970. * 6/15/92 floydr debug section separate from debug table
  971. * 9/25/92 floydr account for .rsrc not being last-1
  972. * 9/28/92 floydr account for adding lots of resources by adding
  973. * a second .rsrc section.
  974. \****************************************************************************/
  975. /* */
  976. LONG PEWriteResFile(INT inpfh, INT outfh, ULONG cbOldexe, PUPDATEDATA pUpdate)
  977. {
  978. IMAGE_NT_HEADERS Old; /* original header */
  979. IMAGE_NT_HEADERS New; /* working header */
  980. PRESNAME pRes;
  981. PRESNAME pResSave;
  982. PRESTYPE pType;
  983. ULONG clock = GetTickCount(); /* current time */
  984. ULONG cbName=0; /* count of bytes in name strings */
  985. ULONG cbType=0; /* count of bytes in type strings */
  986. ULONG cTypeStr=0; /* count of strings */
  987. ULONG cNameStr=0; /* count of strings */
  988. LONG cb; /* temp byte count and file index */
  989. ULONG cTypes = 0L; /* count of resource types */
  990. ULONG cNames = 0L; /* Count of names for multiple languages/name */
  991. ULONG cRes = 0L; /* count of resources */
  992. ULONG cbRestab; /* count of resources */
  993. LONG cbNew = 0L; /* general count */
  994. ULONG ibObjTab;
  995. ULONG ibObjTabEnd;
  996. ULONG ibNewObjTabEnd;
  997. ULONG ibSave;
  998. ULONG adjust=0;
  999. PIMAGE_SECTION_HEADER pObjtblOld,
  1000. pObjtblNew,
  1001. pObjDebug,
  1002. pObjResourceOld,
  1003. pObjResourceNew,
  1004. pObjResourceOldX,
  1005. pObjDebugDirOld,
  1006. pObjDebugDirNew,
  1007. pObjNew,
  1008. pObjOld,
  1009. pObjLast;
  1010. PUCHAR p;
  1011. PIMAGE_RESOURCE_DIRECTORY pResTab;
  1012. PIMAGE_RESOURCE_DIRECTORY pResTabN;
  1013. PIMAGE_RESOURCE_DIRECTORY pResTabL;
  1014. PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirL;
  1015. PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirN;
  1016. PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirT;
  1017. PIMAGE_RESOURCE_DATA_ENTRY pResData;
  1018. PUSHORT pResStr;
  1019. PUSHORT pResStrEnd;
  1020. PSDATA pPreviousName;
  1021. LONG nObjResource=-1;
  1022. LONG nObjResourceX=-1;
  1023. ULONG cbResource;
  1024. ULONG cbMustPad = 0;
  1025. ULONG ibMaxDbgOffsetOld;
  1026. MuMoveFilePos(inpfh, cbOldexe);
  1027. MuRead(inpfh, (PUCHAR)&Old, sizeof(IMAGE_NT_HEADERS));
  1028. ibObjTab = cbOldexe + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
  1029. Old.FileHeader.SizeOfOptionalHeader;
  1030. ibObjTabEnd = ibObjTab + Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
  1031. ibNewObjTabEnd = ibObjTabEnd;
  1032. if (*(PUSHORT)&Old.Signature != IMAGE_NT_SIGNATURE)
  1033. return ERROR_INVALID_EXE_SIGNATURE;
  1034. if((Old.FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0 &&
  1035. (Old.FileHeader.Characteristics & IMAGE_FILE_DLL) == 0)
  1036. {
  1037. return ERROR_EXE_MARKED_INVALID;
  1038. }
  1039. /* New header is like old one. */
  1040. RtlCopyMemory(&New, &Old, sizeof(IMAGE_NT_HEADERS));
  1041. /* Read section table */
  1042. pObjtblOld = (PIMAGE_SECTION_HEADER)GodotHeapAlloc(
  1043. Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
  1044. if (pObjtblOld == NULL)
  1045. {
  1046. cb = ERROR_NOT_ENOUGH_MEMORY;
  1047. goto AbortExit;
  1048. }
  1049. RtlZeroMemory((PVOID)pObjtblOld, Old.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER));
  1050. MuMoveFilePos(inpfh, ibObjTab);
  1051. MuRead(inpfh, (PUCHAR)pObjtblOld,
  1052. Old.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
  1053. pObjLast = pObjtblOld + Old.FileHeader.NumberOfSections;
  1054. ibMaxDbgOffsetOld = 0;
  1055. for (pObjOld=pObjtblOld ; pObjOld<pObjLast ; pObjOld++)
  1056. {
  1057. if (pObjOld->PointerToRawData > ibMaxDbgOffsetOld)
  1058. {
  1059. ibMaxDbgOffsetOld = pObjOld->PointerToRawData + pObjOld->SizeOfRawData;
  1060. }
  1061. }
  1062. /*
  1063. * First, count up the resources. We need this information
  1064. * to discover how much room for header information to allocate
  1065. * in the resource section. cRes tells us how
  1066. * many language directory entries/tables. cNames and cTypes
  1067. * is used for the respective tables and/or entries. cbName totals
  1068. * the bytes required to store the alpha names (including the leading
  1069. * length word). cNameStr counts these strings.
  1070. */
  1071. /* first, count those in the named type list */
  1072. cbResource = 0;
  1073. pType = pUpdate->ResTypeHeadName;
  1074. while (pType != NULL)
  1075. {
  1076. if (pType->NameHeadName != NULL || pType->NameHeadID != NULL)
  1077. {
  1078. cTypes++;
  1079. cTypeStr++;
  1080. cbType += (pType->Type->cbsz + 1) * sizeof(WORD);
  1081. pPreviousName = NULL;
  1082. pRes = pType->NameHeadName;
  1083. while (pRes)
  1084. {
  1085. cRes++;
  1086. if (pPreviousName == NULL ||
  1087. gwcsncmp(pPreviousName->szStr, pRes->Name->szStr, pRes->Name->cbsz) != 0)
  1088. {
  1089. cbName += (pRes->Name->cbsz + 1) * sizeof(WORD);
  1090. cNameStr++;
  1091. cNames++;
  1092. }
  1093. cbResource += ROUNDUP(pRes->DataSize, CBLONG);
  1094. pPreviousName = pRes->Name;
  1095. pRes = pRes->pnext;
  1096. }
  1097. pPreviousName = NULL;
  1098. pRes = pType->NameHeadID;
  1099. while (pRes)
  1100. {
  1101. cRes++;
  1102. if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal)
  1103. {
  1104. cNames++;
  1105. }
  1106. cbResource += ROUNDUP(pRes->DataSize, CBLONG);
  1107. pPreviousName = pRes->Name;
  1108. pRes = pRes->pnext;
  1109. }
  1110. }
  1111. pType = pType->pnext;
  1112. }
  1113. /* second, count those in the ID type list */
  1114. pType = pUpdate->ResTypeHeadID;
  1115. while (pType != NULL)
  1116. {
  1117. if (pType->NameHeadName != NULL || pType->NameHeadID != NULL)
  1118. {
  1119. cTypes++;
  1120. pPreviousName = NULL;
  1121. pRes = pType->NameHeadName;
  1122. while (pRes)
  1123. {
  1124. cRes++;
  1125. if (pPreviousName == NULL ||
  1126. gwcsncmp(pPreviousName->szStr, pRes->Name->szStr, pRes->Name->cbsz) != 0)
  1127. {
  1128. cNames++;
  1129. cbName += (pRes->Name->cbsz + 1) * sizeof(WORD);
  1130. cNameStr++;
  1131. }
  1132. cbResource += ROUNDUP(pRes->DataSize, CBLONG);
  1133. pPreviousName = pRes->Name;
  1134. pRes = pRes->pnext;
  1135. }
  1136. pPreviousName = NULL;
  1137. pRes = pType->NameHeadID;
  1138. while (pRes)
  1139. {
  1140. cRes++;
  1141. if (pPreviousName == NULL ||
  1142. pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal)
  1143. {
  1144. cNames++;
  1145. }
  1146. cbResource += ROUNDUP(pRes->DataSize, CBLONG);
  1147. pPreviousName = pRes->Name;
  1148. pRes = pRes->pnext;
  1149. }
  1150. }
  1151. pType = pType->pnext;
  1152. }
  1153. cb = REMAINDER(cbName + cbType, CBLONG);
  1154. /* Add up the number of bytes needed to store the directory. There is
  1155. * one type table with cTypes entries. They point to cTypes name tables
  1156. * that have a total of cNames entries. Each of them points to a language
  1157. * table and there are a total of cRes entries in all the language tables.
  1158. * Finally, we have the space needed for the Directory string entries,
  1159. * some extra padding to attain the desired alignment, and the space for
  1160. * cRes data entry headers.
  1161. */
  1162. cbRestab = sizeof(IMAGE_RESOURCE_DIRECTORY) + /* root dir (types) */
  1163. cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) +
  1164. cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY) + /* subdir2 (names) */
  1165. cNames * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) +
  1166. cNames * sizeof(IMAGE_RESOURCE_DIRECTORY) + /* subdir3 (langs) */
  1167. cRes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY) +
  1168. (cbName + cbType) + /* name/type strings */
  1169. cb + /* padding */
  1170. cRes * sizeof(IMAGE_RESOURCE_DATA_ENTRY); /* data entries */
  1171. cbResource += cbRestab; /* add in the resource table */
  1172. // Find any current resource sections
  1173. pObjResourceOld = FindSection(pObjtblOld, pObjLast, ".rsrc");
  1174. pObjResourceOldX = FindSection(pObjtblOld, pObjLast, ".rsrc1");
  1175. if (pObjResourceOld == NULL)
  1176. {
  1177. cb = 0x7fffffff; /* can fill forever */
  1178. }
  1179. else if (pObjResourceOld + 1 == pObjResourceOldX)
  1180. {
  1181. nObjResource = pObjResourceOld - pObjtblOld;
  1182. cb = 0x7fffffff; /* merge resource sections */
  1183. }
  1184. else
  1185. {
  1186. nObjResource = pObjResourceOld - pObjtblOld;
  1187. cb = (pObjResourceOld+1)->VirtualAddress - pObjResourceOld->VirtualAddress;
  1188. if (cbRestab > (ULONG)cb)
  1189. {
  1190. return ERROR_INVALID_DATA;
  1191. }
  1192. }
  1193. /*
  1194. * Discover where the first discardable section is. This is where
  1195. * we will stick any new resource section.
  1196. *
  1197. * Note that we are ignoring discardable sections such as .CRT -
  1198. * this is so that we don't cause any relocation problems.
  1199. * Let's hope that .reloc is the one we want!!!
  1200. */
  1201. pObjOld = FindSection(pObjtblOld, pObjLast, ".reloc");
  1202. if (pObjResourceOld != NULL && cbResource > (ULONG)cb)
  1203. {
  1204. if (pObjResourceOld != NULL && pObjOld == pObjResourceOld + 1)
  1205. {
  1206. cb = 0x7fffffff; /* can fill forever */
  1207. }
  1208. else if (pObjResourceOldX == NULL)
  1209. {
  1210. nObjResourceX = pObjOld - pObjtblOld;
  1211. adjust = pObjOld->VirtualAddress - pObjResourceOld->VirtualAddress;
  1212. }
  1213. else /* have already merged .rsrc & .rsrc1, if possible */
  1214. {
  1215. nObjResourceX = pObjResourceOldX - pObjtblOld;
  1216. adjust = pObjResourceOldX->VirtualAddress - pObjResourceOld->VirtualAddress;
  1217. }
  1218. }
  1219. /*
  1220. * Walk the type lists and figure out where the Data entry header will
  1221. * go. Keep a running total of the size for each data element so we
  1222. * can store this in the section header.
  1223. */
  1224. /* first, those in the named type list */
  1225. cbResource = cbRestab; /* assign resource table to 1st rsrc section */
  1226. /* adjust == offset to .rsrc1 */
  1227. /* cb == size availble in .rsrc */
  1228. cbNew = 0; /* count of bytes in second .rsrc */
  1229. pType = pUpdate->ResTypeHeadName;
  1230. while (pType != NULL)
  1231. {
  1232. if (pType->NameHeadName != NULL || pType->NameHeadID != NULL)
  1233. {
  1234. pRes = pType->NameHeadName;
  1235. while (pRes)
  1236. {
  1237. cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew);
  1238. }
  1239. pRes = pType->NameHeadID;
  1240. while (pRes)
  1241. {
  1242. cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew);
  1243. }
  1244. }
  1245. pType = pType->pnext;
  1246. }
  1247. /* then, count those in the ID type list */
  1248. pType = pUpdate->ResTypeHeadID;
  1249. while (pType != NULL)
  1250. {
  1251. if (pType->NameHeadName != NULL || pType->NameHeadID != NULL)
  1252. {
  1253. pRes = pType->NameHeadName;
  1254. while (pRes)
  1255. {
  1256. cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew);
  1257. }
  1258. pRes = pType->NameHeadID;
  1259. while (pRes)
  1260. {
  1261. cbResource = AssignResourceToSection(&pRes, adjust, cbResource, cb, &cbNew);
  1262. }
  1263. }
  1264. pType = pType->pnext;
  1265. }
  1266. /*
  1267. * At this point:
  1268. * cbResource has offset of first byte past the last resource.
  1269. * cbNew has the count of bytes in the first resource section,
  1270. * if there are two sections.
  1271. */
  1272. if (cbNew == 0)
  1273. cbNew = cbResource;
  1274. /*
  1275. * Discover where the Debug info is (if any)?
  1276. */
  1277. pObjDebug = FindSection(pObjtblOld, pObjLast, ".debug");
  1278. if (pObjDebug != NULL)
  1279. {
  1280. if (Old.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress == 0)
  1281. {
  1282. return ERROR_INVALID_DATA;
  1283. }
  1284. if (pObjDebug != pObjLast-1)
  1285. {
  1286. return ERROR_INVALID_DATA;
  1287. }
  1288. }
  1289. pObjDebugDirOld = NULL;
  1290. for (pObjOld=pObjtblOld ; pObjOld<pObjLast ; pObjOld++)
  1291. {
  1292. if(Old.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress >=
  1293. pObjOld->VirtualAddress &&
  1294. Old.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress <
  1295. pObjOld->VirtualAddress+pObjOld->SizeOfRawData)
  1296. {
  1297. pObjDebugDirOld = pObjOld;
  1298. break;
  1299. }
  1300. }
  1301. /*
  1302. * Discover where the first discardable section is. This is where
  1303. * we will stick any new resource section.
  1304. *
  1305. * Note that we are ignoring discardable sections such as .CRT -
  1306. * this is so that we don't cause any relocation problems.
  1307. * Let's hope that .reloc is the one we want!!!
  1308. */
  1309. pObjOld = FindSection(pObjtblOld, pObjLast, ".reloc");
  1310. if (nObjResource == -1) /* no old resource section */
  1311. {
  1312. if (pObjOld != NULL)
  1313. nObjResource = pObjOld - pObjtblOld;
  1314. else if (pObjDebug != NULL)
  1315. nObjResource = pObjDebug - pObjtblOld;
  1316. else
  1317. nObjResource = New.FileHeader.NumberOfSections;
  1318. New.FileHeader.NumberOfSections++;
  1319. }
  1320. if (nObjResourceX != -1)
  1321. {
  1322. if (pObjResourceOldX != NULL)
  1323. {
  1324. nObjResourceX = pObjResourceOldX - pObjtblOld;
  1325. New.FileHeader.NumberOfSections--;
  1326. }
  1327. else if (pObjOld != NULL)
  1328. nObjResourceX = pObjOld - pObjtblOld;
  1329. else if (pObjDebug != NULL)
  1330. nObjResourceX = pObjDebug - pObjtblOld;
  1331. else
  1332. nObjResourceX = New.FileHeader.NumberOfSections;
  1333. New.FileHeader.NumberOfSections++;
  1334. }
  1335. else if (pObjResourceOldX != NULL) /* Was old .rsrc1 section? */
  1336. {
  1337. New.FileHeader.NumberOfSections--; /* yes, delete it */
  1338. }
  1339. /*
  1340. * If we had to add anything to the header (section table),
  1341. * then we have to update the header size and rva's in the header.
  1342. */
  1343. adjust = (New.FileHeader.NumberOfSections -
  1344. Old.FileHeader.NumberOfSections) * sizeof(IMAGE_SECTION_HEADER);
  1345. cb = Old.OptionalHeader.SizeOfHeaders -
  1346. (Old.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER) +
  1347. sizeof(IMAGE_NT_HEADERS) + cbOldexe );
  1348. if (adjust > (ULONG)cb)
  1349. {
  1350. int i;
  1351. adjust -= cb;
  1352. for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES ; i++)
  1353. {
  1354. if (New.OptionalHeader.DataDirectory[i].VirtualAddress &&
  1355. New.OptionalHeader.DataDirectory[i].VirtualAddress < New.OptionalHeader.SizeOfHeaders)
  1356. {
  1357. New.OptionalHeader.DataDirectory[i].VirtualAddress += adjust;
  1358. }
  1359. }
  1360. New.OptionalHeader.SizeOfHeaders += adjust;
  1361. }
  1362. else if (adjust > 0)
  1363. {
  1364. int i;
  1365. //
  1366. // Loop over DataDirectory entries and look for any entries that point to
  1367. // information stored in the 'dead' space after the section table but before
  1368. // the SizeOfHeaders length.
  1369. //
  1370. for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES ; i++)
  1371. {
  1372. if (New.OptionalHeader.DataDirectory[i].VirtualAddress &&
  1373. New.OptionalHeader.DataDirectory[i].VirtualAddress < Old.OptionalHeader.SizeOfHeaders)
  1374. {
  1375. New.OptionalHeader.DataDirectory[i].VirtualAddress += adjust;
  1376. }
  1377. }
  1378. }
  1379. ibNewObjTabEnd += adjust;
  1380. /* Allocate storage for new section table */
  1381. cb = New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
  1382. pObjtblNew = (PIMAGE_SECTION_HEADER)GodotHeapAlloc((short)cb);
  1383. if (pObjtblNew == NULL)
  1384. {
  1385. cb = ERROR_NOT_ENOUGH_MEMORY;
  1386. goto AbortExit;
  1387. }
  1388. RtlZeroMemory((PVOID)pObjtblNew, cb);
  1389. pObjResourceNew = pObjtblNew + nObjResource;
  1390. /*
  1391. * copy old section table to new
  1392. */
  1393. adjust = 0; /* adjustment to virtual address */
  1394. for (pObjOld=pObjtblOld,pObjNew=pObjtblNew ; pObjOld<pObjLast ; pObjOld++)
  1395. {
  1396. if (pObjOld == pObjResourceOldX)
  1397. {
  1398. if (nObjResourceX == -1)
  1399. {
  1400. // we have to move back all the other section.
  1401. // the .rsrc1 is bigger than what we need
  1402. // adjust must be a negative number
  1403. adjust -= (pObjOld+1)->VirtualAddress - pObjOld->VirtualAddress;
  1404. }
  1405. continue;
  1406. }
  1407. else if (pObjNew == pObjResourceNew)
  1408. {
  1409. cb = ROUNDUP(cbNew, New.OptionalHeader.FileAlignment);
  1410. if (pObjResourceOld == NULL)
  1411. {
  1412. adjust = ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment);
  1413. RtlZeroMemory(pObjNew, sizeof(IMAGE_SECTION_HEADER));
  1414. strcpy(pObjNew->Name, ".rsrc");
  1415. pObjNew->VirtualAddress = pObjOld->VirtualAddress;
  1416. pObjNew->PointerToRawData = pObjOld->PointerToRawData;
  1417. pObjNew->Characteristics = IMAGE_SCN_MEM_READ |
  1418. /*IMAGE_SCN_MEM_WRITE | */
  1419. IMAGE_SCN_CNT_INITIALIZED_DATA;
  1420. pObjNew->SizeOfRawData = cb;
  1421. pObjNew->Misc.VirtualSize = cbNew; //ROUNDUP(cb, New.OptionalHeader.SectionAlignment);
  1422. }
  1423. else
  1424. {
  1425. *pObjNew = *pObjOld; /* copy obj table entry */
  1426. pObjNew->SizeOfRawData = cb;
  1427. pObjNew->Misc.VirtualSize = cbNew; // ROUNDUP(cb, New.OptionalHeader.SectionAlignment);
  1428. if (pObjNew->SizeOfRawData == pObjOld->SizeOfRawData)
  1429. {
  1430. adjust = 0;
  1431. }
  1432. else if (pObjNew->SizeOfRawData > pObjOld->SizeOfRawData)
  1433. {
  1434. adjust += ROUNDUP(cbNew, New.OptionalHeader.SectionAlignment) -
  1435. ((pObjOld+1)->VirtualAddress-pObjOld->VirtualAddress);
  1436. }
  1437. else /* is smaller, but pad so will be valid */
  1438. {
  1439. adjust = 0;
  1440. pObjNew->SizeOfRawData = pObjResourceOld->SizeOfRawData;
  1441. /* if legoized, the VS could be > RawSize !!! */
  1442. pObjNew->Misc.VirtualSize = pObjResourceOld->Misc.VirtualSize;
  1443. cbMustPad = pObjResourceOld->SizeOfRawData;
  1444. }
  1445. }
  1446. pObjNew++;
  1447. if (pObjResourceOld == NULL)
  1448. goto rest_of_table;
  1449. }
  1450. else if (nObjResourceX != -1 && pObjNew == pObjtblNew + nObjResourceX)
  1451. {
  1452. RtlZeroMemory(pObjNew, sizeof(IMAGE_SECTION_HEADER));
  1453. strcpy(pObjNew->Name, ".rsrc1");
  1454. /*
  1455. * Before we copy the virtual address we have to move back the
  1456. * .reloc * virtual address. Otherwise we will keep moving the
  1457. * reloc VirtualAddress forward.
  1458. * We will have to move back the address of .rsrc1
  1459. */
  1460. if (pObjResourceOldX == NULL)
  1461. {
  1462. // This is the first time we have a .rsrc1
  1463. pObjNew->VirtualAddress = pObjOld->VirtualAddress;
  1464. pObjNew->Characteristics = IMAGE_SCN_MEM_READ |
  1465. IMAGE_SCN_MEM_WRITE |
  1466. IMAGE_SCN_CNT_INITIALIZED_DATA;
  1467. adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) +
  1468. pObjResourceNew->VirtualAddress - pObjNew->VirtualAddress;
  1469. }
  1470. else
  1471. {
  1472. // we already have an .rsrc1 use the position of that and
  1473. // calculate the new adjust
  1474. pObjNew->VirtualAddress = pObjResourceOldX->VirtualAddress;
  1475. pObjNew->Characteristics = IMAGE_SCN_MEM_READ |
  1476. IMAGE_SCN_MEM_WRITE |
  1477. IMAGE_SCN_CNT_INITIALIZED_DATA;
  1478. // Check if we have enough room in the old .rsrc1
  1479. // Include the full size of the section, data + roundup
  1480. if (cbResource - (pObjResourceOldX->VirtualAddress - pObjResourceOld->VirtualAddress) <=
  1481. pObjOld->VirtualAddress - pObjNew->VirtualAddress )
  1482. {
  1483. // we have to move back all the other section.
  1484. // the .rsrc1 is bigger than what we need
  1485. // adjust must be a negative number
  1486. // calc new adjust size
  1487. adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) +
  1488. pObjResourceNew->VirtualAddress - pObjOld->VirtualAddress;
  1489. }
  1490. else
  1491. {
  1492. // we have to move the section again.
  1493. // The .rsrc1 is too small
  1494. adjust = ROUNDUP(cbResource, New.OptionalHeader.SectionAlignment) +
  1495. pObjResourceNew->VirtualAddress -
  1496. pObjOld->VirtualAddress;
  1497. }
  1498. }
  1499. pObjNew++;
  1500. goto rest_of_table;
  1501. }
  1502. else if (pObjNew < pObjResourceNew)
  1503. {
  1504. *pObjNew++ = *pObjOld; /* copy obj table entry */
  1505. }
  1506. else
  1507. {
  1508. rest_of_table:
  1509. *pObjNew++ = *pObjOld;
  1510. (pObjNew-1)->VirtualAddress += adjust;
  1511. }
  1512. }
  1513. pObjNew = pObjtblNew + New.FileHeader.NumberOfSections - 1;
  1514. New.OptionalHeader.SizeOfImage = ROUNDUP(pObjNew->VirtualAddress +
  1515. pObjNew->SizeOfRawData, New.OptionalHeader.SectionAlignment);
  1516. /* allocate room to build the resource directory/tables in */
  1517. pResTab = (PIMAGE_RESOURCE_DIRECTORY)GodotHeapAlloc(cbRestab);
  1518. if (pResTab == NULL)
  1519. {
  1520. cb = ERROR_NOT_ENOUGH_MEMORY;
  1521. goto AbortExit;
  1522. }
  1523. /* First, setup the "root" type directory table. It will be followed by */
  1524. /* Types directory entries. */
  1525. RtlZeroMemory((PVOID)pResTab, cbRestab);
  1526. p = (PUCHAR)pResTab;
  1527. pResTab->Characteristics = 0L;
  1528. pResTab->TimeDateStamp = clock;
  1529. pResTab->MajorVersion = MAJOR_RESOURCE_VERSION;
  1530. pResTab->MinorVersion = MINOR_RESOURCE_VERSION;
  1531. pResTab->NumberOfNamedEntries = (USHORT)cTypeStr;
  1532. pResTab->NumberOfIdEntries = (USHORT)(cTypes - cTypeStr);
  1533. /* Calculate the start of the various parts of the resource table. */
  1534. /* We need the start of the Type/Name/Language directories as well */
  1535. /* as the start of the UNICODE strings and the actual data nodes. */
  1536. pResDirT = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTab + 1);
  1537. pResDirN = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(((PUCHAR)pResDirT) +
  1538. cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
  1539. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(((PUCHAR)pResDirN) +
  1540. cTypes * sizeof(IMAGE_RESOURCE_DIRECTORY) +
  1541. cNames * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
  1542. pResData = (PIMAGE_RESOURCE_DATA_ENTRY)(((PUCHAR)pResDirL) +
  1543. cNames * sizeof(IMAGE_RESOURCE_DIRECTORY) +
  1544. cRes * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
  1545. pResStr = (PUSHORT)(((PUCHAR)pResData) +
  1546. cRes * sizeof(IMAGE_RESOURCE_DATA_ENTRY));
  1547. pResStrEnd = (PUSHORT)(((PUCHAR)pResStr) + cbName + cbType);
  1548. /*
  1549. * Loop over type table, building the PE resource table.
  1550. */
  1551. /*
  1552. * *****************************************************************
  1553. * This code doesn't sort the table - the TYPEINFO and RESINFO **
  1554. * insertion code in rcp.c (AddResType and SaveResFile) do the **
  1555. * insertion by ordinal type and name, so we don't have to sort **
  1556. * it at this point. **
  1557. * *****************************************************************
  1558. */
  1559. // First, add all the entries in the Types: Alpha list.
  1560. pType = pUpdate->ResTypeHeadName;
  1561. while (pType)
  1562. {
  1563. pResDirT->Name = (ULONG)((((PUCHAR)pResStr) - p) | IMAGE_RESOURCE_NAME_IS_STRING);
  1564. pResDirT->OffsetToData = (ULONG)((((PUCHAR)pResDirN) - p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1565. pResDirT++;
  1566. *pResStr = pType->Type->cbsz;
  1567. gwcsncpy((WCHAR*)(pResStr+1), pType->Type->szStr, pType->Type->cbsz);
  1568. pResStr += pType->Type->cbsz + 1;
  1569. pResTabN = (PIMAGE_RESOURCE_DIRECTORY)pResDirN;
  1570. SetRestab(pResTabN, clock, (USHORT)pType->NumberOfNamesName, (USHORT)pType->NumberOfNamesID);
  1571. pResDirN = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabN + 1);
  1572. pPreviousName = NULL;
  1573. pRes = pType->NameHeadName;
  1574. while (pRes)
  1575. {
  1576. if (pPreviousName == NULL ||
  1577. gwcsncmp(pPreviousName->szStr, pRes->Name->szStr, pRes->Name->cbsz) != 0)
  1578. {
  1579. // Setup a new name directory
  1580. pResDirN->Name = (ULONG)((((PUCHAR)pResStr)-p) | IMAGE_RESOURCE_NAME_IS_STRING);
  1581. pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1582. pResDirN++;
  1583. // Copy the alpha name to a string entry
  1584. *pResStr = pRes->Name->cbsz;
  1585. gwcsncpy((WCHAR*)(pResStr+1),pRes->Name->szStr,pRes->Name->cbsz);
  1586. pResStr += pRes->Name->cbsz + 1;
  1587. pPreviousName = pRes->Name;
  1588. // Setup the Language table
  1589. pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL;
  1590. SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages);
  1591. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1);
  1592. }
  1593. // Setup a new Language directory
  1594. pResDirL->Name = pRes->LanguageId;
  1595. pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p);
  1596. pResDirL++;
  1597. // Setup a new resource data entry
  1598. SetResdata(pResData,
  1599. pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress,
  1600. pRes->DataSize);
  1601. pResData++;
  1602. pRes = pRes->pnext;
  1603. }
  1604. pPreviousName = NULL;
  1605. pRes = pType->NameHeadID;
  1606. while (pRes)
  1607. {
  1608. if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal)
  1609. {
  1610. // Setup the name directory to point to the next language
  1611. // table
  1612. pResDirN->Name = pRes->Name->uu.Ordinal;
  1613. pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1614. pResDirN++;
  1615. pPreviousName = pRes->Name;
  1616. // Init a new Language table
  1617. pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL;
  1618. SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages);
  1619. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1);
  1620. }
  1621. // Setup a new language directory entry to point to the next
  1622. // resource
  1623. pResDirL->Name = pRes->LanguageId;
  1624. pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p);
  1625. pResDirL++;
  1626. // Setup a new resource data entry
  1627. SetResdata(pResData,
  1628. pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress,
  1629. pRes->DataSize);
  1630. pResData++;
  1631. pRes = pRes->pnext;
  1632. }
  1633. pType = pType->pnext;
  1634. }
  1635. // Do the same thing, but this time, use the Types: ID list.
  1636. pType = pUpdate->ResTypeHeadID;
  1637. while (pType)
  1638. {
  1639. pResDirT->Name = (ULONG)pType->Type->uu.Ordinal;
  1640. pResDirT->OffsetToData = (ULONG)((((PUCHAR)pResDirN) - p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1641. pResDirT++;
  1642. pResTabN = (PIMAGE_RESOURCE_DIRECTORY)pResDirN;
  1643. SetRestab(pResTabN, clock, (USHORT)pType->NumberOfNamesName, (USHORT)pType->NumberOfNamesID);
  1644. pResDirN = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabN + 1);
  1645. pPreviousName = NULL;
  1646. pRes = pType->NameHeadName;
  1647. while (pRes)
  1648. {
  1649. if (pPreviousName == NULL ||
  1650. gwcsncmp(pPreviousName->szStr, pRes->Name->szStr, pRes->Name->cbsz) != 0)
  1651. {
  1652. // Setup a new name directory
  1653. pResDirN->Name = (ULONG)((((PUCHAR)pResStr)-p) | IMAGE_RESOURCE_NAME_IS_STRING);
  1654. pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1655. pResDirN++;
  1656. // Copy the alpha name to a string entry.
  1657. *pResStr = pRes->Name->cbsz;
  1658. gwcsncpy((WCHAR*)(pResStr+1),pRes->Name->szStr,pRes->Name->cbsz);
  1659. pResStr += pRes->Name->cbsz + 1;
  1660. pPreviousName = pRes->Name;
  1661. // Setup the Language table
  1662. pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL;
  1663. SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages);
  1664. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1);
  1665. }
  1666. // Setup a new Language directory
  1667. pResDirL->Name = pRes->LanguageId;
  1668. pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p);
  1669. pResDirL++;
  1670. // Setup a new resource data entry
  1671. SetResdata(pResData,
  1672. pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress,
  1673. pRes->DataSize);
  1674. pResData++;
  1675. pRes = pRes->pnext;
  1676. }
  1677. pPreviousName = NULL;
  1678. pRes = pType->NameHeadID;
  1679. while (pRes)
  1680. {
  1681. if (pPreviousName == NULL || pPreviousName->uu.Ordinal != pRes->Name->uu.Ordinal)
  1682. {
  1683. // Setup the name directory to point to the next language
  1684. // table
  1685. pResDirN->Name = pRes->Name->uu.Ordinal;
  1686. pResDirN->OffsetToData = (ULONG)((((PUCHAR)pResDirL)-p) | IMAGE_RESOURCE_DATA_IS_DIRECTORY);
  1687. pResDirN++;
  1688. pPreviousName = pRes->Name;
  1689. // Init a new Language table
  1690. pResTabL = (PIMAGE_RESOURCE_DIRECTORY)pResDirL;
  1691. SetRestab(pResTabL, clock, (USHORT)0, (USHORT)pRes->NumberOfLanguages);
  1692. pResDirL = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pResTabL + 1);
  1693. }
  1694. // Setup a new language directory entry to point to the next
  1695. // resource
  1696. pResDirL->Name = pRes->LanguageId;
  1697. pResDirL->OffsetToData = (ULONG)(((PUCHAR)pResData) - p);
  1698. pResDirL++;
  1699. // Setup a new resource data entry
  1700. SetResdata(pResData, pRes->OffsetToData+pObjtblNew[nObjResource].VirtualAddress, pRes->DataSize);
  1701. pResData++;
  1702. pRes = pRes->pnext;
  1703. }
  1704. pType = pType->pnext;
  1705. }
  1706. while (pResStr < pResStrEnd)
  1707. {
  1708. *pResStr++ = 0;
  1709. }
  1710. /*
  1711. * copy the Old exe header and stub, and allocate room for the PE header.
  1712. */
  1713. MuMoveFilePos(inpfh, 0L);
  1714. MuCopy(inpfh, outfh, cbOldexe + sizeof(IMAGE_NT_HEADERS));
  1715. /*
  1716. * Copy rest of file header
  1717. */
  1718. MuMoveFilePos(outfh, ibNewObjTabEnd + New.OptionalHeader.SizeOfHeaders -
  1719. Old.OptionalHeader.SizeOfHeaders);
  1720. MuMoveFilePos(inpfh, ibObjTabEnd);
  1721. MuCopy(inpfh, outfh, Old.OptionalHeader.SizeOfHeaders - ibNewObjTabEnd);
  1722. /*
  1723. * copy existing image sections
  1724. */
  1725. /* Align data sections on sector boundary */
  1726. cb = REMAINDER(New.OptionalHeader.SizeOfHeaders, New.OptionalHeader.FileAlignment);
  1727. New.OptionalHeader.SizeOfHeaders += cb;
  1728. while (cb >= cbPadMax)
  1729. {
  1730. MuWrite(outfh, pchZero, cbPadMax);
  1731. cb -= cbPadMax;
  1732. }
  1733. MuWrite(outfh, pchZero, cb);
  1734. cb = ROUNDUP(Old.OptionalHeader.SizeOfHeaders, Old.OptionalHeader.FileAlignment);
  1735. MuMoveFilePos(inpfh, cb);
  1736. /* copy one section at a time */
  1737. New.OptionalHeader.SizeOfInitializedData = 0;
  1738. for (pObjOld = pObjtblOld , pObjNew = pObjtblNew ; pObjOld < pObjLast ; pObjNew++)
  1739. {
  1740. if (pObjOld == pObjResourceOldX)
  1741. pObjOld++;
  1742. if (pObjNew == pObjResourceNew)
  1743. {
  1744. /* Write new resource section */
  1745. pObjNew->PointerToRawData = FilePos(outfh);
  1746. New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = pObjResourceNew->VirtualAddress;
  1747. New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = cbResource;
  1748. ibSave = FilePos(outfh);
  1749. MuWrite(outfh, (PUCHAR)pResTab, cbRestab);
  1750. pResSave = WriteResSection(pUpdate, outfh, New.OptionalHeader.FileAlignment,
  1751. pObjResourceNew->SizeOfRawData-cbRestab, NULL);
  1752. cb = FilePos(outfh);
  1753. if (cbMustPad != 0)
  1754. {
  1755. cbMustPad -= cb - ibSave;
  1756. /* assumes that cbMustPad % cbpadMax == 0 */
  1757. while (cbMustPad > 0)
  1758. {
  1759. MuWrite(outfh, pchZero, cbPadMax);
  1760. cbMustPad -= cbPadMax;
  1761. }
  1762. cb = FilePos(outfh);
  1763. }
  1764. if (nObjResourceX == -1)
  1765. {
  1766. MuMoveFilePos(outfh, ibSave);
  1767. MuWrite(outfh, (PUCHAR)pResTab, cbRestab);
  1768. MuMoveFilePos(outfh, cb);
  1769. cb = FilePos(inpfh);
  1770. MuMoveFilePos(inpfh, cb+pObjOld->SizeOfRawData);
  1771. }
  1772. New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData;
  1773. if (pObjResourceOld == NULL)
  1774. {
  1775. pObjNew++;
  1776. goto next_section;
  1777. }
  1778. else
  1779. pObjOld++;
  1780. }
  1781. else if (nObjResourceX != -1 && pObjNew == pObjtblNew + nObjResourceX)
  1782. {
  1783. /* Write new resource section */
  1784. pObjNew->PointerToRawData = FilePos(outfh);
  1785. (void)WriteResSection(pUpdate, outfh, New.OptionalHeader.FileAlignment, 0xffffffff, pResSave);
  1786. cb = FilePos(outfh);
  1787. pObjNew->SizeOfRawData = cb - pObjNew->PointerToRawData;
  1788. pObjNew->Misc.VirtualSize = ROUNDUP(pObjNew->SizeOfRawData,
  1789. New.OptionalHeader.SectionAlignment);
  1790. MuMoveFilePos(outfh, ibSave);
  1791. MuWrite(outfh, (PUCHAR)pResTab, cbRestab);
  1792. MuMoveFilePos(outfh, cb);
  1793. New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData;
  1794. pObjNew++;
  1795. goto next_section;
  1796. }
  1797. else
  1798. {
  1799. if (pObjNew < pObjResourceNew &&
  1800. pObjOld->PointerToRawData != 0 &&
  1801. pObjOld->PointerToRawData != FilePos(outfh))
  1802. {
  1803. MuMoveFilePos(outfh, pObjOld->PointerToRawData);
  1804. }
  1805. next_section:
  1806. if (pObjOld->PointerToRawData != 0)
  1807. {
  1808. pObjNew->PointerToRawData = FilePos(outfh);
  1809. MuMoveFilePos(inpfh, pObjOld->PointerToRawData);
  1810. MuCopy(inpfh, outfh, pObjOld->SizeOfRawData);
  1811. }
  1812. if (pObjOld == pObjDebugDirOld)
  1813. {
  1814. pObjDebugDirNew = pObjNew;
  1815. }
  1816. if ((pObjNew->Characteristics&IMAGE_SCN_CNT_INITIALIZED_DATA) != 0)
  1817. New.OptionalHeader.SizeOfInitializedData += pObjNew->SizeOfRawData;
  1818. pObjOld++;
  1819. }
  1820. }
  1821. if (pObjResourceOldX != NULL)
  1822. New.OptionalHeader.SizeOfInitializedData -= pObjResourceOldX->SizeOfRawData;
  1823. /* Update the address of the relocation table */
  1824. pObjNew = FindSection(pObjtblNew, pObjtblNew+New.FileHeader.NumberOfSections, ".reloc");
  1825. if (pObjNew != NULL)
  1826. {
  1827. New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = pObjNew->VirtualAddress;
  1828. }
  1829. /*
  1830. * Write new section table out.
  1831. */
  1832. MuMoveFilePos(outfh, ibObjTab);
  1833. MuWrite(outfh, (PUCHAR)pObjtblNew, New.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
  1834. /* Seek to end of output file and issue truncating write */
  1835. adjust = _llseek(outfh, 0L, SEEK_END);
  1836. MuWrite(outfh, NULL, 0);
  1837. /* If a debug section, fix up the debug table */
  1838. pObjNew = FindSection(pObjtblNew, pObjtblNew+New.FileHeader.NumberOfSections, ".debug");
  1839. cb = PatchDebug(inpfh, outfh, pObjDebug, pObjNew, pObjDebugDirOld,
  1840. pObjDebugDirNew, &Old, &New, ibMaxDbgOffsetOld, &adjust);
  1841. if (cb == NO_ERROR)
  1842. {
  1843. if (pObjResourceOld == NULL)
  1844. {
  1845. cb = (LONG)pObjResourceNew->SizeOfRawData;
  1846. }
  1847. else
  1848. {
  1849. cb = (LONG)pObjResourceOld->SizeOfRawData - (LONG)pObjResourceNew->SizeOfRawData;
  1850. }
  1851. cb = PatchRVAs(inpfh, outfh, pObjtblNew, cb, &New, Old.OptionalHeader.SizeOfHeaders);
  1852. }
  1853. /* copy NOTMAPPED debug info */
  1854. if (pObjDebugDirOld != NULL && pObjDebug == NULL &&
  1855. New.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0)
  1856. {
  1857. ULONG ibt;
  1858. ibSave = _llseek(inpfh, 0L, SEEK_END); /* copy debug data */
  1859. ibt = _llseek(outfh, 0L, SEEK_END); /* to EOF */
  1860. if (New.FileHeader.PointerToSymbolTable != 0)
  1861. New.FileHeader.PointerToSymbolTable += ibt - adjust;
  1862. MuMoveFilePos(inpfh, adjust); /* returned by PatchDebug */
  1863. MuCopy(inpfh, outfh, ibSave-adjust);
  1864. }
  1865. /*
  1866. * Write updated PE header
  1867. */
  1868. MuMoveFilePos(outfh, (long)cbOldexe);
  1869. MuWrite(outfh, (char*)&New, sizeof(IMAGE_NT_HEADERS));
  1870. /* free up allocated memory */
  1871. GodotHeapFree( pObjtblOld);
  1872. GodotHeapFree( pResTab);
  1873. AbortExit:
  1874. GodotHeapFree( pObjtblNew);
  1875. return cb;
  1876. }
  1877. /***************************************************************************
  1878. * WriteResSection
  1879. *
  1880. * This routine writes out the resources asked for into the current section.
  1881. * It pads resources to dword (4-byte) boundaries.
  1882. **************************************************************************/
  1883. PRESNAME WriteResSection(PUPDATEDATA pUpdate, INT outfh, ULONG align, ULONG cbLeft, PRESNAME pResSave)
  1884. {
  1885. ULONG cbB=0; /* bytes in current section */
  1886. ULONG cbT; /* bytes in current section */
  1887. ULONG size;
  1888. PRESNAME pRes;
  1889. PRESTYPE pType;
  1890. BOOL fName;
  1891. PVOID lpData;
  1892. /* Output contents associated with each resource */
  1893. pType = pUpdate->ResTypeHeadName;
  1894. while (pType) {
  1895. pRes = pType->NameHeadName;
  1896. fName = TRUE;
  1897. loop1:
  1898. for ( ; pRes ; pRes = pRes->pnext)
  1899. {
  1900. if (pResSave != NULL && pRes != pResSave)
  1901. continue;
  1902. pResSave = NULL;
  1903. lpData = (PVOID)pRes->OffsetToDataEntry;
  1904. /* if there is room in the current section, write it there */
  1905. size = pRes->DataSize;
  1906. if (cbLeft != 0 && cbLeft >= size) /* resource fits? */
  1907. {
  1908. MuWrite(outfh, lpData, size);
  1909. /* pad resource */
  1910. cbT = REMAINDER(size, CBLONG);
  1911. MuWrite(outfh, pchPad, cbT); /* dword */
  1912. cbB += size + cbT;
  1913. cbLeft -= size + cbT; /* less left */
  1914. continue; /* next resource */
  1915. }
  1916. else /* will fill up section */
  1917. {
  1918. goto write_pad;
  1919. }
  1920. }
  1921. if (fName)
  1922. {
  1923. fName = FALSE;
  1924. pRes = pType->NameHeadID;
  1925. goto loop1;
  1926. }
  1927. pType = pType->pnext;
  1928. }
  1929. pType = pUpdate->ResTypeHeadID;
  1930. while (pType)
  1931. {
  1932. pRes = pType->NameHeadName;
  1933. fName = TRUE;
  1934. loop2:
  1935. for ( ; pRes ; pRes = pRes->pnext)
  1936. {
  1937. if (pResSave != NULL && pRes != pResSave)
  1938. continue;
  1939. pResSave = NULL;
  1940. lpData = (PVOID)pRes->OffsetToDataEntry;
  1941. /* if there is room in the current section, write it there */
  1942. size = pRes->DataSize;
  1943. if (cbLeft != 0 && cbLeft >= size) /* resource fits? */
  1944. {
  1945. MuWrite(outfh, lpData, size);
  1946. /* pad resource */
  1947. cbT = REMAINDER(size, CBLONG);
  1948. MuWrite(outfh, pchPad, cbT); /* dword */
  1949. cbB += size + cbT;
  1950. cbLeft -= size + cbT; /* less left */
  1951. continue; /* next resource */
  1952. }
  1953. else /* will fill up section */
  1954. {
  1955. goto write_pad;
  1956. }
  1957. }
  1958. if (fName)
  1959. {
  1960. fName = FALSE;
  1961. pRes = pType->NameHeadID;
  1962. goto loop2;
  1963. }
  1964. pType = pType->pnext;
  1965. }
  1966. pRes = NULL;
  1967. write_pad:
  1968. /* pad to alignment boundary */
  1969. cbB = FilePos(outfh);
  1970. cbT = ROUNDUP(cbB, align);
  1971. cbLeft = cbT - cbB;
  1972. if (cbLeft != 0)
  1973. {
  1974. while (cbLeft >= cbPadMax)
  1975. {
  1976. MuWrite(outfh, pchPad, cbPadMax);
  1977. cbLeft -= cbPadMax;
  1978. }
  1979. MuWrite(outfh, pchPad, cbLeft);
  1980. }
  1981. return pRes;
  1982. }
  1983. LONG PatchDebug(int inpfh, int outfh, PIMAGE_SECTION_HEADER pDebugOld, PIMAGE_SECTION_HEADER pDebugNew,
  1984. PIMAGE_SECTION_HEADER pDebugDirOld, PIMAGE_SECTION_HEADER pDebugDirNew,
  1985. PIMAGE_NT_HEADERS pOld, PIMAGE_NT_HEADERS pNew, ULONG ibMaxDbgOffsetOld,
  1986. PULONG pPointerToRawData)
  1987. //
  1988. // adjust debug directory table
  1989. //
  1990. {
  1991. PIMAGE_DEBUG_DIRECTORY pDbgLast;
  1992. PIMAGE_DEBUG_DIRECTORY pDbgSave;
  1993. PIMAGE_DEBUG_DIRECTORY pDbg;
  1994. ULONG ib;
  1995. ULONG adjust;
  1996. ULONG ibNew;
  1997. if (pDebugDirOld == NULL || pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size==0)
  1998. return NO_ERROR;
  1999. pDbg = (PIMAGE_DEBUG_DIRECTORY)GodotHeapAlloc(pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
  2000. pDbgSave = pDbg;
  2001. if (pDbg == NULL)
  2002. return ERROR_NOT_ENOUGH_MEMORY;
  2003. if (pDebugOld)
  2004. {
  2005. }
  2006. else
  2007. adjust = *pPointerToRawData; /* passed in EOF of new file */
  2008. ib = pOld->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress - pDebugDirOld->VirtualAddress;
  2009. MuMoveFilePos(inpfh, pDebugDirOld->PointerToRawData+ib);
  2010. pDbgLast = pDbg + (pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size)/sizeof(IMAGE_DEBUG_DIRECTORY);
  2011. MuRead(inpfh, (PUCHAR)pDbg, pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
  2012. if (pDebugOld == NULL)
  2013. {
  2014. /* find 1st entry - use for offset */
  2015. for (ibNew=0xffffffff ; pDbg<pDbgLast ; pDbg++)
  2016. if (pDbg->PointerToRawData >= ibMaxDbgOffsetOld && pDbg->PointerToRawData < ibNew)
  2017. ibNew = pDbg->PointerToRawData;
  2018. if (ibNew != 0xffffffff)
  2019. *pPointerToRawData = ibNew;
  2020. else
  2021. *pPointerToRawData = _llseek(inpfh, 0L, SEEK_END);
  2022. for (pDbg=pDbgSave ; pDbg<pDbgLast ; pDbg++)
  2023. {
  2024. if (pDbg->PointerToRawData >= ibMaxDbgOffsetOld)
  2025. pDbg->PointerToRawData += adjust - ibNew;
  2026. }
  2027. }
  2028. else
  2029. {
  2030. for ( ; pDbg<pDbgLast ; pDbg++)
  2031. {
  2032. pDbg->AddressOfRawData += pDebugNew->VirtualAddress - pDebugOld->VirtualAddress;
  2033. pDbg->PointerToRawData += pDebugNew->PointerToRawData - pDebugOld->PointerToRawData;
  2034. }
  2035. }
  2036. MuMoveFilePos(outfh, pDebugDirNew->PointerToRawData+ib);
  2037. MuWrite(outfh, (PUCHAR)pDbgSave, pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size);
  2038. GodotHeapFree(pDbgSave);
  2039. return NO_ERROR;
  2040. }
  2041. //
  2042. // This routine patches various RVAs in the file to compensate
  2043. // for extra section table entries.
  2044. //
  2045. LONG PatchRVAs(int inpfh, int outfh, PIMAGE_SECTION_HEADER po32,
  2046. ULONG pagedelta, PIMAGE_NT_HEADERS pNew, ULONG OldSize)
  2047. {
  2048. ULONG hdrdelta;
  2049. ULONG offset, rvaiat, offiat, iat;
  2050. IMAGE_EXPORT_DIRECTORY Exp;
  2051. IMAGE_IMPORT_DESCRIPTOR Imp;
  2052. ULONG i, cmod, cimp;
  2053. hdrdelta = pNew->OptionalHeader.SizeOfHeaders - OldSize;
  2054. if (hdrdelta == 0)
  2055. {
  2056. return NO_ERROR;
  2057. }
  2058. //
  2059. // Patch export section RVAs
  2060. //
  2061. offset = ((pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) == 0);
  2062. if (offset < pNew->OptionalHeader.SizeOfHeaders)
  2063. {
  2064. MuMoveFilePos(inpfh, offset - hdrdelta);
  2065. MuRead(inpfh, (PUCHAR) &Exp, sizeof(Exp));
  2066. Exp.Name += hdrdelta;
  2067. (ULONG)Exp.AddressOfFunctions += hdrdelta;
  2068. (ULONG)Exp.AddressOfNames += hdrdelta;
  2069. (ULONG)Exp.AddressOfNameOrdinals += hdrdelta;
  2070. MuMoveFilePos(outfh, offset);
  2071. MuWrite(outfh, (PUCHAR) &Exp, sizeof(Exp));
  2072. }
  2073. //
  2074. // Patch import section RVAs
  2075. //
  2076. offset = ((pNew->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) == 0);
  2077. if (offset < pNew->OptionalHeader.SizeOfHeaders)
  2078. {
  2079. for (cimp = cmod = 0; ; cmod++)
  2080. {
  2081. MuMoveFilePos(inpfh, offset + cmod * sizeof(Imp) - hdrdelta);
  2082. MuRead(inpfh, (PUCHAR) &Imp, sizeof(Imp));
  2083. if (Imp.FirstThunk == 0)
  2084. {
  2085. break;
  2086. }
  2087. Imp.Name += hdrdelta;
  2088. MuMoveFilePos(outfh, offset + cmod * sizeof(Imp));
  2089. MuWrite(outfh, (PUCHAR) &Imp, sizeof(Imp));
  2090. rvaiat = (ULONG)Imp.FirstThunk;
  2091. for (i = 0; i < pNew->FileHeader.NumberOfSections; i++)
  2092. {
  2093. if (rvaiat >= po32[i].VirtualAddress &&
  2094. rvaiat < po32[i].VirtualAddress + po32[i].SizeOfRawData)
  2095. {
  2096. offiat = rvaiat - po32[i].VirtualAddress + po32[i].PointerToRawData;
  2097. goto found;
  2098. }
  2099. }
  2100. return ERROR_INVALID_DATA;
  2101. found:
  2102. MuMoveFilePos(inpfh, offiat - pagedelta);
  2103. MuMoveFilePos(outfh, offiat);
  2104. for (;;)
  2105. {
  2106. MuRead(inpfh, (PUCHAR) &iat, sizeof(iat));
  2107. if (iat == 0)
  2108. {
  2109. break;
  2110. }
  2111. if ((iat & IMAGE_ORDINAL_FLAG) == 0) // if import by name
  2112. {
  2113. iat += hdrdelta;
  2114. cimp++;
  2115. }
  2116. MuWrite(outfh, (PUCHAR) &iat, sizeof(iat)); // Avoids seeking
  2117. }
  2118. }
  2119. }
  2120. return NO_ERROR;
  2121. }
  2122. /*---------------------------------------------------------------------------*/
  2123. /* */
  2124. /* WriteResFile() - */
  2125. /* */
  2126. /*---------------------------------------------------------------------------*/
  2127. LONG WriteResFile(HANDLE hUpdate, WCHAR *pDstname)
  2128. {
  2129. INT inpfh;
  2130. INT outfh;
  2131. ULONG onewexe;
  2132. IMAGE_DOS_HEADER oldexe;
  2133. PUPDATEDATA pUpdate;
  2134. INT rc;
  2135. WCHAR *pFilename;
  2136. pUpdate = (PUPDATEDATA)GlobalLock(hUpdate);
  2137. pFilename = (WCHAR*)GlobalLock(pUpdate->hFileName);
  2138. /* open the original exe file */
  2139. inpfh = (INT)CreateFileW(pFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  2140. GlobalUnlock(pUpdate->hFileName);
  2141. if (inpfh == -1)
  2142. {
  2143. GlobalUnlock(hUpdate);
  2144. return ERROR_OPEN_FAILED;
  2145. }
  2146. /* read the old format EXE header */
  2147. rc = _lread(inpfh, (char*)&oldexe, sizeof(oldexe));
  2148. if (rc != sizeof(oldexe))
  2149. {
  2150. _lclose(inpfh);
  2151. GlobalUnlock(hUpdate);
  2152. return ERROR_READ_FAULT;
  2153. }
  2154. /* make sure its really an EXE file */
  2155. if (oldexe.e_magic != IMAGE_DOS_SIGNATURE)
  2156. {
  2157. _lclose(inpfh);
  2158. GlobalUnlock(hUpdate);
  2159. return ERROR_INVALID_EXE_SIGNATURE;
  2160. }
  2161. /* make sure theres a new EXE header floating around somewhere */
  2162. if (!(onewexe = oldexe.e_lfanew))
  2163. {
  2164. _lclose(inpfh);
  2165. GlobalUnlock(hUpdate);
  2166. return ERROR_BAD_EXE_FORMAT;
  2167. }
  2168. outfh = (INT)CreateFileW(pDstname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
  2169. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  2170. if (outfh != -1)
  2171. {
  2172. rc = PEWriteResFile(inpfh, outfh, onewexe, pUpdate);
  2173. _lclose(outfh);
  2174. }
  2175. _lclose(inpfh);
  2176. GlobalUnlock(hUpdate);
  2177. return rc;
  2178. }