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.

1720 lines
51 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 "basedll.h"
  12. #pragma hdrstop
  13. #include <updrsrc.h>
  14. #include <strsafe.h>
  15. char *pchPad = "PADDINGXXPADDING";
  16. char *pchZero = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
  17. #define FREE_RES_ID( _Res_ ) \
  18. if (IS_ID == (_Res_)->discriminant) \
  19. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)(_Res_)) \
  20. /****************************************************************************
  21. **
  22. ** API entry points
  23. **
  24. ****************************************************************************/
  25. HANDLE
  26. APIENTRY
  27. BeginUpdateResourceW(
  28. LPCWSTR pwch,
  29. BOOL bDeleteExistingResources
  30. )
  31. /*++
  32. Routine Description
  33. Begins an update of resources. Save away the name
  34. and current resources in a list, using EnumResourceXxx
  35. api set.
  36. Parameters:
  37. lpFileName - Supplies the name of the executable file that the
  38. resource specified by lpType/lpName/language will be updated
  39. in. This file must be able to be opened for writing (ie, not
  40. currently executing, etc.) The file may be fully qualified,
  41. or if not, the current directory is assumed. It must be a
  42. valid Windows executable file.
  43. bDeleteExistingResources - if TRUE, existing resources are
  44. deleted, and only new resources will appear in the result.
  45. Otherwise, all resources in the input file will be in the
  46. output file unless specifically deleted or replaced.
  47. Return Value:
  48. NULL - The file specified was not able to be opened for writing.
  49. Either it was not an executable image, the executable image is
  50. already loaded, or the filename did not exist. More information may
  51. be available via GetLastError api.
  52. HANDLE - A handle to be passed to the UpdateResource and
  53. EndUpdateResources function.
  54. --*/
  55. {
  56. HMODULE hModule;
  57. PUPDATEDATA pUpdate;
  58. HANDLE hUpdate;
  59. LPWSTR pFileName;
  60. DWORD attr;
  61. size_t cchFileNameLen;
  62. HRESULT hr;
  63. SetLastError(NO_ERROR);
  64. if (pwch == NULL) {
  65. SetLastError(ERROR_INVALID_PARAMETER);
  66. goto cleanup;
  67. }
  68. hUpdate = GlobalAlloc(GHND, sizeof(UPDATEDATA));
  69. if (hUpdate == NULL) {
  70. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  71. goto cleanup;
  72. }
  73. pUpdate = (PUPDATEDATA)GlobalLock(hUpdate);
  74. if (pUpdate == NULL) {
  75. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  76. goto cleanup_hupdate;
  77. }
  78. hr = StringCchLengthW(pwch, STRSAFE_MAX_CCH, &cchFileNameLen);
  79. if (FAILED(hr)) {
  80. SetLastError(HRESULT_CODE(hr));
  81. goto cleanup_pupdate;
  82. }
  83. pUpdate->Status = NO_ERROR;
  84. pUpdate->hFileName = GlobalAlloc(GHND, (cchFileNameLen+1)*sizeof(WCHAR));
  85. if (pUpdate->hFileName == NULL) {
  86. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  87. goto cleanup_pupdate;
  88. }
  89. pFileName = (LPWSTR)GlobalLock(pUpdate->hFileName);
  90. if (pFileName == NULL) {
  91. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  92. goto cleanup_pfilename;
  93. }
  94. hr = StringCchCopyW(pFileName,
  95. cchFileNameLen + 1,
  96. pwch);
  97. GlobalUnlock(pUpdate->hFileName);
  98. if (FAILED(hr)) {
  99. SetLastError(HRESULT_CODE(hr));
  100. goto cleanup_pfilename;
  101. }
  102. attr = GetFileAttributesW(pFileName);
  103. if (attr == 0xffffffff) {
  104. goto cleanup_pfilename;
  105. } else if (attr & (FILE_ATTRIBUTE_READONLY |
  106. FILE_ATTRIBUTE_SYSTEM |
  107. FILE_ATTRIBUTE_HIDDEN |
  108. FILE_ATTRIBUTE_DIRECTORY)) {
  109. SetLastError(ERROR_WRITE_PROTECT);
  110. goto cleanup_pfilename;
  111. }
  112. if (bDeleteExistingResources)
  113. ;
  114. else {
  115. hModule = LoadLibraryExW(pwch, NULL,LOAD_LIBRARY_AS_DATAFILE| DONT_RESOLVE_DLL_REFERENCES);
  116. if (hModule == NULL) {
  117. if (GetLastError() == NO_ERROR)
  118. SetLastError(ERROR_BAD_EXE_FORMAT);
  119. goto cleanup_pfilename;
  120. } else
  121. EnumResourceTypesW(hModule, (ENUMRESTYPEPROCW)EnumTypesFunc, (LONG_PTR)pUpdate);
  122. FreeLibrary(hModule);
  123. }
  124. if (pUpdate->Status != NO_ERROR) {
  125. // return code set by enum functions
  126. goto cleanup_pfilename;
  127. }
  128. GlobalUnlock(hUpdate);
  129. return hUpdate;
  130. cleanup_pfilename:
  131. GlobalFree(pUpdate->hFileName);
  132. cleanup_pupdate:
  133. GlobalUnlock(hUpdate);
  134. cleanup_hupdate:
  135. GlobalFree(hUpdate);
  136. cleanup:
  137. return NULL;
  138. }
  139. HANDLE
  140. APIENTRY
  141. BeginUpdateResourceA(
  142. LPCSTR pch,
  143. BOOL bDeleteExistingResources
  144. )
  145. /*++
  146. Routine Description
  147. ASCII entry point. Convert filename to UNICODE and call
  148. the UNICODE entry point.
  149. --*/
  150. {
  151. PUNICODE_STRING Unicode;
  152. ANSI_STRING AnsiString;
  153. NTSTATUS Status;
  154. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  155. RtlInitAnsiString(&AnsiString, pch);
  156. Status = RtlAnsiStringToUnicodeString(Unicode, &AnsiString, FALSE);
  157. if ( !NT_SUCCESS(Status) ) {
  158. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  159. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  160. } else {
  161. //BaseSetLastNTError(Status);
  162. SetLastError(RtlNtStatusToDosError(Status));
  163. }
  164. return FALSE;
  165. }
  166. return BeginUpdateResourceW((LPCWSTR)Unicode->Buffer,bDeleteExistingResources);
  167. }
  168. BOOL
  169. APIENTRY
  170. UpdateResourceW(
  171. HANDLE hUpdate,
  172. LPCWSTR lpType,
  173. LPCWSTR lpName,
  174. WORD language,
  175. LPVOID lpData,
  176. ULONG cb
  177. )
  178. /*++
  179. Routine Description
  180. This routine adds, deletes or modifies the input resource
  181. in the list initialized by BeginUpdateResource. The modify
  182. case is simple, the add is easy, the delete is hard.
  183. The ASCII entry point converts inputs to UNICODE.
  184. Parameters:
  185. hUpdateFile - The handle returned by the BeginUpdateResources
  186. function.
  187. lpType - Points to a null-terminated character string that
  188. represents the type name of the resource to be updated or
  189. added. May be an integer value passed to MAKEINTRESOURCE
  190. macro. For predefined resource types, the lpType parameter
  191. should be one of the following values:
  192. RT_ACCELERATOR - Accelerator table
  193. RT_BITMAP - Bitmap resource
  194. RT_DIALOG - Dialog box
  195. RT_FONT - Font resource
  196. RT_FONTDIR - Font directory resource
  197. RT_MENU - Menu resource
  198. RT_RCDATA - User-defined resource (raw data)
  199. RT_VERSION - Version resource
  200. RT_ICON - Icon resource
  201. RT_CURSOR - Cursor resource
  202. lpName - Points to a null-terminated character string that
  203. represents the name of the resource to be updated or added.
  204. May be an integer value passed to MAKEINTRESOURCE macro.
  205. language - Is the word value that specifies the language of the
  206. resource to be updated. A complete list of values is
  207. available in winnls.h.
  208. lpData - A pointer to the raw data to be inserted into the
  209. executable image's resource table and data. If the data is
  210. one of the predefined types, it must be valid and properly
  211. aligned. If lpData is NULL, the specified resource is to be
  212. deleted from the executable image.
  213. cb - count of bytes in the data.
  214. Return Value:
  215. TRUE - The resource specified was successfully replaced in, or added
  216. to, the specified executable image.
  217. FALSE/NULL - The resource specified was not successfully added to or
  218. updated in the executable image. More information may be available
  219. via GetLastError api.
  220. --*/
  221. {
  222. PUPDATEDATA pUpdate;
  223. PSDATA Type;
  224. PSDATA Name;
  225. PVOID lpCopy;
  226. LONG fRet;
  227. SetLastError(0);
  228. pUpdate = (PUPDATEDATA)GlobalLock(hUpdate);
  229. if (pUpdate == NULL) {
  230. // GlobalLock set last error, nothing to unlock.
  231. return FALSE;
  232. }
  233. Name = AddStringOrID(lpName, pUpdate);
  234. if (Name == NULL) {
  235. pUpdate->Status = ERROR_NOT_ENOUGH_MEMORY;
  236. GlobalUnlock(hUpdate);
  237. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  238. return FALSE;
  239. }
  240. Type = AddStringOrID(lpType, pUpdate);
  241. if (Type == NULL) {
  242. pUpdate->Status = ERROR_NOT_ENOUGH_MEMORY;
  243. FREE_RES_ID(Name);
  244. FreeStrings(pUpdate);
  245. GlobalUnlock(hUpdate);
  246. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  247. return FALSE;
  248. }
  249. if (cb == 0) {
  250. lpCopy = NULL;
  251. } else {
  252. lpCopy = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), cb);
  253. if (lpCopy == NULL) {
  254. pUpdate->Status = ERROR_NOT_ENOUGH_MEMORY;
  255. FREE_RES_ID(Type);
  256. FREE_RES_ID(Name);
  257. FreeStrings(pUpdate);
  258. GlobalUnlock(hUpdate);
  259. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  260. return FALSE;
  261. }
  262. RtlCopyMemory(lpCopy, lpData, cb);
  263. }
  264. fRet = AddResource(Type, Name, language, pUpdate, lpCopy, cb);
  265. if (fRet == NO_ERROR) {
  266. GlobalUnlock(hUpdate);
  267. return TRUE;
  268. } else {
  269. FreeData(pUpdate);
  270. GlobalUnlock(hUpdate);
  271. if (lpCopy != NULL)
  272. RtlFreeHeap(RtlProcessHeap(), 0, lpCopy);
  273. SetLastError(fRet);
  274. return FALSE;
  275. }
  276. }
  277. BOOL
  278. APIENTRY
  279. UpdateResourceA(
  280. HANDLE hUpdate,
  281. LPCSTR lpType,
  282. LPCSTR lpName,
  283. WORD language,
  284. LPVOID lpData,
  285. ULONG cb
  286. )
  287. {
  288. LPCWSTR lpwType;
  289. LPCWSTR lpwName;
  290. INT cch;
  291. UNICODE_STRING UnicodeType;
  292. UNICODE_STRING UnicodeName;
  293. STRING string;
  294. BOOL result;
  295. NTSTATUS Status;
  296. RtlInitUnicodeString(&UnicodeType, NULL);
  297. RtlInitUnicodeString(&UnicodeName, NULL);
  298. __try {
  299. if ((ULONG_PTR)lpType >= LDR_RESOURCE_ID_NAME_MINVAL) {
  300. cch = strlen(lpType);
  301. string.Length = (USHORT)cch;
  302. // string.MaximumLength = (USHORT)cch + sizeof(CHAR); /* unnecessary */
  303. string.Buffer = (PCHAR)lpType;
  304. Status = RtlAnsiStringToUnicodeString(&UnicodeType, &string, TRUE);
  305. if (! NT_SUCCESS(Status)) {
  306. BaseSetLastNTError(Status);
  307. result = FALSE;
  308. __leave;
  309. }
  310. lpwType = (LPCWSTR)UnicodeType.Buffer;
  311. } else {
  312. lpwType = (LPCWSTR)lpType;
  313. }
  314. if ((ULONG_PTR)lpName >= LDR_RESOURCE_ID_NAME_MINVAL) {
  315. cch = strlen(lpName);
  316. string.Length = (USHORT)cch;
  317. // string.MaximumLength = (USHORT)cch + sizeof(CHAR); /* unnecessary */
  318. string.Buffer = (PCHAR)lpName;
  319. Status = RtlAnsiStringToUnicodeString(&UnicodeName, &string, TRUE);
  320. if (! NT_SUCCESS(Status)) {
  321. BaseSetLastNTError(Status);
  322. result = FALSE;
  323. __leave;
  324. }
  325. lpwName = (LPCWSTR)UnicodeName.Buffer;
  326. } else {
  327. lpwName = (LPCWSTR)lpName;
  328. }
  329. result = UpdateResourceW(hUpdate, lpwType, lpwName, language,
  330. lpData, cb);
  331. } __finally {
  332. RtlFreeUnicodeString(&UnicodeType);
  333. RtlFreeUnicodeString(&UnicodeName);
  334. }
  335. return result;
  336. }
  337. BOOL
  338. APIENTRY
  339. EndUpdateResourceW(
  340. HANDLE hUpdate,
  341. BOOL fDiscard
  342. )
  343. /*++
  344. Routine Description
  345. Finishes the UpdateResource action. Copies the
  346. input file to a temporary, adds the resources left
  347. in the list (hUpdate) to the exe.
  348. Parameters:
  349. hUpdateFile - The handle returned by the BeginUpdateResources
  350. function.
  351. fDiscard - If TRUE, discards all the updates, frees all memory.
  352. Return Value:
  353. FALSE - The file specified was not able to be written. More
  354. information may be available via GetLastError api.
  355. TRUE - The accumulated resources specified by UpdateResource calls
  356. were written to the executable file specified by the hUpdateFile
  357. handle.
  358. --*/
  359. {
  360. LPWSTR pFileName;
  361. PUPDATEDATA pUpdate;
  362. WCHAR pTempFileName[MAX_PATH];
  363. LPWSTR p;
  364. LONG rc;
  365. DWORD LastError = 0;
  366. HRESULT hr;
  367. SetLastError(0);
  368. pUpdate = (PUPDATEDATA)GlobalLock(hUpdate);
  369. if (fDiscard) {
  370. rc = NO_ERROR;
  371. } else {
  372. if (pUpdate == NULL) {
  373. return FALSE;
  374. }
  375. pFileName = (LPWSTR)GlobalLock(pUpdate->hFileName);
  376. if (pFileName != NULL) {
  377. hr = StringCchCopyExW(pTempFileName,
  378. RTL_NUMBER_OF(pTempFileName),
  379. pFileName,
  380. &p,
  381. NULL,
  382. 0);
  383. if (FAILED(hr)) {
  384. rc = LastError = HRESULT_CODE(hr);
  385. } else {
  386. do {
  387. p--;
  388. } while (*p != L'\\' && p >= pTempFileName);
  389. *(p+1) = 0;
  390. rc = GetTempFileNameW(pTempFileName, L"RCX", 0, pTempFileName);
  391. if (rc == 0) {
  392. rc = GetTempPathW(MAX_PATH, pTempFileName);
  393. if (rc == 0) {
  394. pTempFileName[0] = L'.';
  395. pTempFileName[1] = L'\\';
  396. pTempFileName[2] = 0;
  397. }
  398. rc = GetTempFileNameW(pTempFileName, L"RCX", 0, pTempFileName);
  399. if (rc == 0) {
  400. rc = GetLastError();
  401. } else {
  402. rc = WriteResFile(hUpdate, pTempFileName);
  403. if (rc == NO_ERROR) {
  404. DeleteFileW(pFileName);
  405. MoveFileW(pTempFileName, pFileName);
  406. } else {
  407. LastError = rc;
  408. DeleteFileW(pTempFileName);
  409. }
  410. }
  411. } else {
  412. rc = WriteResFile(hUpdate, pTempFileName);
  413. if (rc == NO_ERROR) {
  414. DeleteFileW(pFileName);
  415. MoveFileW(pTempFileName, pFileName);
  416. } else {
  417. LastError = rc;
  418. DeleteFileW(pTempFileName);
  419. }
  420. }
  421. }
  422. GlobalUnlock(pUpdate->hFileName);
  423. }
  424. GlobalFree(pUpdate->hFileName);
  425. }
  426. if (pUpdate != NULL) {
  427. FreeData(pUpdate);
  428. GlobalUnlock(hUpdate);
  429. }
  430. GlobalFree(hUpdate);
  431. SetLastError(LastError);
  432. return rc?FALSE:TRUE;
  433. }
  434. BOOL
  435. APIENTRY
  436. EndUpdateResourceA(
  437. HANDLE hUpdate,
  438. BOOL fDiscard)
  439. /*++
  440. Routine Description
  441. Ascii version - see above for description.
  442. --*/
  443. {
  444. return EndUpdateResourceW(hUpdate, fDiscard);
  445. }
  446. /**********************************************************************
  447. **
  448. ** End of API entry points.
  449. **
  450. ** Beginning of private entry points for worker routines to do the
  451. ** real work.
  452. **
  453. ***********************************************************************/
  454. BOOL
  455. EnumTypesFunc(
  456. HANDLE hModule,
  457. LPWSTR lpType,
  458. LPARAM lParam
  459. )
  460. {
  461. EnumResourceNamesW((HINSTANCE)hModule, lpType, (ENUMRESNAMEPROCW)EnumNamesFunc, lParam);
  462. return TRUE;
  463. }
  464. BOOL
  465. EnumNamesFunc(
  466. HANDLE hModule,
  467. LPWSTR lpType,
  468. LPWSTR lpName,
  469. LPARAM lParam
  470. )
  471. {
  472. EnumResourceLanguagesW((HINSTANCE)hModule, lpType, lpName, (ENUMRESLANGPROCW)EnumLangsFunc, lParam);
  473. return TRUE;
  474. }
  475. BOOL
  476. EnumLangsFunc(
  477. HANDLE hModule,
  478. LPWSTR lpType,
  479. LPWSTR lpName,
  480. WORD language,
  481. LPARAM lParam
  482. )
  483. {
  484. HANDLE hResInfo;
  485. LONG fError;
  486. PSDATA Type;
  487. PSDATA Name;
  488. ULONG cb;
  489. PVOID lpData;
  490. HANDLE hResource;
  491. PVOID lpResource;
  492. hResInfo = FindResourceExW((HINSTANCE)hModule, lpType, lpName, language);
  493. if (hResInfo == NULL) {
  494. return FALSE;
  495. } else {
  496. Type = AddStringOrID(lpType, (PUPDATEDATA)lParam);
  497. if (Type == NULL) {
  498. ((PUPDATEDATA)lParam)->Status = ERROR_NOT_ENOUGH_MEMORY;
  499. return FALSE;
  500. }
  501. Name = AddStringOrID(lpName, (PUPDATEDATA)lParam);
  502. if (Name == NULL) {
  503. ((PUPDATEDATA)lParam)->Status = ERROR_NOT_ENOUGH_MEMORY;
  504. FREE_RES_ID(Type);
  505. return FALSE;
  506. }
  507. cb = SizeofResource((HINSTANCE)hModule, (HRSRC)hResInfo);
  508. if (cb == 0) {
  509. FREE_RES_ID(Type);
  510. FREE_RES_ID(Name);
  511. return FALSE;
  512. }
  513. lpData = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), cb);
  514. if (lpData == NULL) {
  515. FREE_RES_ID(Type);
  516. FREE_RES_ID(Name);
  517. return FALSE;
  518. }
  519. RtlZeroMemory(lpData, cb);
  520. hResource = LoadResource((HINSTANCE)hModule, (HRSRC)hResInfo);
  521. if (hResource == NULL) {
  522. RtlFreeHeap(RtlProcessHeap(), 0, lpData);
  523. FREE_RES_ID(Type);
  524. FREE_RES_ID(Name);
  525. return FALSE;
  526. }
  527. lpResource = (PVOID)LockResource(hResource);
  528. if (lpResource == NULL) {
  529. RtlFreeHeap(RtlProcessHeap(), 0, lpData);
  530. FREE_RES_ID(Type);
  531. FREE_RES_ID(Name);
  532. return FALSE;
  533. }
  534. RtlCopyMemory(lpData, lpResource, cb);
  535. (VOID)UnlockResource(hResource);
  536. (VOID)FreeResource(hResource);
  537. fError = AddResource(Type, Name, language, (PUPDATEDATA)lParam, lpData, cb);
  538. if (fError != NO_ERROR) {
  539. ((PUPDATEDATA)lParam)->Status = ERROR_NOT_ENOUGH_MEMORY;
  540. return FALSE;
  541. }
  542. }
  543. return TRUE;
  544. }
  545. VOID
  546. FreeOne(
  547. PRESNAME pRes
  548. )
  549. {
  550. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pRes->OffsetToDataEntry);
  551. FREE_RES_ID(pRes->Name);
  552. FREE_RES_ID(pRes->Type);
  553. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pRes);
  554. }
  555. VOID
  556. FreeStrings(
  557. PUPDATEDATA pUpd
  558. )
  559. {
  560. PSDATA pstring, pStringTmp;
  561. pstring = pUpd->StringHead;
  562. while (pstring != NULL) {
  563. pStringTmp = pstring->uu.ss.pnext;
  564. if (pstring->discriminant == IS_STRING)
  565. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pstring->szStr);
  566. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pstring);
  567. pstring = pStringTmp;
  568. }
  569. return;
  570. }
  571. VOID
  572. FreeData(
  573. PUPDATEDATA pUpd
  574. )
  575. {
  576. PRESTYPE pType;
  577. PRESNAME pRes;
  578. for (pType=pUpd->ResTypeHeadID ; pUpd->ResTypeHeadID ; pType=pUpd->ResTypeHeadID) {
  579. pUpd->ResTypeHeadID = pUpd->ResTypeHeadID->pnext;
  580. for (pRes=pType->NameHeadID ; pType->NameHeadID ; pRes=pType->NameHeadID ) {
  581. pType->NameHeadID = pType->NameHeadID->pnext;
  582. FreeOne(pRes);
  583. }
  584. for (pRes=pType->NameHeadName ; pType->NameHeadName ; pRes=pType->NameHeadName ) {
  585. pType->NameHeadName = pType->NameHeadName->pnext;
  586. FreeOne(pRes);
  587. }
  588. FREE_RES_ID(pType->Type);
  589. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pType);
  590. }
  591. for (pType=pUpd->ResTypeHeadName ; pUpd->ResTypeHeadName ; pType=pUpd->ResTypeHeadName) {
  592. pUpd->ResTypeHeadName = pUpd->ResTypeHeadName->pnext;
  593. for (pRes=pType->NameHeadID ; pType->NameHeadID ; pRes=pType->NameHeadID ) {
  594. pType->NameHeadID = pType->NameHeadID->pnext;
  595. FreeOne(pRes);
  596. }
  597. for (pRes=pType->NameHeadName ; pType->NameHeadName ; pRes=pType->NameHeadName ) {
  598. pType->NameHeadName = pType->NameHeadName->pnext;
  599. FreeOne(pRes);
  600. }
  601. // no FREE_RES_ID needed here.
  602. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pType);
  603. }
  604. FreeStrings(pUpd);
  605. return;
  606. }
  607. /*+++
  608. Routines to register strings
  609. ---*/
  610. //
  611. // Resources are DWORD aligned and may be in any order.
  612. //
  613. #define TABLE_ALIGN 4
  614. #define DATA_ALIGN 4L
  615. PSDATA
  616. AddStringOrID(
  617. LPCWSTR lp,
  618. PUPDATEDATA pupd
  619. )
  620. {
  621. USHORT cb;
  622. PSDATA pstring;
  623. PPSDATA ppstring;
  624. if ((ULONG_PTR)lp < LDR_RESOURCE_ID_NAME_MINVAL) {
  625. //
  626. // an ID
  627. //
  628. pstring = (PSDATA)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), sizeof(SDATA));
  629. if (pstring == NULL)
  630. return NULL;
  631. RtlZeroMemory((PVOID)pstring, sizeof(SDATA));
  632. pstring->discriminant = IS_ID;
  633. pstring->uu.Ordinal = (WORD)((ULONG_PTR)lp & 0x0000ffff);
  634. } else {
  635. //
  636. // a string
  637. //
  638. cb = wcslen(lp) + 1;
  639. ppstring = &pupd->StringHead;
  640. while ((pstring = *ppstring) != NULL) {
  641. if (!wcsncmp(pstring->szStr, lp, cb))
  642. break;
  643. ppstring = &(pstring->uu.ss.pnext);
  644. }
  645. if (!pstring) {
  646. //
  647. // allocate a new one
  648. //
  649. pstring = (PSDATA)RtlAllocateHeap(RtlProcessHeap(),
  650. MAKE_TAG( RES_TAG ) | HEAP_ZERO_MEMORY,
  651. sizeof(SDATA)
  652. );
  653. if (pstring == NULL)
  654. return NULL;
  655. RtlZeroMemory((PVOID)pstring, sizeof(SDATA));
  656. pstring->szStr = (WCHAR*)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ),
  657. cb*sizeof(WCHAR));
  658. if (pstring->szStr == NULL) {
  659. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pstring);
  660. return NULL;
  661. }
  662. pstring->discriminant = IS_STRING;
  663. pstring->OffsetToString = pupd->cbStringTable;
  664. pstring->cbData = sizeof(pstring->cbsz) + cb * sizeof(WCHAR);
  665. pstring->cbsz = cb - 1; /* don't include zero terminator */
  666. RtlCopyMemory(pstring->szStr, lp, cb*sizeof(WCHAR));
  667. pupd->cbStringTable += pstring->cbData;
  668. pstring->uu.ss.pnext=NULL;
  669. *ppstring=pstring;
  670. }
  671. }
  672. return(pstring);
  673. }
  674. //
  675. // add a resource into the resource directory hiearchy
  676. //
  677. LONG
  678. AddResource(
  679. IN PSDATA Type,
  680. IN PSDATA Name,
  681. IN WORD Language,
  682. IN PUPDATEDATA pupd,
  683. IN PVOID lpData,
  684. IN ULONG cb
  685. )
  686. {
  687. PRESTYPE pType;
  688. PPRESTYPE ppType;
  689. PRESNAME pName;
  690. PRESNAME pNameM;
  691. PPRESNAME ppName = NULL;
  692. BOOL fTypeID=(Type->discriminant == IS_ID);
  693. BOOL fNameID=(Name->discriminant == IS_ID);
  694. BOOL fSame=FALSE;
  695. int iCompare;
  696. //
  697. // figure out which list to store it in
  698. //
  699. ppType = fTypeID ? &pupd->ResTypeHeadID : &pupd->ResTypeHeadName;
  700. //
  701. // Try to find the Type in the list
  702. //
  703. while ((pType=*ppType) != NULL) {
  704. if (pType->Type->uu.Ordinal == Type->uu.Ordinal) {
  705. ppName = fNameID ? &pType->NameHeadID : &pType->NameHeadName;
  706. break;
  707. }
  708. if (fTypeID) {
  709. if (Type->uu.Ordinal < pType->Type->uu.Ordinal)
  710. break;
  711. } else {
  712. if (wcscmp(Type->szStr, pType->Type->szStr) < 0)
  713. break;
  714. }
  715. ppType = &(pType->pnext);
  716. }
  717. //
  718. // Create a new type if needed
  719. //
  720. if (ppName == NULL) {
  721. pType = (PRESTYPE)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), sizeof(RESTYPE));
  722. if (pType == NULL) {
  723. FREE_RES_ID(Type);
  724. FREE_RES_ID(Name);
  725. return ERROR_NOT_ENOUGH_MEMORY;
  726. }
  727. RtlZeroMemory((PVOID)pType, sizeof(RESTYPE));
  728. if (fTypeID) {
  729. /* fix for bug 698940. Duplicate the ID node since the rest of this function's
  730. * logic either attaches the passed node to pName->Type or frees it. */
  731. pType->Type = (PSDATA)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ),
  732. sizeof(SDATA));
  733. if (pType->Type == NULL) {
  734. FREE_RES_ID(Type);
  735. FREE_RES_ID(Name);
  736. return ERROR_NOT_ENOUGH_MEMORY;
  737. }
  738. RtlZeroMemory((PVOID)pType->Type, sizeof(SDATA));
  739. pType->Type->discriminant = IS_ID;
  740. pType->Type->uu.Ordinal = Type->uu.Ordinal;
  741. } else {
  742. pType->Type = Type;
  743. }
  744. pType->pnext = *ppType;
  745. *ppType = pType;
  746. ppName = fNameID ? &pType->NameHeadID : &pType->NameHeadName;
  747. }
  748. //
  749. // Find proper place for name
  750. //
  751. while ( (pName = *ppName) != NULL) {
  752. if (fNameID) {
  753. if (Name->uu.Ordinal == pName->Name->uu.Ordinal) {
  754. fSame = TRUE;
  755. break;
  756. }
  757. if (Name->uu.Ordinal < pName->Name->uu.Ordinal)
  758. break;
  759. } else {
  760. iCompare = wcscmp(Name->szStr, pName->Name->szStr );
  761. if (iCompare == 0) {
  762. fSame = TRUE;
  763. break;
  764. } else if (iCompare < 0) {
  765. break;
  766. }
  767. }
  768. ppName = &(pName->pnext);
  769. }
  770. //
  771. // check for delete/modify
  772. //
  773. if (fSame) { /* same name, new language */
  774. if (pName->NumberOfLanguages == 1) { /* one language currently ? */
  775. if (Language == pName->LanguageId) { /* REPLACE || DELETE */
  776. pName->DataSize = cb;
  777. FREE_RES_ID(Type);
  778. FREE_RES_ID(Name);
  779. if (lpData == NULL) { /* DELETE */
  780. return DeleteResourceFromList(pupd, pType, pName, Language, fTypeID, fNameID);
  781. }
  782. RtlFreeHeap(RtlProcessHeap(),0,(PVOID)pName->OffsetToDataEntry);
  783. pName->OffsetToDataEntry = (ULONG_PTR)lpData;
  784. return NO_ERROR;
  785. } else {
  786. if (lpData == NULL) { /* no data but new? */
  787. FREE_RES_ID(Type);
  788. FREE_RES_ID(Name);
  789. return ERROR_INVALID_PARAMETER; /* badness */
  790. }
  791. return InsertResourceIntoLangList(pupd, Type, Name, pType, pName, Language, fNameID, cb, lpData);
  792. }
  793. } else { /* many languages currently */
  794. pNameM = pName; /* save head of lang list */
  795. while ( (pName = *ppName) != NULL) {/* find insertion point */
  796. if (!(fNameID ? pName->Name->uu.Ordinal == (*ppName)->Name->uu.Ordinal :
  797. !wcscmp(pName->Name->uu.ss.sz, (*ppName)->Name->uu.ss.sz)) ||
  798. Language <= pName->LanguageId) /* here? */
  799. break; /* yes */
  800. ppName = &(pName->pnext); /* traverse language list */
  801. }
  802. if (pName && Language == pName->LanguageId) { /* language found? */
  803. FREE_RES_ID(Type);
  804. FREE_RES_ID(Name);
  805. if (lpData == NULL) { /* DELETE */
  806. return DeleteResourceFromList(pupd, pType, pName, Language, fTypeID, fNameID);
  807. }
  808. pName->DataSize = cb; /* REPLACE */
  809. RtlFreeHeap(RtlProcessHeap(),0,(PVOID)pName->OffsetToDataEntry);
  810. pName->OffsetToDataEntry = (ULONG_PTR)lpData;
  811. return NO_ERROR;
  812. } else { /* add new language */
  813. return InsertResourceIntoLangList(pupd, Type, Name, pType, pNameM, Language, fNameID, cb, lpData);
  814. }
  815. }
  816. } else { /* unique name */
  817. if (lpData == NULL) { /* can't delete new name */
  818. FREE_RES_ID(Type);
  819. FREE_RES_ID(Name);
  820. return ERROR_INVALID_PARAMETER;
  821. }
  822. }
  823. //
  824. // add new name/language
  825. //
  826. if (!fSame) {
  827. if (fNameID)
  828. pType->NumberOfNamesID++;
  829. else
  830. pType->NumberOfNamesName++;
  831. }
  832. pName = (PRESNAME)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), sizeof(RESNAME));
  833. if (pName == NULL) {
  834. FREE_RES_ID(Type);
  835. FREE_RES_ID(Name);
  836. return ERROR_NOT_ENOUGH_MEMORY;
  837. }
  838. RtlZeroMemory((PVOID)pName, sizeof(RESNAME));
  839. pName->pnext = *ppName;
  840. *ppName = pName;
  841. pName->Name = Name;
  842. pName->Type = Type;
  843. pName->NumberOfLanguages = 1;
  844. pName->LanguageId = Language;
  845. pName->DataSize = cb;
  846. pName->OffsetToDataEntry = (ULONG_PTR)lpData;
  847. return NO_ERROR;
  848. }
  849. BOOL
  850. DeleteResourceFromList(
  851. PUPDATEDATA pUpd,
  852. PRESTYPE pType,
  853. PRESNAME pName,
  854. INT Language,
  855. INT fType,
  856. INT fName
  857. )
  858. {
  859. PPRESTYPE ppType;
  860. PPRESNAME ppName;
  861. PRESNAME pNameT;
  862. /* find previous type node */
  863. ppType = fType ? &pUpd->ResTypeHeadID : &pUpd->ResTypeHeadName;
  864. while (*ppType != pType) {
  865. ppType = &((*ppType)->pnext);
  866. }
  867. /* find previous name node */
  868. ppName = fName ? &pType->NameHeadID : &pType->NameHeadName;
  869. pNameT = NULL;
  870. while (*ppName != pName) {
  871. if (pNameT == NULL) { /* find first Name in lang list */
  872. if (fName) {
  873. if ((*ppName)->Name->uu.Ordinal == pName->Name->uu.Ordinal) {
  874. pNameT = *ppName;
  875. }
  876. } else {
  877. if (wcscmp((*ppName)->Name->szStr, pName->Name->szStr) == 0) {
  878. pNameT = *ppName;
  879. }
  880. }
  881. }
  882. ppName = &((*ppName)->pnext);
  883. }
  884. if (pNameT) {
  885. pNameT->NumberOfLanguages--;
  886. if (pNameT->NumberOfLanguages == 0) {
  887. if (fName)
  888. pType->NumberOfNamesID -= 1;
  889. else
  890. pType->NumberOfNamesName -= 1;
  891. }
  892. }
  893. else
  894. {
  895. if (fName)
  896. pType->NumberOfNamesID -= 1;
  897. else
  898. pType->NumberOfNamesName -= 1;
  899. }
  900. *ppName = pName->pnext; /* link to next */
  901. FreeOne(pName);
  902. if (!pType->NameHeadID && !pType->NameHeadName)
  903. { /* type list completely empty? */
  904. *ppType = pType->pnext; /* link to next */
  905. FREE_RES_ID(pType->Type);
  906. RtlFreeHeap(RtlProcessHeap(), 0, pType); /* and free */
  907. }
  908. return NO_ERROR;
  909. }
  910. BOOL
  911. InsertResourceIntoLangList(
  912. PUPDATEDATA pUpd,
  913. PSDATA Type,
  914. PSDATA Name,
  915. PRESTYPE pType,
  916. PRESNAME pName,
  917. INT Language,
  918. INT fName,
  919. INT cb,
  920. PVOID lpData
  921. )
  922. {
  923. PRESNAME pNameM;
  924. PRESNAME pNameNew;
  925. PPRESNAME ppName;
  926. pNameNew = (PRESNAME)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), sizeof(RESNAME));
  927. if (pNameNew == NULL) {
  928. FREE_RES_ID(Type);
  929. FREE_RES_ID(Name);
  930. return ERROR_NOT_ENOUGH_MEMORY;
  931. }
  932. RtlZeroMemory((PVOID)pNameNew, sizeof(RESNAME));
  933. pNameNew->Name = Name;
  934. pNameNew->Type = Type;
  935. pNameNew->LanguageId = (WORD)Language;
  936. pNameNew->DataSize = cb;
  937. pNameNew->OffsetToDataEntry = (ULONG_PTR)lpData;
  938. if (Language < pName->LanguageId) { /* have to add to the front */
  939. pNameNew->NumberOfLanguages = pName->NumberOfLanguages + 1;
  940. pName->NumberOfLanguages = 1;
  941. ppName = fName ? &pType->NameHeadID : &pType->NameHeadName;
  942. /* don't have to look for NULL at end of list !!! */
  943. while (pName != *ppName) { /* find insertion point */
  944. ppName = &((*ppName)->pnext); /* traverse language list */
  945. }
  946. pNameNew->pnext = *ppName; /* insert */
  947. *ppName = pNameNew;
  948. } else {
  949. pNameM = pName;
  950. pName->NumberOfLanguages += 1;
  951. while ( (pName != NULL) &&
  952. (fName ? Name->uu.Ordinal == pName->Name->uu.Ordinal :
  953. !wcscmp(Name->uu.ss.sz, pName->Name->uu.ss.sz))) { /* find insertion point */
  954. if (Language <= pName->LanguageId) /* here? */
  955. break; /* yes */
  956. pNameM = pName;
  957. pName = pName->pnext; /* traverse language list */
  958. }
  959. pName = pNameM->pnext;
  960. pNameM->pnext = pNameNew;
  961. pNameNew->pnext = pName;
  962. }
  963. return NO_ERROR;
  964. }
  965. /*
  966. * Utility routines
  967. */
  968. ULONG
  969. FilePos(int fh)
  970. {
  971. return _llseek(fh, 0L, SEEK_CUR);
  972. }
  973. ULONG
  974. MuMoveFilePos( INT fh, ULONG pos )
  975. {
  976. return _llseek( fh, pos, SEEK_SET );
  977. }
  978. ULONG
  979. MuWrite( INT fh, PVOID p, ULONG n )
  980. {
  981. ULONG n1;
  982. if ((n1 = _lwrite(fh, (const char *)p, n)) != n) {
  983. return n1;
  984. } else
  985. return 0;
  986. }
  987. ULONG
  988. MuRead(INT fh, UCHAR*p, ULONG n )
  989. {
  990. ULONG n1;
  991. if ((n1 = _lread( fh, p, n )) != n) {
  992. return n1;
  993. } else
  994. return 0;
  995. }
  996. BOOL
  997. MuCopy( INT srcfh, INT dstfh, ULONG nbytes )
  998. {
  999. ULONG n;
  1000. ULONG cb=0L;
  1001. PUCHAR pb;
  1002. pb = (PUCHAR)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( RES_TAG ), BUFSIZE);
  1003. if (pb == NULL)
  1004. return 0;
  1005. RtlZeroMemory((PVOID)pb, BUFSIZE);
  1006. while (nbytes) {
  1007. if (nbytes <= BUFSIZE)
  1008. n = nbytes;
  1009. else
  1010. n = BUFSIZE;
  1011. nbytes -= n;
  1012. if (!MuRead( srcfh, pb, n )) {
  1013. cb += n;
  1014. MuWrite( dstfh, pb, n );
  1015. } else {
  1016. RtlFreeHeap(RtlProcessHeap(), 0, pb);
  1017. return cb;
  1018. }
  1019. }
  1020. RtlFreeHeap(RtlProcessHeap(), 0, pb);
  1021. return cb;
  1022. }
  1023. VOID
  1024. SetResdata(
  1025. PIMAGE_RESOURCE_DATA_ENTRY pResData,
  1026. ULONG offset,
  1027. ULONG size)
  1028. {
  1029. pResData->OffsetToData = offset;
  1030. pResData->Size = size;
  1031. pResData->CodePage = DEFAULT_CODEPAGE;
  1032. pResData->Reserved = 0L;
  1033. }
  1034. __inline VOID
  1035. SetRestab(
  1036. PIMAGE_RESOURCE_DIRECTORY pRestab,
  1037. LONG time,
  1038. WORD cNamed,
  1039. WORD cId)
  1040. {
  1041. pRestab->Characteristics = 0L;
  1042. pRestab->TimeDateStamp = time;
  1043. pRestab->MajorVersion = MAJOR_RESOURCE_VERSION;
  1044. pRestab->MinorVersion = MINOR_RESOURCE_VERSION;
  1045. pRestab->NumberOfNamedEntries = cNamed;
  1046. pRestab->NumberOfIdEntries = cId;
  1047. }
  1048. PIMAGE_SECTION_HEADER
  1049. FindSection(
  1050. PIMAGE_SECTION_HEADER pObjBottom,
  1051. PIMAGE_SECTION_HEADER pObjTop,
  1052. LPSTR pName
  1053. )
  1054. {
  1055. while (pObjBottom < pObjTop) {
  1056. if (strcmp((const char *)&pObjBottom->Name[0], pName) == 0)
  1057. return pObjBottom;
  1058. pObjBottom++;
  1059. }
  1060. return NULL;
  1061. }
  1062. ULONG
  1063. AssignResourceToSection(
  1064. PRESNAME *ppRes, /* resource to assign */
  1065. ULONG ExtraSectionOffset, /* offset between .rsrc and .rsrc1 */
  1066. ULONG Offset, /* next available offset in section */
  1067. LONG Size, /* Maximum size of .rsrc */
  1068. PLONG pSizeRsrc1
  1069. )
  1070. {
  1071. ULONG cb;
  1072. /* Assign this res to this section */
  1073. cb = ROUNDUP((*ppRes)->DataSize, CBLONG);
  1074. if (Offset < ExtraSectionOffset && Offset + cb > (ULONG)Size) {
  1075. *pSizeRsrc1 = Offset;
  1076. Offset = ExtraSectionOffset;
  1077. DPrintf((DebugBuf, "<<< Secondary resource section @%#08lx >>>\n", Offset));
  1078. }
  1079. (*ppRes)->OffsetToData = Offset;
  1080. *ppRes = (*ppRes)->pnext;
  1081. DPrintf((DebugBuf, " --> %#08lx bytes at %#08lx\n", cb, Offset));
  1082. return Offset + cb;
  1083. }
  1084. //
  1085. // Adjust debug directory table.
  1086. //
  1087. // The following code instantiates the PatchDebug function template twice.
  1088. // Once to generate code for 32-bit image headers and once to generate
  1089. // code for 64-bit image headers.
  1090. //
  1091. template
  1092. LONG
  1093. PatchDebug<IMAGE_NT_HEADERS32>(
  1094. int inpfh,
  1095. int outfh,
  1096. PIMAGE_SECTION_HEADER pDebugOld,
  1097. PIMAGE_SECTION_HEADER pDebugNew,
  1098. PIMAGE_SECTION_HEADER pDebugDirOld,
  1099. PIMAGE_SECTION_HEADER pDebugDirNew,
  1100. IMAGE_NT_HEADERS32 *pOld,
  1101. IMAGE_NT_HEADERS32 *pNew,
  1102. ULONG ibMaxDbgOffsetOld,
  1103. PULONG pPointerToRawData
  1104. );
  1105. template
  1106. LONG
  1107. PatchDebug<IMAGE_NT_HEADERS64>(
  1108. int inpfh,
  1109. int outfh,
  1110. PIMAGE_SECTION_HEADER pDebugOld,
  1111. PIMAGE_SECTION_HEADER pDebugNew,
  1112. PIMAGE_SECTION_HEADER pDebugDirOld,
  1113. PIMAGE_SECTION_HEADER pDebugDirNew,
  1114. IMAGE_NT_HEADERS64 *pOld,
  1115. IMAGE_NT_HEADERS64 *pNew,
  1116. ULONG ibMaxDbgOffsetOld,
  1117. PULONG pPointerToRawData
  1118. );
  1119. //
  1120. // Patch various RVAs in the specified file to compensate for extra
  1121. // section table entries.
  1122. //
  1123. // The following code instantiates the PatchRVAs function template twice.
  1124. // Once to generate code for 32-bit image headers and once to generate
  1125. // code for 64-bit image headers.
  1126. //
  1127. template
  1128. LONG
  1129. PatchRVAs<IMAGE_NT_HEADERS32>(
  1130. int inpfh,
  1131. int outfh,
  1132. PIMAGE_SECTION_HEADER po32,
  1133. ULONG pagedelta,
  1134. IMAGE_NT_HEADERS32 *pNew,
  1135. ULONG OldSize
  1136. );
  1137. template
  1138. LONG
  1139. PatchRVAs<IMAGE_NT_HEADERS64>(
  1140. int inpfh,
  1141. int outfh,
  1142. PIMAGE_SECTION_HEADER po32,
  1143. ULONG pagedelta,
  1144. IMAGE_NT_HEADERS64 *pNew,
  1145. ULONG OldSize
  1146. );
  1147. /***************************** Main Worker Function ***************************
  1148. * LONG PEWriteResFile
  1149. *
  1150. * This function writes the resources to the named executable file.
  1151. * It assumes that resources have no fixups (even any existing resources
  1152. * that it removes from the executable.) It places all the resources into
  1153. * one or two sections. The resources are packed tightly into the section,
  1154. * being aligned on dword boundaries. Each section is padded to a file
  1155. * sector size (no invalid or zero-filled pages), and each
  1156. * resource is padded to the afore-mentioned dword boundary. This
  1157. * function uses the capabilities of the NT system to enable it to easily
  1158. * manipulate the data: to wit, it assumes that the system can allocate
  1159. * any sized piece of data, in particular the section and resource tables.
  1160. * If it did not, it might have to deal with temporary files (the system
  1161. * may have to grow the swap file, but that's what the system is for.)
  1162. *
  1163. * Return values are:
  1164. * TRUE - file was written succesfully.
  1165. * FALSE - file was not written succesfully.
  1166. *
  1167. * Effects:
  1168. *
  1169. * History:
  1170. * Thur Apr 27, 1989 by Floyd Rogers [floydr]
  1171. * Created.
  1172. * 12/8/89 sanfords Added multiple section support.
  1173. * 12/11/90 floydr Modified for new (NT) Linear Exe format
  1174. * 1/18/92 vich Modified for new (NT) Portable Exe format
  1175. * 5/8/92 bryant General cleanup so resonexe can work with unicode
  1176. * 6/9/92 floydr incorporate bryan's changes
  1177. * 6/15/92 floydr debug section separate from debug table
  1178. * 9/25/92 floydr account for .rsrc not being last-1
  1179. * 9/28/92 floydr account for adding lots of resources by adding
  1180. * a second .rsrc section.
  1181. \****************************************************************************/
  1182. //
  1183. // The following code instantiates the PEWriteResource function template
  1184. // twice. Once to generate code for 32-bit image headers and once to
  1185. // generate code for 64-bit image headers.
  1186. //
  1187. template
  1188. LONG
  1189. PEWriteResource<IMAGE_NT_HEADERS32> (
  1190. INT inpfh,
  1191. INT outfh,
  1192. ULONG cbOldexe,
  1193. PUPDATEDATA pUpdate,
  1194. IMAGE_NT_HEADERS32 *NtHeader
  1195. );
  1196. template
  1197. LONG
  1198. PEWriteResource<IMAGE_NT_HEADERS64> (
  1199. INT inpfh,
  1200. INT outfh,
  1201. ULONG cbOldexe,
  1202. PUPDATEDATA pUpdate,
  1203. IMAGE_NT_HEADERS64 *NtHeader
  1204. );
  1205. LONG
  1206. PEWriteResFile(
  1207. INT inpfh,
  1208. INT outfh,
  1209. ULONG cbOldexe,
  1210. PUPDATEDATA pUpdate
  1211. )
  1212. {
  1213. IMAGE_NT_HEADERS32 Old;
  1214. //
  1215. // Position file to start of NT header and read the image header.
  1216. //
  1217. MuMoveFilePos(inpfh, cbOldexe);
  1218. MuRead(inpfh, (PUCHAR)&Old, sizeof(IMAGE_NT_HEADERS32));
  1219. //
  1220. // If the file is not an NT image, then return an error.
  1221. //
  1222. if (Old.Signature != IMAGE_NT_SIGNATURE) {
  1223. return ERROR_INVALID_EXE_SIGNATURE;
  1224. }
  1225. //
  1226. // If the file is not an executable or a dll, then return an error.
  1227. //
  1228. if ((Old.FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0 &&
  1229. (Old.FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) {
  1230. return ERROR_EXE_MARKED_INVALID;
  1231. }
  1232. //
  1233. // Call the proper function dependent on the machine type.
  1234. //
  1235. if (Old.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  1236. return PEWriteResource(inpfh, outfh, cbOldexe, pUpdate, (IMAGE_NT_HEADERS64 *)&Old);
  1237. } else if (Old.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  1238. return PEWriteResource(inpfh, outfh, cbOldexe, pUpdate, (IMAGE_NT_HEADERS32 *)&Old);
  1239. } else {
  1240. return ERROR_BAD_EXE_FORMAT;
  1241. }
  1242. }
  1243. /***************************************************************************
  1244. * WriteResSection
  1245. *
  1246. * This routine writes out the resources asked for into the current section.
  1247. * It pads resources to dword (4-byte) boundaries.
  1248. **************************************************************************/
  1249. PRESNAME
  1250. WriteResSection(
  1251. PUPDATEDATA pUpdate,
  1252. INT outfh,
  1253. ULONG align,
  1254. ULONG cbLeft,
  1255. PRESNAME pResSave
  1256. )
  1257. {
  1258. ULONG cbB=0; /* bytes in current section */
  1259. ULONG cbT; /* bytes in current section */
  1260. ULONG size;
  1261. PRESNAME pRes;
  1262. PRESTYPE pType;
  1263. BOOL fName;
  1264. PVOID lpData;
  1265. /* Output contents associated with each resource */
  1266. pType = pUpdate->ResTypeHeadName;
  1267. while (pType) {
  1268. pRes = pType->NameHeadName;
  1269. fName = TRUE;
  1270. loop1:
  1271. for ( ; pRes ; pRes = pRes->pnext) {
  1272. if (pResSave != NULL && pRes != pResSave)
  1273. continue;
  1274. pResSave = NULL;
  1275. #if DBG
  1276. if (pType->Type->discriminant == IS_STRING) {
  1277. DPrintf((DebugBuf, " "));
  1278. DPrintfu((pType->Type->szStr));
  1279. DPrintfn((DebugBuf, "."));
  1280. } else {
  1281. DPrintf(( DebugBuf, " %d.", pType->Type->uu.Ordinal ));
  1282. }
  1283. if (pRes->Name->discriminant == IS_STRING) {
  1284. DPrintfu((pRes->Name->szStr));
  1285. } else {
  1286. DPrintfn(( DebugBuf, "%d", pRes->Name->uu.Ordinal ));
  1287. }
  1288. #endif
  1289. lpData = (PVOID)pRes->OffsetToDataEntry;
  1290. DPrintfn((DebugBuf, "\n"));
  1291. /* if there is room in the current section, write it there */
  1292. size = pRes->DataSize;
  1293. if (cbLeft != 0 && cbLeft >= size) { /* resource fits? */
  1294. DPrintf((DebugBuf, "Writing resource: %#04lx bytes @%#08lx\n", size, FilePos(outfh)));
  1295. MuWrite(outfh, lpData, size);
  1296. /* pad resource */
  1297. cbT = REMAINDER(size, CBLONG);
  1298. #if DBG
  1299. if (cbT != 0) {
  1300. DPrintf((DebugBuf, "Writing small pad: %#04lx bytes @%#08lx\n", cbT, FilePos(outfh)));
  1301. }
  1302. #endif
  1303. MuWrite(outfh, pchPad, cbT); /* dword */
  1304. cbB += size + cbT;
  1305. cbLeft -= size + cbT; /* less left */
  1306. continue; /* next resource */
  1307. } else { /* will fill up section */
  1308. DPrintf((DebugBuf, "Done with .rsrc section\n"));
  1309. goto write_pad;
  1310. }
  1311. }
  1312. if (fName) {
  1313. fName = FALSE;
  1314. pRes = pType->NameHeadID;
  1315. goto loop1;
  1316. }
  1317. pType = pType->pnext;
  1318. }
  1319. pType = pUpdate->ResTypeHeadID;
  1320. while (pType) {
  1321. pRes = pType->NameHeadName;
  1322. fName = TRUE;
  1323. loop2:
  1324. for ( ; pRes ; pRes = pRes->pnext) {
  1325. if (pResSave != NULL && pRes != pResSave)
  1326. continue;
  1327. pResSave = NULL;
  1328. #if DBG
  1329. if (pType->Type->discriminant == IS_STRING) {
  1330. DPrintf((DebugBuf, " "));
  1331. DPrintfu((pType->Type->szStr));
  1332. DPrintfn((DebugBuf, "."));
  1333. } else {
  1334. DPrintf(( DebugBuf, " %d.", pType->Type->uu.Ordinal ));
  1335. }
  1336. if (pRes->Name->discriminant == IS_STRING) {
  1337. DPrintfu((pRes->Name->szStr));
  1338. } else {
  1339. DPrintfn(( DebugBuf, "%d", pRes->Name->uu.Ordinal ));
  1340. }
  1341. #endif
  1342. lpData = (PVOID)pRes->OffsetToDataEntry;
  1343. DPrintfn((DebugBuf, "\n"));
  1344. /* if there is room in the current section, write it there */
  1345. size = pRes->DataSize;
  1346. if (cbLeft != 0 && cbLeft >= size) { /* resource fits? */
  1347. DPrintf((DebugBuf, "Writing resource: %#04lx bytes @%#08lx\n", size, FilePos(outfh)));
  1348. MuWrite(outfh, lpData, size);
  1349. /* pad resource */
  1350. cbT = REMAINDER(size, CBLONG);
  1351. #if DBG
  1352. if (cbT != 0) {
  1353. DPrintf((DebugBuf, "Writing small pad: %#04lx bytes @%#08lx\n", cbT, FilePos(outfh)));
  1354. }
  1355. #endif
  1356. MuWrite(outfh, pchPad, cbT); /* dword */
  1357. cbB += size + cbT;
  1358. cbLeft -= size + cbT; /* less left */
  1359. continue; /* next resource */
  1360. } else { /* will fill up section */
  1361. DPrintf((DebugBuf, "Done with .rsrc section\n"));
  1362. goto write_pad;
  1363. }
  1364. }
  1365. if (fName) {
  1366. fName = FALSE;
  1367. pRes = pType->NameHeadID;
  1368. goto loop2;
  1369. }
  1370. pType = pType->pnext;
  1371. }
  1372. pRes = NULL;
  1373. write_pad:
  1374. /* pad to alignment boundary */
  1375. cbB = FilePos(outfh);
  1376. cbT = ROUNDUP(cbB, align);
  1377. cbLeft = cbT - cbB;
  1378. DPrintf((DebugBuf, "Writing file sector pad: %#04lx bytes @%#08lx\n", cbLeft, FilePos(outfh)));
  1379. if (cbLeft != 0) {
  1380. while (cbLeft >= cbPadMax) {
  1381. MuWrite(outfh, pchPad, cbPadMax);
  1382. cbLeft -= cbPadMax;
  1383. }
  1384. MuWrite(outfh, pchPad, cbLeft);
  1385. }
  1386. return pRes;
  1387. }
  1388. #if DBG
  1389. void
  1390. wchprintf(WCHAR*wch)
  1391. {
  1392. UNICODE_STRING ustring;
  1393. STRING string;
  1394. char buf[257];
  1395. ustring.MaximumLength = ustring.Length = wcslen(wch) * sizeof(WCHAR);
  1396. ustring.Buffer = wch;
  1397. string.Length = 0;
  1398. string.MaximumLength = 256;
  1399. string.Buffer = buf;
  1400. RtlUnicodeStringToAnsiString(&string, &ustring, FALSE);
  1401. buf[string.Length] = '\000';
  1402. DPrintfn((DebugBuf, "%s", buf));
  1403. }
  1404. #endif
  1405. /*---------------------------------------------------------------------------*/
  1406. /* */
  1407. /* WriteResFile() - */
  1408. /* */
  1409. /*---------------------------------------------------------------------------*/
  1410. LONG
  1411. WriteResFile(
  1412. HANDLE hUpdate,
  1413. WCHAR *pDstname)
  1414. {
  1415. INT inpfh;
  1416. INT outfh;
  1417. ULONG onewexe;
  1418. IMAGE_DOS_HEADER oldexe;
  1419. PUPDATEDATA pUpdate;
  1420. INT rc;
  1421. WCHAR *pFilename;
  1422. pUpdate = (PUPDATEDATA)GlobalLock(hUpdate);
  1423. if (pUpdate == NULL) {
  1424. return GetLastError();
  1425. }
  1426. pFilename = (WCHAR*)GlobalLock(pUpdate->hFileName);
  1427. if (pFilename == NULL) {
  1428. GlobalUnlock(hUpdate);
  1429. return GetLastError();
  1430. }
  1431. /* open the original exe file */
  1432. inpfh = HandleToUlong(CreateFileW(pFilename, GENERIC_READ,
  1433. 0 /*exclusive access*/, NULL /* security attr */,
  1434. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
  1435. GlobalUnlock(pUpdate->hFileName);
  1436. if (inpfh == -1) {
  1437. GlobalUnlock(hUpdate);
  1438. return ERROR_OPEN_FAILED;
  1439. }
  1440. /* read the old format EXE header */
  1441. rc = _lread(inpfh, (char*)&oldexe, sizeof(oldexe));
  1442. if (rc != sizeof(oldexe)) {
  1443. _lclose(inpfh);
  1444. GlobalUnlock(hUpdate);
  1445. return ERROR_READ_FAULT;
  1446. }
  1447. /* make sure its really an EXE file */
  1448. if (oldexe.e_magic != IMAGE_DOS_SIGNATURE) {
  1449. _lclose(inpfh);
  1450. GlobalUnlock(hUpdate);
  1451. return ERROR_INVALID_EXE_SIGNATURE;
  1452. }
  1453. /* make sure theres a new EXE header floating around somewhere */
  1454. if (!(onewexe = oldexe.e_lfanew)) {
  1455. _lclose(inpfh);
  1456. GlobalUnlock(hUpdate);
  1457. return ERROR_BAD_EXE_FORMAT;
  1458. }
  1459. outfh = HandleToUlong(CreateFileW(pDstname, GENERIC_READ|GENERIC_WRITE,
  1460. 0 /*exclusive access*/, NULL /* security attr */,
  1461. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
  1462. if (outfh != -1) {
  1463. rc = PEWriteResFile(inpfh, outfh, onewexe, pUpdate);
  1464. _lclose(outfh);
  1465. }
  1466. _lclose(inpfh);
  1467. GlobalUnlock(hUpdate);
  1468. return rc;
  1469. }
  1470.