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.

1041 lines
23 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name :
  4. parseini.cpp
  5. Abstract:
  6. Class used to parse the ini file
  7. Author:
  8. Christopher Achille (cachille)
  9. Project:
  10. URLScan Update
  11. Revision History:
  12. March 2002: Created
  13. --*/
  14. #include "stdafx.h"
  15. #include "windows.h"
  16. #include "parseini.h"
  17. #include "stdio.h"
  18. #include "malloc.h"
  19. // Constructor
  20. //
  21. CIniFileLine::CIniFileLine()
  22. {
  23. m_szLine[0] = '\0';
  24. m_szStrippedLineContents[0] = '\0';
  25. }
  26. // CopyLine
  27. //
  28. // Copy the specific line into both our buffers
  29. //
  30. BOOL
  31. CIniFileLine::CopyLine(LPWSTR szNewLineContents)
  32. {
  33. if ( _tcslen( szNewLineContents ) >= ( MAX_PATH - 1 ) )
  34. {
  35. // Right now we only support loading Lines of MAX_PATH
  36. // chars or less
  37. return FALSE;
  38. }
  39. // Copy String into both buffers
  40. _tcscpy(m_szLine, szNewLineContents);
  41. _tcscpy(m_szStrippedLineContents, szNewLineContents);
  42. // Strip off \r\n
  43. StripOffEOL( m_szLine );
  44. StripOffEOL( m_szStrippedLineContents );
  45. // Strip off Comments
  46. StripOffComments( m_szStrippedLineContents );
  47. // Stipp off trailing white
  48. StripOffTrailingWhite( m_szStrippedLineContents );
  49. return TRUE;
  50. }
  51. // CopyLine
  52. //
  53. // Copy the specific line into both our buffers
  54. //
  55. BOOL
  56. CIniFileLine::CopyLine(LPSTR szNewLineContents)
  57. {
  58. WCHAR szBuffer[MAX_PATH];
  59. if ( !MultiByteToWideChar( CP_ACP, //CP_THREAD_ACP doesn't work on NT4
  60. MB_ERR_INVALID_CHARS,
  61. szNewLineContents, // Input String
  62. -1, // Null terminated
  63. szBuffer,
  64. MAX_PATH ) )
  65. {
  66. return FALSE;
  67. }
  68. return CopyLine( szBuffer );
  69. }
  70. // StripOffEOL
  71. //
  72. // Strip off the EOL markers
  73. //
  74. void
  75. CIniFileLine::StripOffEOL(LPTSTR szString)
  76. {
  77. LPTSTR szCurrent;
  78. szCurrent = _tcsstr( szString, L"\r" );
  79. if ( szCurrent )
  80. {
  81. *szCurrent = '\0';
  82. return;
  83. }
  84. szCurrent = _tcsstr( szString, L"\n" );
  85. if ( szCurrent )
  86. {
  87. // we won't hit this case, unless it was terminated with
  88. // just \n
  89. *szCurrent = '\0';
  90. }
  91. }
  92. // StripOffComments
  93. //
  94. // Strip off any comments that are in the line
  95. //
  96. void
  97. CIniFileLine::StripOffComments(LPTSTR szString)
  98. {
  99. LPTSTR szCurrent;
  100. szCurrent = _tcsstr( szString, L";" );
  101. if ( szCurrent )
  102. {
  103. *szCurrent = '\0';
  104. }
  105. }
  106. // Strip Off TrailingWhite
  107. //
  108. // strip off all the trailing while stuff in the line
  109. //
  110. void
  111. CIniFileLine::StripOffTrailingWhite(LPTSTR szString)
  112. {
  113. // Set szCurrent at Null Terminator
  114. LPTSTR szCurrent = szString + _tcslen( szString );
  115. if ( ( *szCurrent == '\0' ) &&
  116. ( szCurrent != szString ) )
  117. {
  118. // Backup one character to start on the last char
  119. szCurrent--;
  120. }
  121. while ( ( szCurrent != szString ) &&
  122. ( ( *szCurrent == ' ' ) ||
  123. ( *szCurrent == '\t' ) )
  124. )
  125. {
  126. szCurrent--;
  127. }
  128. if ( *szCurrent != '\0' )
  129. {
  130. *( szCurrent + 1 ) = '\0';
  131. }
  132. }
  133. // QueryLine
  134. //
  135. // Query the contents of the line, before formatting
  136. //
  137. LPTSTR
  138. CIniFileLine::QueryLine()
  139. {
  140. return m_szLine;
  141. }
  142. // QueryStrippedLine
  143. //
  144. // Query the line that has the comments, EOL, and
  145. // white spaces removed
  146. //
  147. LPTSTR
  148. CIniFileLine::QueryStrippedLine()
  149. {
  150. return m_szStrippedLineContents;
  151. }
  152. // Constructor
  153. //
  154. CIniFile::CIniFile()
  155. {
  156. // Initialize everything to empty
  157. m_pIniLines = NULL;
  158. m_dwNumberofLines = 0;
  159. m_dwLinesAllocated = 0;
  160. m_dwCurrentLine = 0;
  161. m_bUnicodeFile = FALSE;
  162. }
  163. // Destructor
  164. //
  165. CIniFile::~CIniFile()
  166. {
  167. ClearIni();
  168. }
  169. // ClearIni
  170. //
  171. // Clear all of the data in the ini file class
  172. //
  173. void
  174. CIniFile::ClearIni()
  175. {
  176. DWORD dwCurrent;
  177. if ( m_pIniLines )
  178. {
  179. for ( dwCurrent = 0;
  180. dwCurrent < m_dwLinesAllocated;
  181. dwCurrent ++ )
  182. {
  183. if ( m_pIniLines[dwCurrent] )
  184. {
  185. // Free memory, and reset to NULL
  186. delete m_pIniLines[dwCurrent];
  187. m_pIniLines[dwCurrent] = NULL;
  188. }
  189. }
  190. m_dwNumberofLines = 0;
  191. // Free Ini Table Altogether
  192. delete m_pIniLines;
  193. m_pIniLines = NULL;
  194. m_dwLinesAllocated = 0;
  195. }
  196. }
  197. // CreateMoreLines
  198. //
  199. // Create Room for more lines on the array. This allows us to
  200. // stretch the array
  201. BOOL
  202. CIniFile::CreateRoomForMoreLines()
  203. {
  204. CIniFileLine **pNewLines = NULL;
  205. DWORD dwNewNumberofLinesAllocated = m_dwLinesAllocated ?
  206. m_dwLinesAllocated * 2 :
  207. INIFILE_INITIALNUMBEROFLINES;
  208. DWORD dwCurrent;
  209. // Enlarge buffer
  210. pNewLines = (CIniFileLine **) realloc( m_pIniLines,
  211. sizeof( CIniFileLine * ) * dwNewNumberofLinesAllocated );
  212. if ( pNewLines == NULL )
  213. {
  214. // Failure to enlarge.
  215. // Do not need to worry about old memory, since it is still valid in m_pIniLines
  216. return FALSE;
  217. }
  218. for ( dwCurrent = m_dwLinesAllocated;
  219. dwCurrent < dwNewNumberofLinesAllocated;
  220. dwCurrent++ )
  221. {
  222. // Initialize to Null
  223. pNewLines[ dwCurrent ] = NULL;
  224. }
  225. m_pIniLines = pNewLines;
  226. m_dwLinesAllocated = dwNewNumberofLinesAllocated;
  227. return TRUE;
  228. }
  229. // AddLine
  230. //
  231. // Add a line at a specific location
  232. //
  233. // Parameters:
  234. // dwLineNumber - The line number where it should be inserted
  235. //
  236. // Return
  237. // NULL - Failure
  238. // Pointer - A pointer to the CIniFileLine for the new line
  239. //
  240. CIniFileLine *
  241. CIniFile::AddLine( DWORD dwLocation )
  242. {
  243. CIniFileLine *pNewLine;
  244. DWORD dwCurrentLine;
  245. if ( dwLocation > m_dwNumberofLines )
  246. {
  247. // Fail if we try to insert in a number to big
  248. return FALSE;
  249. }
  250. if ( ( m_dwNumberofLines == m_dwLinesAllocated ) &&
  251. !CreateRoomForMoreLines() )
  252. {
  253. // Could not create new lines for us
  254. return FALSE;
  255. }
  256. pNewLine = new (CIniFileLine);
  257. if ( !pNewLine )
  258. {
  259. // Failure to create new line
  260. return FALSE;
  261. }
  262. // Move all the lines after it down, to make room for this one
  263. if ( m_dwNumberofLines != 0 )
  264. {
  265. for ( dwCurrentLine = m_dwNumberofLines - 1;
  266. dwCurrentLine >= dwLocation;
  267. dwCurrentLine-- )
  268. {
  269. m_pIniLines[ dwCurrentLine + 1 ] = m_pIniLines[ dwCurrentLine ];
  270. }
  271. }
  272. m_pIniLines[ dwLocation ] = pNewLine;
  273. m_dwNumberofLines++;
  274. return pNewLine;
  275. }
  276. // FindSectionNumber
  277. //
  278. // Find a section by a specific name
  279. //
  280. // Parameters
  281. // szSectionName - [in] Section to look for
  282. // pdwSection - [out] The Line #
  283. //
  284. // Return:
  285. // TRUE - Found
  286. // FALSE - Not found
  287. //
  288. BOOL
  289. CIniFile::FindSectionNumber(LPTSTR szSectionName, DWORD *pdwSection)
  290. {
  291. DWORD dwCurrentIndex;
  292. // ASSERT( pdwSection );
  293. for ( dwCurrentIndex = 0; dwCurrentIndex < m_dwNumberofLines; dwCurrentIndex++ )
  294. {
  295. if ( IsSameSection( szSectionName,
  296. m_pIniLines[dwCurrentIndex]->QueryStrippedLine() ) )
  297. {
  298. *pdwSection = dwCurrentIndex;
  299. return TRUE;
  300. }
  301. }
  302. return FALSE;
  303. }
  304. // IsSameSection
  305. //
  306. // Returns if the section is the same of not
  307. //
  308. // Parameters
  309. // szSectionName - [in] The name of the Section (ie. TestSection)
  310. // szLines - [in] The line in the file (ie. [TheSection])
  311. //
  312. // Return Values:
  313. // TRUE - The same
  314. // FALSE - Not the same
  315. //
  316. BOOL
  317. CIniFile::IsSameSection(LPTSTR szSectionName, LPTSTR szLine)
  318. {
  319. LPTSTR szSectionCurrent;
  320. LPTSTR szLineCurrent;
  321. if ( szLine[0] != '[' )
  322. {
  323. // If the first character is not a '[', then
  324. // it is not een a section
  325. return FALSE;
  326. }
  327. szSectionCurrent = szSectionName;
  328. szLineCurrent = szLine + 1; // Skip preceding '['
  329. while ( ( towlower( *szSectionCurrent ) == towlower( *szLineCurrent ) ) &&
  330. ( *szSectionCurrent != '\0' )
  331. )
  332. {
  333. szSectionCurrent++;
  334. szLineCurrent++;
  335. }
  336. if ( ( *szSectionCurrent == '\0' ) &&
  337. ( *szLineCurrent == ']' ) &&
  338. ( *(szLineCurrent + 1) == '\0' )
  339. )
  340. {
  341. // They match
  342. return TRUE;
  343. }
  344. return FALSE;
  345. }
  346. // function: IsSameItem
  347. //
  348. // Is the Item Passed in, and the line, the same?
  349. // Since items have nothing else on the line, this should
  350. // be a simple _tcsicmp
  351. //
  352. // Parameters:
  353. // szItemName - [in] The Item Name
  354. // szLine - [in] The Line that is passed in
  355. //
  356. BOOL
  357. CIniFile::IsSameItem(LPTSTR szItemName, LPTSTR szLine)
  358. {
  359. return _tcsicmp( szItemName, szLine) == 0;
  360. }
  361. // function: IsSameSetting
  362. //
  363. // Is the setting that is passed in, the same on
  364. // that is on this specific line
  365. //
  366. // Parameters:
  367. // szSettingName - [in] The Name of the setting (ie. MaxPath)
  368. // szLine - [in] The Line to comapre (ie. MaxPath=30)
  369. //
  370. // Return Values:
  371. // TRUE == same
  372. // FALSE == no same
  373. BOOL
  374. CIniFile::IsSameSetting(LPTSTR szSettingName, LPTSTR szLine)
  375. {
  376. LPTSTR szSettingCurrent;
  377. LPTSTR szLineCurrent;
  378. szSettingCurrent = szSettingName;
  379. szLineCurrent = szLine;
  380. while ( ( towlower( *szSettingCurrent ) == towlower( *szLineCurrent ) ) &&
  381. ( *szSettingCurrent != '\0' )
  382. )
  383. {
  384. szSettingCurrent++;
  385. szLineCurrent++;
  386. }
  387. if ( ( *szSettingCurrent == '\0' ) &&
  388. ( *szLineCurrent == '=' )
  389. )
  390. {
  391. // They match
  392. return TRUE;
  393. }
  394. return FALSE;
  395. }
  396. // DoesSectionExist
  397. //
  398. // Does the specified section exist?
  399. //
  400. BOOL
  401. CIniFile::DoesSectionExist(LPTSTR szSectionName)
  402. {
  403. DWORD dwLineNumber;
  404. return FindSectionNumber( szSectionName, &dwLineNumber );
  405. }
  406. // GetLine
  407. //
  408. // Return a pointer to a particular line number
  409. //
  410. CIniFileLine *
  411. CIniFile::GetLine(DWORD dwLineNumber)
  412. {
  413. return m_pIniLines[ dwLineNumber ];
  414. }
  415. // FindSection
  416. //
  417. // Find a specific section, and set the current pointer to
  418. // that section, then user FindNextLineInSection to parse
  419. // through that section
  420. //
  421. // Parameters
  422. // szSectionName - [in] The Name of the Section
  423. //
  424. BOOL
  425. CIniFile::FindSection( LPTSTR szSectionName )
  426. {
  427. if ( !FindSectionNumber( szSectionName, &m_dwCurrentLine ) )
  428. {
  429. // Could not find section
  430. return FALSE;
  431. }
  432. return TRUE;
  433. }
  434. // FindNextLineInSection
  435. //
  436. // Find the next Line in the section, if any are left
  437. //
  438. BOOL
  439. CIniFile::FindNextLineInSection( CIniFileLine **ppCurrentLine )
  440. {
  441. // Increment Line number
  442. m_dwCurrentLine++;
  443. if ( ( m_dwCurrentLine >= m_dwLinesAllocated ) ||
  444. ( GetLine( m_dwCurrentLine ) == NULL ) )
  445. {
  446. // We have either gone past the last line,
  447. // or it does not exist, so return FALSE
  448. return FALSE;
  449. }
  450. if ( GetLine( m_dwCurrentLine )->QueryStrippedLine()[0] == '[' )
  451. {
  452. // We have hit the begining of another section, so exit
  453. return FALSE;
  454. }
  455. *ppCurrentLine = GetLine( m_dwCurrentLine );
  456. return TRUE;
  457. }
  458. // DoesItemInSectionExist
  459. //
  460. // Does an Item in a particular section exist
  461. //
  462. // Parameters:
  463. // szSectionName - [in] The section to search
  464. // szItem - [in] The Item to find
  465. //
  466. // Return Values:
  467. // TRUE - It exists
  468. // FALSE - It does not exist
  469. //
  470. BOOL
  471. CIniFile::DoesItemInSectionExist(LPTSTR szSectionName, LPTSTR szItem)
  472. {
  473. CIniFileLine *pCurrentLine;
  474. if ( !FindSection( szSectionName ) )
  475. {
  476. // Could not find section, forget about the item
  477. return FALSE;
  478. }
  479. while ( FindNextLineInSection( &pCurrentLine ) )
  480. {
  481. if ( IsSameItem( szItem, pCurrentLine->QueryStrippedLine() ) )
  482. {
  483. // We have found the item
  484. return TRUE;
  485. }
  486. }
  487. return FALSE;
  488. }
  489. // DoesSettingInSectionExist
  490. //
  491. // Does an Setting in a particular section exist
  492. //
  493. // Parameters:
  494. // szSectionName - [in] The section to search
  495. // szSetting - [in] The Setting to find
  496. //
  497. // Return Values:
  498. // TRUE - It exists
  499. // FALSE - It does not exist
  500. //
  501. BOOL
  502. CIniFile::DoesSettingInSectionExist(LPTSTR szSectionName, LPTSTR szSetting)
  503. {
  504. CIniFileLine *pCurrentLine;
  505. if ( !FindSection( szSectionName ) )
  506. {
  507. // Could not find section, forget about the item
  508. return FALSE;
  509. }
  510. while ( FindNextLineInSection( &pCurrentLine ) )
  511. {
  512. if ( IsSameSetting( szSetting, pCurrentLine->QueryStrippedLine() ) )
  513. {
  514. // We have found the item
  515. return TRUE;
  516. }
  517. }
  518. return FALSE;
  519. }
  520. // GetNumberofLines
  521. //
  522. // Return the number of lines in the ini file
  523. //
  524. DWORD
  525. CIniFile::GetNumberofLines()
  526. {
  527. return m_dwNumberofLines;
  528. }
  529. // AddSection
  530. //
  531. // Add a Section to the File
  532. // (it inserts at end)
  533. //
  534. BOOL
  535. CIniFile::AddSection(LPTSTR szNewSectionName)
  536. {
  537. TCHAR szBuffer[MAX_PATH];
  538. CIniFileLine *pNewLine;
  539. if ( _tcslen( szNewSectionName ) >= ( MAX_PATH - 3 ) ) // Leave room for [,],\0
  540. {
  541. return FALSE;
  542. }
  543. // Add a new line at the end
  544. pNewLine = AddLine( GetNumberofLines() );
  545. if ( !pNewLine )
  546. {
  547. // Failed to Add
  548. return FALSE;
  549. }
  550. _tcscpy(szBuffer, L"[");
  551. _tcscat(szBuffer, szNewSectionName);
  552. _tcscat(szBuffer, L"]");
  553. if ( !pNewLine->CopyLine( szBuffer ) )
  554. {
  555. // Failed to copy data
  556. return FALSE;
  557. }
  558. // It has now been added, and updated with text
  559. return TRUE;
  560. }
  561. // SetStartforSectionIterator
  562. //
  563. // Set the current line for the Section Iterator,
  564. // this is so that you can start at anyline in the file you want
  565. // and iterate through that section
  566. //
  567. BOOL
  568. CIniFile::SetStartforSectionIterator( DWORD dwIndex )
  569. {
  570. if ( dwIndex >= m_dwNumberofLines )
  571. {
  572. return FALSE;
  573. }
  574. m_dwCurrentLine = dwIndex;
  575. return TRUE;
  576. }
  577. // GetCurrentSectionIteratorLine
  578. //
  579. // Get current line that the iterator has
  580. //
  581. DWORD
  582. CIniFile::GetCurrentSectionIteratorLine()
  583. {
  584. return m_dwCurrentLine;
  585. }
  586. // AddLinesToSection
  587. //
  588. // Add Lines to a specific section
  589. // This is what we use to update the ini files with the new options
  590. //
  591. // Note: This will not create the section for you, so do that before
  592. // you call this function
  593. // Note2: If this function fails, it is possible to have part of your
  594. // data in the file, so in essence, it is probably corrupted
  595. //
  596. // Parameters:
  597. // szSectionName - The name of the section to update
  598. // dwNumLines - The number of Lines in **szLines
  599. // szLines - An array of lines to add (Null terminated)
  600. // (no \r\n's are needed)
  601. //
  602. // Return Values:
  603. // TRUE - Added Successfully
  604. // FALSE - Failed to Add
  605. //
  606. BOOL
  607. CIniFile::AddLinesToSection(LPTSTR szSectionName, DWORD dwNumLines, LPTSTR *szLines)
  608. {
  609. CIniFileLine *pCurrentLine;
  610. DWORD dwCurrentLineinFile;
  611. DWORD dwCurrentLineinInput;
  612. if ( !FindSection( szSectionName ) )
  613. {
  614. // Failed to find section, bail now
  615. return FALSE;
  616. }
  617. while ( FindNextLineInSection( &pCurrentLine ) )
  618. {
  619. // Do nothing, just iterate through the section
  620. }
  621. dwCurrentLineinFile = GetCurrentSectionIteratorLine();
  622. for ( dwCurrentLineinInput = 0;
  623. dwCurrentLineinInput < dwNumLines;
  624. dwCurrentLineinInput++, dwCurrentLineinFile++ )
  625. {
  626. pCurrentLine = AddLine( dwCurrentLineinFile );
  627. if ( !pCurrentLine ||
  628. !pCurrentLine->CopyLine( szLines[ dwCurrentLineinInput ] )
  629. )
  630. {
  631. // We failed to add the line, or to add contents to
  632. // it, so we must bail
  633. return FALSE;
  634. }
  635. }
  636. return TRUE;
  637. }
  638. // LoadFile
  639. //
  640. // Load the ini file from the OS
  641. //
  642. BOOL
  643. CIniFile::LoadFile( LPTSTR szFileName )
  644. {
  645. HANDLE hFile;
  646. BOOL bRet;
  647. hFile = CreateFile( szFileName,
  648. GENERIC_READ, // Read
  649. 0, // No sharing
  650. NULL,
  651. OPEN_EXISTING,
  652. FILE_ATTRIBUTE_NORMAL,
  653. NULL );
  654. if ( hFile == INVALID_HANDLE_VALUE )
  655. {
  656. // Could not open file, Doh!
  657. return FALSE;
  658. }
  659. bRet = ReadFileContents( hFile );
  660. // Close File
  661. CloseHandle( hFile );
  662. return bRet;
  663. }
  664. // ReadFileContents
  665. //
  666. // Read all of the FileContents into memory
  667. //
  668. BOOL
  669. CIniFile::ReadFileContents( HANDLE hFile )
  670. {
  671. BYTE pBuffer[INIFILE_READ_CHUNK_SIZE + 2]; // For \0\0
  672. DWORD dwCurrentLocation = 0;
  673. DWORD dwBytesRead;
  674. BOOL bRet = TRUE;
  675. m_bUnicodeFile = FALSE;
  676. if ( ReadFile( hFile, pBuffer, 2, &dwCurrentLocation, NULL ) &&
  677. ( dwCurrentLocation == 2 ) &&
  678. ( pBuffer[0] == 0xFF ) &&
  679. ( pBuffer[1] == 0xFE )
  680. )
  681. {
  682. // Since there is the 0xFF, 0xFE we will assume it is unicode
  683. m_bUnicodeFile = TRUE;
  684. // Reset Pointer, so we ignore the FFFE.
  685. dwCurrentLocation = 0;
  686. }
  687. while ( ReadFile( hFile,
  688. pBuffer + dwCurrentLocation,
  689. INIFILE_READ_CHUNK_SIZE - dwCurrentLocation,
  690. &dwBytesRead,
  691. NULL ) &&
  692. ( dwBytesRead != 0 ) )
  693. {
  694. dwCurrentLocation += dwBytesRead;
  695. pBuffer[dwCurrentLocation] = '\0';
  696. pBuffer[dwCurrentLocation + 1 ] = '\0';
  697. if ( !LoadChunk( pBuffer, &dwCurrentLocation, FALSE ) )
  698. {
  699. bRet = FALSE;
  700. break;
  701. }
  702. }
  703. if ( bRet )
  704. {
  705. if ( !LoadChunk( pBuffer, &dwCurrentLocation, TRUE) )
  706. {
  707. bRet = FALSE;
  708. }
  709. }
  710. return bRet;
  711. }
  712. // LoadChunk
  713. //
  714. // Load the Chunk of Data from this buffer, into the ini
  715. // class lines
  716. //
  717. // Parameters
  718. // pData - [in/out] Buffer of Bytes to be loaded
  719. // pdwCurrentLocation - [in/out] Location of end of buffer
  720. // bIsLastChunck - [in] Flag to tells us if this is the last chunk
  721. BOOL
  722. CIniFile::LoadChunk( LPBYTE pData, DWORD *pdwCurrentLocation, BOOL bIsLastChunk )
  723. {
  724. LPBYTE szEndofLine;
  725. LPBYTE szNextLine;
  726. CIniFileLine *pCurrentLine;
  727. while ( *pdwCurrentLocation > 0 )
  728. {
  729. szEndofLine = m_bUnicodeFile ? (LPBYTE) wcsstr( (LPWSTR) pData, L"\r" ) :
  730. (LPBYTE) strstr( (LPSTR) pData, "\r" );
  731. if ( szEndofLine == NULL )
  732. {
  733. szEndofLine = m_bUnicodeFile ? (LPBYTE) wcsstr( (LPWSTR) pData, L"\n" ) :
  734. (LPBYTE) strstr( (LPSTR) pData, "\n" );
  735. // Move to next line (this is \n, so it is only 1 char away)
  736. szNextLine = szEndofLine + ( m_bUnicodeFile ? 2 : 1 );
  737. }
  738. else
  739. {
  740. // \r was found
  741. if ( m_bUnicodeFile )
  742. {
  743. // Jump past \r, or \r\n
  744. szNextLine = szEndofLine + ( *( (LPWSTR) szEndofLine + 1 ) == '\n' ?
  745. 4 : 2 );
  746. }
  747. else
  748. {
  749. // Jump past \r, or \r\n
  750. szNextLine = szEndofLine + ( *( (LPSTR) szEndofLine + 1) == '\n' ?
  751. 2 : 1 );
  752. }
  753. if ( !bIsLastChunk &&
  754. ( m_bUnicodeFile ? *( (LPWSTR) szEndofLine + 1) == '\0' :
  755. *( (LPSTR) szEndofLine + 1) == '\0' ) )
  756. {
  757. // This is a \r with a \0 imediately after it, this might mean that we have
  758. // not read enough, so lets return and lets read another chunk
  759. return TRUE;
  760. }
  761. }
  762. if ( !szEndofLine )
  763. {
  764. if ( bIsLastChunk )
  765. {
  766. szEndofLine = pData + *pdwCurrentLocation;
  767. szNextLine = szEndofLine;
  768. }
  769. else
  770. {
  771. // Can not find another line, so exit
  772. return TRUE;
  773. }
  774. }
  775. // Null Terminate Here
  776. if ( m_bUnicodeFile )
  777. {
  778. wcscpy( (LPWSTR) szEndofLine, L"\0" );
  779. }
  780. else
  781. {
  782. strcpy( (LPSTR) szEndofLine, "\0" );
  783. }
  784. if ( ( ( pCurrentLine = AddLine( GetNumberofLines() ) ) == NULL ) ||
  785. !( m_bUnicodeFile ? pCurrentLine->CopyLine( (LPWSTR) pData ) :
  786. pCurrentLine->CopyLine( (LPSTR) pData ) )
  787. )
  788. {
  789. // Error Adding Line
  790. return FALSE;
  791. }
  792. // Remove that part of the line
  793. memmove( pData, szNextLine, *pdwCurrentLocation - (szNextLine - pData) + 2 ); // +2 for \0\0
  794. *pdwCurrentLocation -= (DWORD) (szNextLine - pData);
  795. }
  796. return TRUE;
  797. }
  798. // SaveFile
  799. //
  800. // Save the ini file to disk
  801. //
  802. BOOL
  803. CIniFile::SaveFile( LPTSTR szFileName )
  804. {
  805. HANDLE hFile;
  806. BOOL bRet;
  807. hFile = CreateFile( szFileName,
  808. GENERIC_WRITE, // Read
  809. 0, // No sharing
  810. NULL,
  811. CREATE_ALWAYS,
  812. FILE_ATTRIBUTE_NORMAL,
  813. NULL );
  814. if ( hFile == INVALID_HANDLE_VALUE )
  815. {
  816. // Could not create the file
  817. return FALSE;
  818. }
  819. bRet = WriteFileContents( hFile );
  820. // Close File
  821. CloseHandle( hFile );
  822. return bRet;
  823. }
  824. // WriteFileContents
  825. //
  826. // Write the ini contents to the file
  827. //
  828. BOOL
  829. CIniFile::WriteFileContents( HANDLE hFile )
  830. {
  831. DWORD dwCurrent;
  832. CHAR szLine[MAX_PATH];
  833. DWORD dwBytesWritten;
  834. if ( m_bUnicodeFile )
  835. {
  836. // If this file is unicode, lets write the prefix 0xFF,0xFE right now
  837. BYTE pData[2] = { 0xFF, 0xFE };
  838. if ( !WriteFile( hFile, pData, sizeof( pData ),
  839. &dwBytesWritten, NULL ) )
  840. {
  841. // Failed to write to file
  842. return FALSE;
  843. }
  844. }
  845. for ( dwCurrent = 0; dwCurrent < GetNumberofLines(); dwCurrent++ )
  846. {
  847. if ( !m_bUnicodeFile )
  848. {
  849. // If not unicode, then we need to translate back to Ansi
  850. if ( !WideCharToMultiByte( CP_ACP, //CP_THREAD_ACP doesn't work on NT4
  851. 0,
  852. GetLine( dwCurrent )->QueryLine(),
  853. -1, // Null terminated
  854. szLine,
  855. MAX_PATH,
  856. NULL,
  857. NULL) )
  858. {
  859. // Line could not be converted, so lets fail
  860. return FALSE;
  861. }
  862. }
  863. // Write line to file
  864. if ( !WriteFile( hFile,
  865. m_bUnicodeFile ? (LPBYTE) GetLine( dwCurrent )->QueryLine():
  866. (LPBYTE) szLine,
  867. m_bUnicodeFile ? (DWORD) wcslen( GetLine( dwCurrent )->QueryLine() ) * sizeof( WCHAR ):
  868. (DWORD) strlen( szLine ) * sizeof( CHAR),
  869. &dwBytesWritten,
  870. NULL ) )
  871. {
  872. // Failed to write Line
  873. return FALSE;
  874. }
  875. // Line Terminators
  876. if ( !WriteFile( hFile,
  877. m_bUnicodeFile ? (LPBYTE) L"\r\n":
  878. (LPBYTE) "\r\n",
  879. m_bUnicodeFile ? (DWORD) wcslen( L"\r\n" ) * sizeof( WCHAR ) :
  880. (DWORD) strlen( "\r\n") * sizeof( CHAR) ,
  881. &dwBytesWritten,
  882. NULL ) )
  883. {
  884. // Failed to write Line
  885. return FALSE;
  886. }
  887. } // for
  888. return TRUE;
  889. }