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.

2213 lines
44 KiB

  1. #include <windows.h>
  2. #include <shellapi.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #ifndef CHAR
  6. #define CHAR char
  7. #endif // ifndef CHAR
  8. // from winreg.h:
  9. // HKEY_CLASSES_ROOT already defined
  10. #define HKEY_CURRENT_USER (( HKEY ) 0x80000001 )
  11. #define HKEY_LOCAL_MACHINE (( HKEY ) 0x80000002 )
  12. #define HKEY_USERS (( HKEY ) 0x80000003 )
  13. #define HKEY_PERFORMANCE_DATA (( HKEY ) 0x80000004 )
  14. #define HKEY_CURRENT_CONFIG (( HKEY ) 0x80000005 )
  15. #define HKEY_DYN_DATA (( HKEY ) 0x80000006 )
  16. #include "regdef.h" // regdef.h from \\guilo\slm\src\dev\inc)
  17. //from pch.h, remove extern
  18. CHAR g_ValueNameBuffer[MAXVALUENAME_LENGTH];
  19. BYTE g_ValueDataBuffer[MAXDATA_LENGTH];
  20. // interface to regmain values
  21. extern LPSTR lpMerge;
  22. #include "reg1632.h"
  23. #include "regporte.h"
  24. #include "regresid.h"
  25. /*******************************************************************************
  26. *
  27. * (C) COPYRIGHT MICROSOFT CORP., 1993-1994
  28. *
  29. * TITLE: REGPORTE.C
  30. *
  31. * VERSION: 4.01
  32. *
  33. * AUTHOR: Tracy Sharpe
  34. *
  35. * DATE: 06 Apr 1994
  36. *
  37. * File import and export engine routines for the Registry Editor.
  38. *
  39. *******************************************************************************/
  40. //#include "pch.h"
  41. //#include "regresid.h"
  42. //#include "reg1632.h"
  43. // When building for the Registry Editor, put all of the following constants
  44. // in a read-only data section.
  45. #ifdef WIN32
  46. #pragma data_seg(DATASEG_READONLY)
  47. #endif
  48. // Association between the ASCII name and the handle of the registry key.
  49. const REGISTRY_ROOT g_RegistryRoots[] = {
  50. "HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT,
  51. "HKEY_CURRENT_USER", HKEY_CURRENT_USER,
  52. "HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE,
  53. "HKEY_USERS", HKEY_USERS,
  54. // "HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA,
  55. "HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG,
  56. "HKEY_DYN_DATA", HKEY_DYN_DATA
  57. };
  58. const CHAR s_RegistryHeader[] = "REGEDIT";
  59. const CHAR s_OldWin31RegFileRoot[] = ".classes";
  60. const CHAR s_Win40RegFileHeader[] = "REGEDIT4\n\n";
  61. const CHAR s_HexPrefix[] = "hex";
  62. const CHAR s_DwordPrefix[] = "dword:";
  63. const CHAR g_HexConversion[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
  64. '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  65. const CHAR s_FileLineBreak[] = ",\\\n ";
  66. #ifdef WIN32
  67. #pragma data_seg()
  68. #endif
  69. #define SIZE_FILE_IO_BUFFER 512
  70. typedef struct _FILE_IO {
  71. CHAR Buffer[SIZE_FILE_IO_BUFFER];
  72. FILE_HANDLE hFile;
  73. int BufferOffset;
  74. int CurrentColumn;
  75. int CharsAvailable;
  76. DWORD FileSizeDiv100;
  77. DWORD FileOffset;
  78. UINT LastPercentage;
  79. #ifdef DEBUG
  80. BOOL fValidateUngetChar;
  81. #endif
  82. } FILE_IO;
  83. FILE_IO s_FileIo;
  84. UINT g_FileErrorStringID;
  85. VOID
  86. NEAR PASCAL
  87. ImportWin31RegFile(
  88. VOID
  89. );
  90. VOID
  91. NEAR PASCAL
  92. ImportWin40RegFile(
  93. VOID
  94. );
  95. VOID
  96. NEAR PASCAL
  97. ParseHeader(
  98. LPHKEY lphKey
  99. );
  100. VOID
  101. NEAR PASCAL
  102. ParseValuename(
  103. HKEY hKey
  104. );
  105. VOID
  106. NEAR PASCAL
  107. ParseDefaultValue(
  108. HKEY hKey
  109. );
  110. BOOL
  111. NEAR PASCAL
  112. ParseString(
  113. LPSTR lpString,
  114. LPDWORD cbStringData
  115. );
  116. BOOL
  117. NEAR PASCAL
  118. ParseHexSequence(
  119. LPBYTE lpHexData,
  120. LPDWORD lpcbHexData
  121. );
  122. BOOL
  123. NEAR PASCAL
  124. ParseHexDword(
  125. LPDWORD lpDword
  126. );
  127. BOOL
  128. NEAR PASCAL
  129. ParseHexByte(
  130. LPBYTE lpByte
  131. );
  132. BOOL
  133. NEAR PASCAL
  134. ParseHexDigit(
  135. LPBYTE lpDigit
  136. );
  137. BOOL
  138. NEAR PASCAL
  139. ParseEndOfLine(
  140. VOID
  141. );
  142. VOID
  143. NEAR PASCAL
  144. SkipWhitespace(
  145. VOID
  146. );
  147. VOID
  148. NEAR PASCAL
  149. SkipPastEndOfLine(
  150. VOID
  151. );
  152. BOOL
  153. NEAR PASCAL
  154. GetChar(
  155. LPCHAR lpChar
  156. );
  157. VOID
  158. NEAR PASCAL
  159. UngetChar(
  160. VOID
  161. );
  162. BOOL
  163. NEAR PASCAL
  164. MatchChar(
  165. CHAR CharToMatch
  166. );
  167. BOOL
  168. NEAR PASCAL
  169. IsWhitespace(
  170. CHAR Char
  171. );
  172. BOOL
  173. NEAR PASCAL
  174. IsNewLine(
  175. CHAR Char
  176. );
  177. VOID
  178. NEAR PASCAL
  179. PutBranch(
  180. HKEY hKey,
  181. LPSTR lpKeyName
  182. );
  183. VOID
  184. NEAR PASCAL
  185. PutLiteral(
  186. LPCSTR lpString
  187. );
  188. VOID
  189. NEAR PASCAL
  190. PutString(
  191. LPCSTR lpString
  192. );
  193. VOID
  194. NEAR PASCAL
  195. PutBinary(
  196. CONST BYTE FAR* lpBuffer,
  197. DWORD Type,
  198. DWORD cbBytes
  199. );
  200. VOID
  201. NEAR PASCAL
  202. PutDword(
  203. DWORD Dword,
  204. BOOL fLeadingZeroes
  205. );
  206. VOID
  207. NEAR PASCAL
  208. PutChar(
  209. CHAR Char
  210. );
  211. VOID
  212. NEAR PASCAL
  213. FlushIoBuffer(
  214. VOID
  215. );
  216. #ifdef DBCS
  217. #ifndef WIN32
  218. LPSTR
  219. NEAR PASCAL
  220. DBCSStrChr(
  221. LPSTR string,
  222. CHAR chr
  223. );
  224. BOOL
  225. NEAR PASCAL
  226. IsDBCSLeadByte(
  227. BYTE chr
  228. );
  229. #endif
  230. #endif
  231. /*******************************************************************************
  232. *
  233. * CreateRegistryKey
  234. *
  235. * DESCRIPTION:
  236. * Parses the pFullKeyName string and creates a handle to the registry key.
  237. *
  238. * PARAMETERS:
  239. * lphKey, location to store handle to registry key.
  240. * lpFullKeyName, string of form "HKEY_LOCAL_MACHINE\Subkey1\Subkey2".
  241. * fCreate, TRUE if key should be created, else FALSE for open only.
  242. * (returns), ERROR_SUCCESS, no errors occurred, phKey is valid,
  243. * ERROR_CANTOPEN, registry access error of some form,
  244. * ERROR_BADKEY, incorrectly formed pFullKeyName.
  245. *
  246. *******************************************************************************/
  247. DWORD
  248. PASCAL
  249. CreateRegistryKey(
  250. LPHKEY lphKey,
  251. LPSTR lpFullKeyName,
  252. BOOL fCreate
  253. )
  254. {
  255. LPSTR lpSubKeyName;
  256. CHAR PrevChar;
  257. HKEY hRootKey;
  258. UINT Counter;
  259. DWORD Result;
  260. if ((lpSubKeyName = (LPSTR) STRCHR(lpFullKeyName, '\\')) != NULL) {
  261. PrevChar = *lpSubKeyName;
  262. *lpSubKeyName++ = '\0';
  263. }
  264. CHARUPPERSTRING(lpFullKeyName);
  265. hRootKey = NULL;
  266. for (Counter = 0; Counter < NUMBER_REGISTRY_ROOTS; Counter++) {
  267. if (STRCMP(g_RegistryRoots[Counter].lpKeyName, lpFullKeyName) == 0) {
  268. hRootKey = g_RegistryRoots[Counter].hKey;
  269. break;
  270. }
  271. }
  272. if (hRootKey) {
  273. Result = ERROR_CANTOPEN;
  274. if (fCreate) {
  275. if (RegCreateKey(hRootKey, lpSubKeyName, lphKey) == ERROR_SUCCESS)
  276. Result = ERROR_SUCCESS;
  277. }
  278. else {
  279. if (RegOpenKey(hRootKey, lpSubKeyName, lphKey) == ERROR_SUCCESS)
  280. Result = ERROR_SUCCESS;
  281. }
  282. }
  283. else
  284. Result = ERROR_BADKEY;
  285. if (lpSubKeyName != NULL) {
  286. lpSubKeyName--;
  287. *lpSubKeyName = PrevChar;
  288. }
  289. return Result;
  290. }
  291. /*******************************************************************************
  292. *
  293. * ImportRegFile
  294. *
  295. * DESCRIPTION:
  296. *
  297. * PARAMETERS:
  298. * lpFileName, address of name of file to be imported.
  299. *
  300. *******************************************************************************/
  301. #ifdef WIN95
  302. VOID
  303. PASCAL
  304. ImportRegFile(
  305. LPSTR lpFileName
  306. )
  307. {
  308. CHAR Char;
  309. LPCCH lpHeader;
  310. BOOL fNewRegistryFile;
  311. #ifdef WIN32
  312. OFSTRUCT OFStruct;
  313. #endif
  314. g_FileErrorStringID = IDS_IMPFILEERRSUCCESS;
  315. if (OPENREADFILE(lpFileName, s_FileIo.hFile)) {
  316. s_FileIo.FileSizeDiv100 = GETFILESIZE(s_FileIo.hFile) / 100;
  317. s_FileIo.FileOffset = 0;
  318. s_FileIo.LastPercentage = 0;
  319. //
  320. // The following will force GetChar to read in the first block of data.
  321. //
  322. s_FileIo.BufferOffset = SIZE_FILE_IO_BUFFER;
  323. SkipWhitespace();
  324. lpHeader = s_RegistryHeader;
  325. while (*lpHeader != '\0') {
  326. if (MatchChar(*lpHeader))
  327. lpHeader++;
  328. else
  329. break;
  330. }
  331. if (*lpHeader == '\0') {
  332. fNewRegistryFile = MatchChar('4');
  333. SkipWhitespace();
  334. if (GetChar(&Char) && IsNewLine(Char)) {
  335. if (fNewRegistryFile)
  336. ImportWin40RegFile();
  337. else
  338. ImportWin31RegFile();
  339. }
  340. }
  341. else
  342. g_FileErrorStringID = IDS_IMPFILEERRFORMATBAD;
  343. CLOSEFILE(s_FileIo.hFile);
  344. }
  345. else
  346. g_FileErrorStringID = IDS_IMPFILEERRFILEOPEN;
  347. }
  348. /*******************************************************************************
  349. *
  350. * ImportWin31RegFile
  351. *
  352. * DESCRIPTION:
  353. * Imports the contents of a Windows 3.1 style registry file into the
  354. * registry.
  355. *
  356. * We scan over the file looking for lines of the following type:
  357. * HKEY_CLASSES_ROOT\keyname = value_data
  358. * HKEY_CLASSES_ROOT\keyname =value_data
  359. * HKEY_CLASSES_ROOT\keyname value_data
  360. * HKEY_CLASSES_ROOT\keyname (null value data)
  361. *
  362. * In all cases, any number of spaces may follow 'keyname'. Although we
  363. * only document the first syntax, the Windows 3.1 Regedit handled all of
  364. * these formats as valid, so this version will as well (fortunately, it
  365. * doesn't make the parsing any more complex!).
  366. *
  367. * Note, we also support replacing HKEY_CLASSES_ROOT with \.classes above
  368. * which must come from some early releases of Windows.
  369. *
  370. * PARAMETERS:
  371. * (none).
  372. *
  373. *******************************************************************************/
  374. VOID
  375. NEAR PASCAL
  376. ImportWin31RegFile(
  377. VOID
  378. )
  379. {
  380. HKEY hKey;
  381. CHAR Char;
  382. BOOL fSuccess;
  383. LPCSTR lpClassesRoot;
  384. CHAR KeyName[MAXKEYNAME];
  385. UINT Index;
  386. //
  387. // Keep an open handle to the classes root. We may prevent some
  388. // unneccessary flushing.
  389. //
  390. if (RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey) != ERROR_SUCCESS) {
  391. g_FileErrorStringID = IDS_IMPFILEERRREGOPEN;
  392. return;
  393. }
  394. while (TRUE) {
  395. //
  396. // Check for the end of file condition.
  397. //
  398. if (!GetChar(&Char))
  399. break;
  400. UngetChar(); // Not efficient, but works for now.
  401. //
  402. // Match the beginning of the line against one of the two aliases for
  403. // HKEY_CLASSES_ROOT.
  404. //
  405. if (MatchChar('\\'))
  406. lpClassesRoot = s_OldWin31RegFileRoot;
  407. else
  408. lpClassesRoot = g_RegistryRoots[INDEX_HKEY_CLASSES_ROOT].lpKeyName;
  409. fSuccess = TRUE;
  410. while (*lpClassesRoot != '\0') {
  411. if (!MatchChar(*lpClassesRoot++)) {
  412. fSuccess = FALSE;
  413. break;
  414. }
  415. }
  416. //
  417. // Make sure that we have a backslash seperating one of the aliases
  418. // from the keyname.
  419. //
  420. if (fSuccess)
  421. fSuccess = MatchChar('\\');
  422. if (fSuccess) {
  423. //
  424. // We've found one of the valid aliases, so read in the keyname.
  425. //
  426. // fSuccess = TRUE; // Must be TRUE if we're in this block
  427. Index = 0;
  428. while (GetChar(&Char)) {
  429. if (Char == ' ' || IsNewLine(Char))
  430. break;
  431. //
  432. // Make sure that the keyname buffer doesn't overflow. We must
  433. // leave room for a terminating null.
  434. //
  435. if (Index >= sizeof(KeyName) - 1) {
  436. fSuccess = FALSE;
  437. break;
  438. }
  439. KeyName[Index++] = Char;
  440. }
  441. if (fSuccess) {
  442. KeyName[Index] = '\0';
  443. //
  444. // Now see if we have a value to assign to this keyname.
  445. //
  446. SkipWhitespace();
  447. if (MatchChar('='))
  448. MatchChar(' ');
  449. // fSuccess = TRUE; // Must be TRUE if we're in this block
  450. Index = 0;
  451. while (GetChar(&Char)) {
  452. if (IsNewLine(Char))
  453. break;
  454. //
  455. // Make sure that the value data buffer doesn't overflow.
  456. // Because this is always string data, we must leave room
  457. // for a terminating null.
  458. //
  459. if (Index >= MAXDATA_LENGTH - 1) {
  460. fSuccess = FALSE;
  461. break;
  462. }
  463. g_ValueDataBuffer[Index++] = Char;
  464. }
  465. if (fSuccess) {
  466. g_ValueDataBuffer[Index] = '\0';
  467. if (RegSetValue(hKey, KeyName, REG_SZ, g_ValueDataBuffer,
  468. Index) != ERROR_SUCCESS)
  469. g_FileErrorStringID = IDS_IMPFILEERRREGSET;
  470. }
  471. }
  472. }
  473. //
  474. // Somewhere along the line, we had a parsing error, so resynchronize
  475. // on the next line.
  476. //
  477. if (!fSuccess)
  478. SkipPastEndOfLine();
  479. }
  480. RegFlushKey(hKey);
  481. RegCloseKey(hKey);
  482. }
  483. #endif // ifdef WIN95
  484. /*******************************************************************************
  485. *
  486. * ImportWin40RegFile
  487. *
  488. * DESCRIPTION:
  489. *
  490. * PARAMETERS:
  491. *
  492. *******************************************************************************/
  493. VOID
  494. NEAR PASCAL
  495. ImportWin40RegFile(
  496. VOID
  497. )
  498. {
  499. HKEY hLocalMachineKey;
  500. HKEY hUsersKey;
  501. HKEY hKey;
  502. CHAR Char;
  503. //
  504. // Keep open handles for the predefined roots to prevent the registry
  505. // library from flushing after every single RegOpenKey/RegCloseKey
  506. // operation.
  507. //
  508. RegOpenKey(HKEY_LOCAL_MACHINE, NULL, &hLocalMachineKey);
  509. RegOpenKey(HKEY_USERS, NULL, &hUsersKey);
  510. #ifdef DEBUG
  511. if (hLocalMachineKey == NULL)
  512. OutputDebugString("Unable to open HKEY_LOCAL_MACHINE\n\r");
  513. if (hUsersKey == NULL)
  514. OutputDebugString("Unable to open HKEY_USERS\n\r");
  515. #endif
  516. hKey = NULL;
  517. while (TRUE) {
  518. SkipWhitespace();
  519. //
  520. // Check for the end of file condition.
  521. //
  522. if (!GetChar(&Char))
  523. break;
  524. switch (Char) {
  525. case '[':
  526. //
  527. // If a registry key is currently open, we must close it first.
  528. // If ParseHeader happens to fail (for example, no closing
  529. // bracket), then hKey will be NULL and any values that we
  530. // parse must be ignored.
  531. //
  532. if (hKey != NULL) {
  533. RegCloseKey(hKey);
  534. hKey = NULL;
  535. }
  536. ParseHeader(&hKey);
  537. break;
  538. case '"':
  539. //
  540. // As noted above, if we don't have an open registry key, then
  541. // just skip the line.
  542. //
  543. if (hKey != NULL)
  544. ParseValuename(hKey);
  545. else
  546. SkipPastEndOfLine();
  547. break;
  548. case '@':
  549. //
  550. //
  551. //
  552. if (hKey != NULL)
  553. ParseDefaultValue(hKey);
  554. else
  555. SkipPastEndOfLine();
  556. break;
  557. case ';':
  558. //
  559. // This line is a comment so just dump the rest of it.
  560. //
  561. SkipPastEndOfLine();
  562. break;
  563. default:
  564. if (IsNewLine(Char))
  565. break;
  566. SkipPastEndOfLine();
  567. break;
  568. }
  569. }
  570. if (hKey != NULL)
  571. RegCloseKey(hKey);
  572. if (hUsersKey != NULL)
  573. RegCloseKey(hUsersKey);
  574. if (hLocalMachineKey != NULL)
  575. RegCloseKey(hLocalMachineKey);
  576. }
  577. /*******************************************************************************
  578. *
  579. * ParseHeader
  580. *
  581. * DESCRIPTION:
  582. *
  583. * PARAMETERS:
  584. *
  585. *******************************************************************************/
  586. #define SIZE_FULL_KEYNAME (MAXKEYNAME + 40)
  587. VOID
  588. NEAR PASCAL
  589. ParseHeader(
  590. LPHKEY lphKey
  591. )
  592. {
  593. CHAR FullKeyName[SIZE_FULL_KEYNAME];
  594. int CurrentIndex;
  595. int LastRightBracketIndex;
  596. CHAR Char;
  597. CurrentIndex = 0;
  598. LastRightBracketIndex = -1;
  599. while (GetChar(&Char)) {
  600. if (IsNewLine(Char))
  601. break;
  602. if (Char == ']')
  603. LastRightBracketIndex = CurrentIndex;
  604. FullKeyName[CurrentIndex++] = Char;
  605. if (CurrentIndex == SIZE_FULL_KEYNAME) {
  606. do {
  607. if (Char == ']')
  608. LastRightBracketIndex = -1;
  609. if (IsNewLine(Char))
  610. break;
  611. } while (GetChar(&Char));
  612. break;
  613. }
  614. }
  615. if (LastRightBracketIndex != -1) {
  616. FullKeyName[LastRightBracketIndex] = '\0';
  617. switch (CreateRegistryKey(lphKey, FullKeyName, TRUE)) {
  618. case ERROR_CANTOPEN:
  619. g_FileErrorStringID = IDS_IMPFILEERRREGOPEN;
  620. break;
  621. }
  622. }
  623. }
  624. /*******************************************************************************
  625. *
  626. * ParseValuename
  627. *
  628. * DESCRIPTION:
  629. *
  630. * PARAMETERS:
  631. *
  632. *******************************************************************************/
  633. VOID
  634. NEAR PASCAL
  635. ParseValuename(
  636. HKEY hKey
  637. )
  638. {
  639. DWORD Type;
  640. CHAR ValueName[MAXVALUENAME_LENGTH];
  641. DWORD cbData;
  642. LPCSTR lpPrefix;
  643. cbData = sizeof(ValueName);
  644. if (!ParseString(ValueName, &cbData))
  645. goto ParseError;
  646. SkipWhitespace();
  647. if (!MatchChar('='))
  648. goto ParseError;
  649. SkipWhitespace();
  650. //
  651. // REG_SZ.
  652. //
  653. // "ValueName" = "string of text"
  654. //
  655. if (MatchChar('"')) {
  656. // LATER: Line continuations for strings?
  657. cbData = MAXDATA_LENGTH;
  658. if (!ParseString(g_ValueDataBuffer, &cbData) || !ParseEndOfLine())
  659. goto ParseError;
  660. Type = REG_SZ;
  661. }
  662. //
  663. // REG_DWORD.
  664. //
  665. // "ValueName" = dword: 12345678
  666. //
  667. else if (MatchChar(s_DwordPrefix[0])) {
  668. lpPrefix = &s_DwordPrefix[1];
  669. while (*lpPrefix != '\0')
  670. if (!MatchChar(*lpPrefix++))
  671. goto ParseError;
  672. SkipWhitespace();
  673. if (!ParseHexDword((LPDWORD) g_ValueDataBuffer) || !ParseEndOfLine())
  674. goto ParseError;
  675. Type = REG_DWORD;
  676. cbData = sizeof(DWORD);
  677. }
  678. //
  679. // REG_BINARY and other.
  680. //
  681. // "ValueName" = hex: 00 , 11 , 22
  682. // "ValueName" = hex(12345678): 00, 11, 22
  683. //
  684. else {
  685. lpPrefix = s_HexPrefix;
  686. while (*lpPrefix != '\0')
  687. if (!MatchChar(*lpPrefix++))
  688. goto ParseError;
  689. //
  690. // Check if this is a type of registry data that we don't directly
  691. // support. If so, then it's just a dump of hex data of the specified
  692. // type.
  693. //
  694. if (MatchChar('(')) {
  695. if (!ParseHexDword(&Type) || !MatchChar(')'))
  696. goto ParseError;
  697. }
  698. else
  699. Type = REG_BINARY;
  700. if (!MatchChar(':') || !ParseHexSequence(g_ValueDataBuffer, &cbData) ||
  701. !ParseEndOfLine())
  702. goto ParseError;
  703. }
  704. if (RegSetValueEx(hKey, ValueName, 0, Type, g_ValueDataBuffer, cbData) !=
  705. ERROR_SUCCESS)
  706. g_FileErrorStringID = IDS_IMPFILEERRREGSET;
  707. return;
  708. ParseError:
  709. SkipPastEndOfLine();
  710. }
  711. /*******************************************************************************
  712. *
  713. * ParseDefaultValue
  714. *
  715. * DESCRIPTION:
  716. *
  717. * PARAMETERS:
  718. *
  719. *******************************************************************************/
  720. VOID
  721. NEAR PASCAL
  722. ParseDefaultValue(
  723. HKEY hKey
  724. )
  725. {
  726. BOOL fSuccess;
  727. DWORD cbData;
  728. fSuccess = FALSE;
  729. SkipWhitespace();
  730. if (MatchChar('=')) {
  731. SkipWhitespace();
  732. if (MatchChar('"')) {
  733. // LATER: Line continuations for strings?
  734. cbData = MAXDATA_LENGTH;
  735. if (ParseString(g_ValueDataBuffer, &cbData) && ParseEndOfLine()) {
  736. if (RegSetValue(hKey, NULL, REG_SZ, g_ValueDataBuffer,
  737. cbData) != ERROR_SUCCESS)
  738. g_FileErrorStringID = IDS_IMPFILEERRREGSET;
  739. fSuccess = TRUE;
  740. }
  741. }
  742. }
  743. if (!fSuccess)
  744. SkipPastEndOfLine();
  745. }
  746. /*******************************************************************************
  747. *
  748. * ParseString
  749. *
  750. * DESCRIPTION:
  751. *
  752. * PARAMETERS:
  753. *
  754. *******************************************************************************/
  755. BOOL
  756. NEAR PASCAL
  757. ParseString(
  758. LPSTR lpString,
  759. LPDWORD lpcbStringData
  760. )
  761. {
  762. CHAR Char;
  763. DWORD cbMaxStringData;
  764. DWORD cbStringData;
  765. cbMaxStringData = *lpcbStringData;
  766. cbStringData = 1; // Account for the null terminator
  767. while (GetChar(&Char)) {
  768. if (cbStringData >= cbMaxStringData)
  769. return FALSE;
  770. switch (Char) {
  771. case '\\':
  772. if (!GetChar(&Char))
  773. return FALSE;
  774. switch (Char) {
  775. case '\\':
  776. *lpString++ = '\\';
  777. break;
  778. case '"':
  779. *lpString++ = '"';
  780. break;
  781. default:
  782. OutputDebugString("ParseString: Invalid escape sequence");
  783. return FALSE;
  784. }
  785. break;
  786. case '"':
  787. *lpString = '\0';
  788. *lpcbStringData = cbStringData;
  789. return TRUE;
  790. default:
  791. if (IsNewLine(Char))
  792. return FALSE;
  793. *lpString++ = Char;
  794. #ifdef DBCS
  795. if (IsDBCSLeadByte((BYTE)Char))
  796. {
  797. if (!GetChar(&Char))
  798. return FALSE;
  799. *lpString++ = Char;
  800. }
  801. #endif
  802. break;
  803. }
  804. cbStringData++;
  805. }
  806. return FALSE;
  807. }
  808. /*******************************************************************************
  809. *
  810. * ParseHexSequence
  811. *
  812. * DESCRIPTION:
  813. *
  814. * PARAMETERS:
  815. *
  816. *******************************************************************************/
  817. BOOL
  818. NEAR PASCAL
  819. ParseHexSequence(
  820. LPBYTE lpHexData,
  821. LPDWORD lpcbHexData
  822. )
  823. {
  824. DWORD cbHexData;
  825. cbHexData = 0;
  826. do {
  827. if (cbHexData >= MAXDATA_LENGTH)
  828. return FALSE;
  829. SkipWhitespace();
  830. if (MatchChar('\\') && !ParseEndOfLine())
  831. return FALSE;
  832. SkipWhitespace();
  833. if (!ParseHexByte(lpHexData++))
  834. break;
  835. cbHexData++;
  836. SkipWhitespace();
  837. } while (MatchChar(','));
  838. *lpcbHexData = cbHexData;
  839. return TRUE;
  840. }
  841. /*******************************************************************************
  842. *
  843. * ParseHexDword
  844. *
  845. * DESCRIPTION:
  846. * Parses a one dword hexadecimal string from the registry file stream and
  847. * converts it to a binary number. A maximum of eight hex digits will be
  848. * parsed from the stream.
  849. *
  850. * PARAMETERS:
  851. * lpByte, location to store binary number.
  852. * (returns), TRUE if a hexadecimal dword was parsed, else FALSE.
  853. *
  854. *******************************************************************************/
  855. BOOL
  856. NEAR PASCAL
  857. ParseHexDword(
  858. LPDWORD lpDword
  859. )
  860. {
  861. UINT CountDigits;
  862. DWORD Dword;
  863. BYTE Byte;
  864. Dword = 0;
  865. CountDigits = 0;
  866. while (TRUE) {
  867. if (!ParseHexDigit(&Byte))
  868. break;
  869. Dword = (Dword << 4) + (DWORD) Byte;
  870. if (++CountDigits == 8)
  871. break;
  872. }
  873. *lpDword = Dword;
  874. return CountDigits != 0;
  875. }
  876. /*******************************************************************************
  877. *
  878. * ParseHexByte
  879. *
  880. * DESCRIPTION:
  881. * Parses a one byte hexadecimal string from the registry file stream and
  882. * converts it to a binary number.
  883. *
  884. * PARAMETERS:
  885. * lpByte, location to store binary number.
  886. * (returns), TRUE if a hexadecimal byte was parsed, else FALSE.
  887. *
  888. *******************************************************************************/
  889. BOOL
  890. NEAR PASCAL
  891. ParseHexByte(
  892. LPBYTE lpByte
  893. )
  894. {
  895. BYTE SecondDigit;
  896. if (ParseHexDigit(lpByte)) {
  897. if (ParseHexDigit(&SecondDigit))
  898. *lpByte = (BYTE) ((*lpByte << 4) | SecondDigit);
  899. return TRUE;
  900. }
  901. else
  902. return FALSE;
  903. }
  904. /*******************************************************************************
  905. *
  906. * ParseHexDigit
  907. *
  908. * DESCRIPTION:
  909. * Parses a hexadecimal character from the registry file stream and converts
  910. * it to a binary number.
  911. *
  912. * PARAMETERS:
  913. * lpDigit, location to store binary number.
  914. * (returns), TRUE if a hexadecimal digit was parsed, else FALSE.
  915. *
  916. *******************************************************************************/
  917. BOOL
  918. NEAR PASCAL
  919. ParseHexDigit(
  920. LPBYTE lpDigit
  921. )
  922. {
  923. CHAR Char;
  924. BYTE Digit;
  925. if (GetChar(&Char)) {
  926. if (Char >= '0' && Char <= '9')
  927. Digit = (BYTE) (Char - '0');
  928. else if (Char >= 'a' && Char <= 'f')
  929. Digit = (BYTE) (Char - 'a' + 10);
  930. else if (Char >= 'A' && Char <= 'F')
  931. Digit = (BYTE) (Char - 'A' + 10);
  932. else {
  933. UngetChar();
  934. return FALSE;
  935. }
  936. *lpDigit = Digit;
  937. return TRUE;
  938. }
  939. return FALSE;
  940. }
  941. /*******************************************************************************
  942. *
  943. * ParseEndOfLine
  944. *
  945. * DESCRIPTION:
  946. *
  947. * PARAMETERS:
  948. *
  949. *******************************************************************************/
  950. BOOL
  951. NEAR PASCAL
  952. ParseEndOfLine(
  953. VOID
  954. )
  955. {
  956. CHAR Char;
  957. BOOL fComment;
  958. BOOL fFoundOneEndOfLine;
  959. fComment = FALSE;
  960. fFoundOneEndOfLine = FALSE;
  961. while (GetChar(&Char)) {
  962. if (IsWhitespace(Char))
  963. continue;
  964. if (IsNewLine(Char)) {
  965. fComment = FALSE;
  966. fFoundOneEndOfLine = TRUE;
  967. }
  968. //
  969. // Like .INIs and .INFs, comments begin with a semicolon character.
  970. //
  971. else if (Char == ';')
  972. fComment = TRUE;
  973. else if (!fComment) {
  974. UngetChar();
  975. break;
  976. }
  977. }
  978. return fFoundOneEndOfLine;
  979. }
  980. /*******************************************************************************
  981. *
  982. * SkipWhitespace
  983. *
  984. * DESCRIPTION:
  985. * Advances the registry file pointer to the first character past any
  986. * detected whitespace.
  987. *
  988. * PARAMETERS:
  989. * (none).
  990. *
  991. *******************************************************************************/
  992. VOID
  993. NEAR PASCAL
  994. SkipWhitespace(
  995. VOID
  996. )
  997. {
  998. CHAR Char;
  999. while (GetChar(&Char)) {
  1000. if (!IsWhitespace(Char)) {
  1001. UngetChar();
  1002. break;
  1003. }
  1004. }
  1005. }
  1006. /*******************************************************************************
  1007. *
  1008. * SkipPastEndOfLine
  1009. *
  1010. * DESCRIPTION:
  1011. * Advances the registry file pointer to the first character past the first
  1012. * detected new line character.
  1013. *
  1014. * PARAMETERS:
  1015. * (none).
  1016. *
  1017. *******************************************************************************/
  1018. VOID
  1019. NEAR PASCAL
  1020. SkipPastEndOfLine(
  1021. VOID
  1022. )
  1023. {
  1024. CHAR Char;
  1025. while (GetChar(&Char)) {
  1026. if (IsNewLine(Char))
  1027. break;
  1028. }
  1029. while (GetChar(&Char)) {
  1030. if (!IsNewLine(Char)) {
  1031. UngetChar();
  1032. break;
  1033. }
  1034. }
  1035. }
  1036. /*******************************************************************************
  1037. *
  1038. * GetChar
  1039. *
  1040. * DESCRIPTION:
  1041. *
  1042. * PARAMETERS:
  1043. *
  1044. *******************************************************************************/
  1045. BOOL
  1046. NEAR PASCAL
  1047. GetChar(
  1048. LPCHAR lpChar
  1049. )
  1050. {
  1051. #ifdef WIN95
  1052. FILE_NUMBYTES NumberOfBytesRead;
  1053. UINT NewPercentage;
  1054. if (s_FileIo.BufferOffset == SIZE_FILE_IO_BUFFER) {
  1055. if (!READFILE(s_FileIo.hFile, s_FileIo.Buffer,
  1056. sizeof(s_FileIo.Buffer), &NumberOfBytesRead)) {
  1057. g_FileErrorStringID = IDS_IMPFILEERRFILEREAD;
  1058. return FALSE;
  1059. }
  1060. s_FileIo.BufferOffset = 0;
  1061. s_FileIo.CharsAvailable = ((int) NumberOfBytesRead);
  1062. s_FileIo.FileOffset += NumberOfBytesRead;
  1063. if (s_FileIo.FileSizeDiv100 != 0) {
  1064. NewPercentage = ((UINT) (s_FileIo.FileOffset /
  1065. s_FileIo.FileSizeDiv100));
  1066. if (NewPercentage > 100)
  1067. NewPercentage = 100;
  1068. }
  1069. else
  1070. NewPercentage = 100;
  1071. if (s_FileIo.LastPercentage != NewPercentage) {
  1072. s_FileIo.LastPercentage = NewPercentage;
  1073. ImportRegFileUICallback(NewPercentage);
  1074. }
  1075. }
  1076. if (s_FileIo.BufferOffset >= s_FileIo.CharsAvailable)
  1077. return FALSE;
  1078. *lpChar = s_FileIo.Buffer[s_FileIo.BufferOffset++];
  1079. return TRUE;
  1080. #else
  1081. if (*lpMerge) {
  1082. *lpChar=*lpMerge++;
  1083. return TRUE;
  1084. } else
  1085. return FALSE;
  1086. #endif // ifdef WIN95
  1087. }
  1088. /*******************************************************************************
  1089. *
  1090. * UngetChar
  1091. *
  1092. * DESCRIPTION:
  1093. *
  1094. * PARAMETERS:
  1095. *
  1096. *******************************************************************************/
  1097. VOID
  1098. NEAR PASCAL
  1099. UngetChar(
  1100. VOID
  1101. )
  1102. {
  1103. #ifdef WIN95
  1104. #ifdef DEBUG
  1105. if (s_FileIo.fValidateUngetChar)
  1106. OutputDebugString("REGEDIT ERROR: Too many UngetChar's called!\n\r");
  1107. #endif // ifdef DEBUG
  1108. s_FileIo.BufferOffset--;
  1109. #else
  1110. lpMerge--;
  1111. #endif // ifdef WIN95
  1112. }
  1113. /*******************************************************************************
  1114. *
  1115. * MatchChar
  1116. *
  1117. * DESCRIPTION:
  1118. *
  1119. * PARAMETERS:
  1120. *
  1121. *******************************************************************************/
  1122. BOOL
  1123. NEAR PASCAL
  1124. MatchChar(
  1125. CHAR CharToMatch
  1126. )
  1127. {
  1128. BOOL fMatch;
  1129. CHAR NextChar;
  1130. fMatch = FALSE;
  1131. if (GetChar(&NextChar)) {
  1132. if (CharToMatch == NextChar)
  1133. fMatch = TRUE;
  1134. else
  1135. UngetChar();
  1136. }
  1137. return fMatch;
  1138. }
  1139. /*******************************************************************************
  1140. *
  1141. * IsWhitespace
  1142. *
  1143. * DESCRIPTION:
  1144. * Checks if the given character is whitespace.
  1145. *
  1146. * PARAMETERS:
  1147. * Char, character to check.
  1148. * (returns), TRUE if character is whitespace, else FALSE.
  1149. *
  1150. *******************************************************************************/
  1151. BOOL
  1152. NEAR PASCAL
  1153. IsWhitespace(
  1154. CHAR Char
  1155. )
  1156. {
  1157. return Char == ' ' || Char == '\t';
  1158. }
  1159. /*******************************************************************************
  1160. *
  1161. * IsNewLine
  1162. *
  1163. * DESCRIPTION:
  1164. * Checks if the given character is a new line character.
  1165. *
  1166. * PARAMETERS:
  1167. * Char, character to check.
  1168. * (returns), TRUE if character is a new line, else FALSE.
  1169. *
  1170. *******************************************************************************/
  1171. BOOL
  1172. NEAR PASCAL
  1173. IsNewLine(
  1174. CHAR Char
  1175. )
  1176. {
  1177. return Char == '\n' || Char == '\r';
  1178. }
  1179. #ifdef WIN95
  1180. /*******************************************************************************
  1181. *
  1182. * ExportWin40RegFile
  1183. *
  1184. * DESCRIPTION:
  1185. *
  1186. * PARAMETERS:
  1187. *
  1188. *******************************************************************************/
  1189. VOID
  1190. PASCAL
  1191. ExportWin40RegFile(
  1192. LPSTR lpFileName,
  1193. LPSTR lpSelectedPath
  1194. )
  1195. {
  1196. HKEY hKey;
  1197. CHAR SelectedPath[SIZE_SELECTED_PATH];
  1198. g_FileErrorStringID = IDS_EXPFILEERRSUCCESS;
  1199. if (lpSelectedPath != NULL && CreateRegistryKey(&hKey, lpSelectedPath,
  1200. FALSE) != ERROR_SUCCESS) {
  1201. g_FileErrorStringID = IDS_EXPFILEERRBADREGPATH;
  1202. return;
  1203. }
  1204. if (OPENWRITEFILE(lpFileName, s_FileIo.hFile)) {
  1205. s_FileIo.BufferOffset = 0;
  1206. s_FileIo.CurrentColumn = 0;
  1207. PutLiteral(s_Win40RegFileHeader);
  1208. if (lpSelectedPath != NULL) {
  1209. STRCPY(SelectedPath, lpSelectedPath);
  1210. PutBranch(hKey, SelectedPath);
  1211. }
  1212. else {
  1213. STRCPY(SelectedPath,
  1214. g_RegistryRoots[INDEX_HKEY_LOCAL_MACHINE].lpKeyName);
  1215. PutBranch(HKEY_LOCAL_MACHINE, SelectedPath);
  1216. STRCPY(SelectedPath,
  1217. g_RegistryRoots[INDEX_HKEY_USERS].lpKeyName);
  1218. PutBranch(HKEY_USERS, SelectedPath);
  1219. }
  1220. FlushIoBuffer();
  1221. CLOSEFILE(s_FileIo.hFile);
  1222. }
  1223. else
  1224. g_FileErrorStringID = IDS_EXPFILEERRFILEOPEN;
  1225. if (lpSelectedPath != NULL)
  1226. RegCloseKey(hKey);
  1227. }
  1228. /*******************************************************************************
  1229. *
  1230. * PutBranch
  1231. *
  1232. * DESCRIPTION:
  1233. * Writes out all of the value names and their data and recursively calls
  1234. * this routine for all of the key's subkeys to the registry file stream.
  1235. *
  1236. * PARAMETERS:
  1237. * hKey, registry key to write to file.
  1238. * lpFullKeyName, string that gives the full path, including the root key
  1239. * name, of the hKey.
  1240. *
  1241. *******************************************************************************/
  1242. VOID
  1243. NEAR PASCAL
  1244. PutBranch(
  1245. HKEY hKey,
  1246. LPSTR lpFullKeyName
  1247. )
  1248. {
  1249. LONG RegError;
  1250. DWORD EnumIndex;
  1251. DWORD cbValueName;
  1252. DWORD cbValueData;
  1253. DWORD Type;
  1254. LPSTR lpSubKeyName;
  1255. int MaximumSubKeyLength;
  1256. HKEY hSubKey;
  1257. //
  1258. // Write out the section header.
  1259. //
  1260. PutChar('[');
  1261. PutLiteral(lpFullKeyName);
  1262. PutLiteral("]\n");
  1263. //
  1264. // Write out all of the value names and their data.
  1265. //
  1266. EnumIndex = 0;
  1267. while (TRUE) {
  1268. cbValueName = sizeof(g_ValueNameBuffer);
  1269. cbValueData = MAXDATA_LENGTH;
  1270. if ((RegError = RegEnumValue(hKey, EnumIndex++, g_ValueNameBuffer,
  1271. &cbValueName, NULL, &Type, g_ValueDataBuffer, &cbValueData))
  1272. != ERROR_SUCCESS)
  1273. break;
  1274. //
  1275. // If cbValueName is zero, then this is the default value of
  1276. // the key, or the Windows 3.1 compatible key value.
  1277. //
  1278. if (cbValueName)
  1279. PutString(g_ValueNameBuffer);
  1280. else
  1281. PutChar('@');
  1282. PutChar('=');
  1283. switch (Type) {
  1284. case REG_SZ:
  1285. PutString((LPSTR) g_ValueDataBuffer);
  1286. break;
  1287. case REG_DWORD:
  1288. if (cbValueData == sizeof(DWORD)) {
  1289. PutLiteral(s_DwordPrefix);
  1290. PutDword(*((LPDWORD) g_ValueDataBuffer), TRUE);
  1291. break;
  1292. }
  1293. // FALL THROUGH
  1294. case REG_BINARY:
  1295. default:
  1296. PutBinary((LPBYTE) g_ValueDataBuffer, Type, cbValueData);
  1297. break;
  1298. }
  1299. PutChar('\n');
  1300. if (g_FileErrorStringID == IDS_EXPFILEERRFILEWRITE)
  1301. return;
  1302. }
  1303. PutChar('\n');
  1304. if (RegError != ERROR_NO_MORE_ITEMS)
  1305. g_FileErrorStringID = IDS_EXPFILEERRREGENUM;
  1306. //
  1307. // Write out all of the subkeys and recurse into them.
  1308. //
  1309. lpSubKeyName = lpFullKeyName + STRLEN(lpFullKeyName);
  1310. *lpSubKeyName++ = '\\';
  1311. MaximumSubKeyLength = MAXKEYNAME - STRLEN(lpSubKeyName);
  1312. EnumIndex = 0;
  1313. while (TRUE) {
  1314. if ((RegError = RegEnumKey(hKey, EnumIndex++, lpSubKeyName,
  1315. MaximumSubKeyLength)) != ERROR_SUCCESS)
  1316. break;
  1317. if (RegOpenKey(hKey, lpSubKeyName, &hSubKey) == ERROR_SUCCESS) {
  1318. PutBranch(hSubKey, lpFullKeyName);
  1319. RegCloseKey(hSubKey);
  1320. if (g_FileErrorStringID == IDS_EXPFILEERRFILEWRITE)
  1321. return;
  1322. }
  1323. else
  1324. g_FileErrorStringID = IDS_EXPFILEERRREGOPEN;
  1325. }
  1326. if (RegError != ERROR_NO_MORE_ITEMS)
  1327. g_FileErrorStringID = IDS_EXPFILEERRREGENUM;
  1328. }
  1329. /*******************************************************************************
  1330. *
  1331. * PutLiteral
  1332. *
  1333. * DESCRIPTION:
  1334. * Writes a literal string to the registry file stream. No special handling
  1335. * is done for the string-- it is written out as is.
  1336. *
  1337. * PARAMETERS:
  1338. * lpLiteral, null-terminated literal to write to file.
  1339. *
  1340. *******************************************************************************/
  1341. VOID
  1342. NEAR PASCAL
  1343. PutLiteral(
  1344. LPCSTR lpLiteral
  1345. )
  1346. {
  1347. while (*lpLiteral != '\0')
  1348. PutChar(*lpLiteral++);
  1349. }
  1350. /*******************************************************************************
  1351. *
  1352. * PutString
  1353. *
  1354. * DESCRIPTION:
  1355. * Writes a string to the registry file stream. A string is surrounded by
  1356. * double quotes and some characters may be translated to escape sequences
  1357. * to enable a parser to read the string back in.
  1358. *
  1359. * PARAMETERS:
  1360. * lpString, null-terminated string to write to file.
  1361. *
  1362. *******************************************************************************/
  1363. VOID
  1364. NEAR PASCAL
  1365. PutString(
  1366. LPCSTR lpString
  1367. )
  1368. {
  1369. CHAR Char;
  1370. PutChar('"');
  1371. while ((Char = *lpString++) != '\0') {
  1372. switch (Char) {
  1373. case '\\':
  1374. case '"':
  1375. PutChar('\\');
  1376. // FALL THROUGH
  1377. default:
  1378. PutChar(Char);
  1379. #ifdef DBCS
  1380. if (IsDBCSLeadByte((BYTE)Char))
  1381. PutChar(*lpString++);
  1382. #endif
  1383. break;
  1384. }
  1385. }
  1386. PutChar('"');
  1387. }
  1388. /*******************************************************************************
  1389. *
  1390. * PutBinary
  1391. *
  1392. * DESCRIPTION:
  1393. * Writes a sequence of hexadecimal bytes to the registry file stream. The
  1394. * output is formatted such that it doesn't exceed a defined line length.
  1395. *
  1396. * PARAMETERS:
  1397. * lpBuffer, bytes to write to file.
  1398. * Type, value data type.
  1399. * cbBytes, number of bytes to write.
  1400. *
  1401. *******************************************************************************/
  1402. VOID
  1403. NEAR PASCAL
  1404. PutBinary(
  1405. CONST BYTE FAR* lpBuffer,
  1406. DWORD Type,
  1407. DWORD cbBytes
  1408. )
  1409. {
  1410. BOOL fFirstByteOnLine;
  1411. BYTE Byte;
  1412. PutLiteral(s_HexPrefix);
  1413. if (Type != REG_BINARY) {
  1414. PutChar('(');
  1415. PutDword(Type, FALSE);
  1416. PutChar(')');
  1417. }
  1418. PutChar(':');
  1419. fFirstByteOnLine = TRUE;
  1420. while (cbBytes--) {
  1421. if (s_FileIo.CurrentColumn > 75) {
  1422. PutLiteral(s_FileLineBreak);
  1423. fFirstByteOnLine = TRUE;
  1424. }
  1425. if (!fFirstByteOnLine)
  1426. PutChar(',');
  1427. Byte = *lpBuffer++;
  1428. PutChar(g_HexConversion[Byte >> 4]);
  1429. PutChar(g_HexConversion[Byte & 0x0F]);
  1430. fFirstByteOnLine = FALSE;
  1431. }
  1432. }
  1433. /*******************************************************************************
  1434. *
  1435. * PutChar
  1436. *
  1437. * DESCRIPTION:
  1438. * Writes a 32-bit word to the registry file stream.
  1439. *
  1440. * PARAMETERS:
  1441. * Dword, dword to write to file.
  1442. *
  1443. *******************************************************************************/
  1444. VOID
  1445. NEAR PASCAL
  1446. PutDword(
  1447. DWORD Dword,
  1448. BOOL fLeadingZeroes
  1449. )
  1450. {
  1451. int CurrentNibble;
  1452. CHAR Char;
  1453. BOOL fWroteNonleadingChar;
  1454. fWroteNonleadingChar = fLeadingZeroes;
  1455. for (CurrentNibble = 7; CurrentNibble >= 0; CurrentNibble--) {
  1456. Char = g_HexConversion[(Dword >> (CurrentNibble * 4)) & 0x0F];
  1457. if (fWroteNonleadingChar || Char != '0') {
  1458. PutChar(Char);
  1459. fWroteNonleadingChar = TRUE;
  1460. }
  1461. }
  1462. //
  1463. // We need to write at least one character, so if we haven't written
  1464. // anything yet, just spit out one zero.
  1465. //
  1466. if (!fWroteNonleadingChar)
  1467. PutChar('0');
  1468. }
  1469. /*******************************************************************************
  1470. *
  1471. * PutChar
  1472. *
  1473. * DESCRIPTION:
  1474. * Writes one character to the registry file stream using an intermediate
  1475. * buffer.
  1476. *
  1477. * PARAMETERS:
  1478. * Char, character to write to file.
  1479. *
  1480. *******************************************************************************/
  1481. VOID
  1482. NEAR PASCAL
  1483. PutChar(
  1484. CHAR Char
  1485. )
  1486. {
  1487. //
  1488. // Keep track of what column we're currently at. This is useful in cases
  1489. // such as writing a large binary registry record. Instead of writing one
  1490. // very long line, the other Put* routines can break up their output.
  1491. //
  1492. if (Char != '\n')
  1493. s_FileIo.CurrentColumn++;
  1494. else {
  1495. //
  1496. // Force a carriage-return, line-feed sequence to keep things like, oh,
  1497. // Notepad happy.
  1498. //
  1499. PutChar('\r');
  1500. s_FileIo.CurrentColumn = 0;
  1501. }
  1502. s_FileIo.Buffer[s_FileIo.BufferOffset++] = Char;
  1503. if (s_FileIo.BufferOffset == SIZE_FILE_IO_BUFFER)
  1504. FlushIoBuffer();
  1505. }
  1506. /*******************************************************************************
  1507. *
  1508. * FlushIoBuffer
  1509. *
  1510. * DESCRIPTION:
  1511. * Flushes the contents of the registry file stream to the disk and resets
  1512. * the buffer pointer.
  1513. *
  1514. * PARAMETERS:
  1515. * (none).
  1516. *
  1517. *******************************************************************************/
  1518. VOID
  1519. NEAR PASCAL
  1520. FlushIoBuffer(
  1521. VOID
  1522. )
  1523. {
  1524. FILE_NUMBYTES NumberOfBytesWritten;
  1525. if (s_FileIo.BufferOffset) {
  1526. if (!WRITEFILE(s_FileIo.hFile, s_FileIo.Buffer, s_FileIo.BufferOffset,
  1527. &NumberOfBytesWritten) || (FILE_NUMBYTES) s_FileIo.BufferOffset !=
  1528. NumberOfBytesWritten)
  1529. g_FileErrorStringID = IDS_EXPFILEERRFILEWRITE;
  1530. }
  1531. s_FileIo.BufferOffset = 0;
  1532. }
  1533. #endif // ifdef WIN95
  1534. #ifndef WIN32
  1535. /*******************************************************************************
  1536. *
  1537. * GetFileSize
  1538. *
  1539. * DESCRIPTION:
  1540. * Returns the file size for the given file handle.
  1541. *
  1542. * DESTRUCTIVE: After this call, the file pointer will be set to byte zero.
  1543. *
  1544. * PARAMETERS:
  1545. * hFile, file handle opened via MS-DOS.
  1546. * (returns), size of file.
  1547. *
  1548. *******************************************************************************/
  1549. DWORD
  1550. NEAR PASCAL
  1551. GetFileSize(
  1552. FILE_HANDLE hFile
  1553. )
  1554. {
  1555. DWORD FileSize;
  1556. FileSize = _llseek(hFile, 0, SEEK_END);
  1557. _llseek(hFile, 0, SEEK_SET);
  1558. return FileSize;
  1559. }
  1560. #endif
  1561. #ifdef DBCS
  1562. #ifndef WIN32
  1563. /*******************************************************************************
  1564. *
  1565. * DBCSSTRCHR
  1566. *
  1567. * DESCRIPTION:
  1568. * DBCS enabled STRCHR
  1569. *
  1570. *******************************************************************************/
  1571. LPSTR
  1572. NEAR PASCAL
  1573. DBCSStrChr(
  1574. LPSTR string,
  1575. CHAR chr
  1576. )
  1577. {
  1578. LPSTR p;
  1579. p = string;
  1580. while (*p)
  1581. {
  1582. if (IsDBCSLeadByte((BYTE)*p))
  1583. {
  1584. p++;
  1585. if (*p == 0)
  1586. break;
  1587. }
  1588. else if (*p == chr)
  1589. return (p);
  1590. p++;
  1591. }
  1592. if (*p == chr)
  1593. return (p);
  1594. return NULL;
  1595. }
  1596. /*******************************************************************************
  1597. *
  1598. * IsDBCSLeadByte
  1599. *
  1600. * DESCRIPTION:
  1601. * Test if the character is DBCS lead byte
  1602. *
  1603. *******************************************************************************/
  1604. BOOL
  1605. NEAR PASCAL
  1606. IsDBCSLeadByte(
  1607. BYTE chr
  1608. )
  1609. {
  1610. static unsigned char far *DBCSLeadByteTable = NULL;
  1611. WORD off,segs;
  1612. LPSTR p;
  1613. if (DBCSLeadByteTable == NULL)
  1614. {
  1615. _asm {
  1616. push ds
  1617. mov ax,6300h
  1618. int 21h
  1619. mov off,si
  1620. mov segs,ds
  1621. pop ds
  1622. }
  1623. FP_OFF(DBCSLeadByteTable) = off;
  1624. FP_SEG(DBCSLeadByteTable) = segs;
  1625. }
  1626. p = DBCSLeadByteTable;
  1627. while (p[0] || p[1])
  1628. {
  1629. if (chr >= p[0] && chr <= p[1])
  1630. return TRUE;
  1631. p += 2;
  1632. }
  1633. return FALSE;
  1634. }
  1635. #endif // WIN32
  1636. #endif // DBCS