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.

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