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.

800 lines
19 KiB

  1. #include "headers.hxx"
  2. #include "CSVDSReader.hpp"
  3. #include "resourceDspecup.h"
  4. #include "constants.hpp"
  5. #include "global.hpp"
  6. #include <stdio.h>
  7. #include <crtdbg.h>
  8. CSVDSReader::CSVDSReader():file(INVALID_HANDLE_VALUE)
  9. {
  10. canCallGetNext=false;
  11. }
  12. HRESULT
  13. CSVDSReader::read(
  14. const wchar_t *fileName_,
  15. const long *locales)
  16. {
  17. LOG_FUNCTION(CSVDSReader::read);
  18. localeOffsets.clear();
  19. propertyPositions.clear();
  20. fileName=fileName_;
  21. HRESULT hr=S_OK;
  22. do
  23. {
  24. // fill localeOffsets and property positions
  25. if(!FS::FileExists(fileName))
  26. {
  27. error = String::format(IDS_COULD_NOT_FIND_FILE,
  28. fileName.c_str());
  29. hr=E_FAIL;
  30. break;
  31. }
  32. hr=FS::CreateFile(fileName,file,GENERIC_READ,FILE_SHARE_READ);
  33. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  34. do
  35. {
  36. AnsiString unicodeId;
  37. hr=FS::Read(file, 2, unicodeId);
  38. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  39. if (unicodeId[0]!='\xFF' || unicodeId[1]!='\xFE')
  40. {
  41. error = String::format(IDS_INVALID_CSV_UNICODE_ID,
  42. fileName.c_str());
  43. hr=E_FAIL;
  44. break;
  45. }
  46. hr=parseProperties();
  47. BREAK_ON_FAILED_HRESULT(hr);
  48. hr=parseLocales(locales);
  49. BREAK_ON_FAILED_HRESULT(hr);
  50. } while(0);
  51. if (FAILED(hr))
  52. {
  53. CloseHandle(file);
  54. file=INVALID_HANDLE_VALUE;
  55. break;
  56. }
  57. } while(0);
  58. LOG_HRESULT(hr);
  59. return hr;
  60. }
  61. // Decode first line of the file building propertyPositions
  62. // Expects file to be in the first valid file character (after
  63. // the unicode identifier)
  64. HRESULT CSVDSReader::parseProperties()
  65. {
  66. LOG_FUNCTION(CSVDSReader::parseProperties);
  67. ASSERT(file!=INVALID_HANDLE_VALUE);
  68. HRESULT hr=S_OK;
  69. do
  70. {
  71. String csvLine;
  72. hr=ReadLine(file,csvLine);
  73. // We are breaking for EOF_HRESULT too, since
  74. // there should be more lines in the csv
  75. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  76. hr = WinGetVLFilePointer(file, &startPosition);
  77. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  78. StringList tokens;
  79. size_t token_count = csvLine.tokenize(back_inserter(tokens),L",");
  80. ASSERT(token_count == tokens.size());
  81. StringList::iterator begin=tokens.begin();
  82. StringList::iterator end=tokens.end();
  83. long count=0;
  84. while( begin != end )
  85. {
  86. propertyPositions[*begin]=count++;
  87. begin++;
  88. }
  89. } while(0);
  90. LOG_HRESULT(hr);
  91. return hr;
  92. }
  93. // Fill localeOffsets with the starting position of all locales
  94. // Expects file to be in the second line
  95. // Expects the locale order to be the same as the one
  96. // found in the file
  97. HRESULT CSVDSReader::parseLocales(const long *locales)
  98. {
  99. LOG_FUNCTION(CSVDSReader::parseLocales);
  100. ASSERT(file!=INVALID_HANDLE_VALUE);
  101. HRESULT hr=S_OK;
  102. do
  103. {
  104. long count=0;
  105. bool flagEof=false;
  106. while(locales[count]!=0 && !flagEof)
  107. {
  108. long locale=locales[count];
  109. String localeStr=String::format(L"CN=%1!3x!,", locale);
  110. LARGE_INTEGER pos;
  111. hr = WinGetVLFilePointer(file, &pos);
  112. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  113. String csvLine;
  114. hr=ReadLine(file,csvLine);
  115. if(hr==EOF_HRESULT)
  116. {
  117. flagEof=true;
  118. hr=S_OK;
  119. }
  120. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  121. if(csvLine.length() > localeStr.length())
  122. {
  123. csvLine.erase(localeStr.size()+1);
  124. if( localeStr.icompare(&csvLine[1])==0 )
  125. {
  126. localeOffsets[locale]=pos;
  127. count++;
  128. }
  129. }
  130. }
  131. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  132. if(locales[count]!=0)
  133. {
  134. error=String::format(IDS_MISSING_LOCALES,fileName.c_str());
  135. hr=E_FAIL;
  136. break;
  137. }
  138. } while(0);
  139. LOG_HRESULT(hr);
  140. return hr;
  141. }
  142. // get the csv value starting with inValue to outValue
  143. // returns S_FALSE if no value is found
  144. HRESULT
  145. CSVDSReader::getCsvValue
  146. (
  147. const long locale,
  148. const wchar_t *object,
  149. const wchar_t *property,
  150. const String &inValue,
  151. String &outValue
  152. ) const
  153. {
  154. LOG_FUNCTION(CSVDSReader::getCsvValue);
  155. HRESULT hr=S_OK;
  156. outValue.erase();
  157. bool found=false;
  158. do
  159. {
  160. StringList values;
  161. hr=getCsvValues(locale,object,property,values);
  162. BREAK_ON_FAILED_HRESULT(hr);
  163. StringList::const_iterator begin,end;
  164. begin=values.begin();
  165. end=values.end();
  166. while(begin!=end && !found)
  167. {
  168. if (_wcsnicmp(begin->c_str(),inValue.c_str(),inValue.length())==0)
  169. {
  170. outValue=*begin;
  171. found=true;
  172. }
  173. begin++;
  174. }
  175. }
  176. while(0);
  177. if (!found)
  178. {
  179. hr=S_FALSE;
  180. }
  181. LOG_HRESULT(hr);
  182. return hr;
  183. }
  184. // return all values for a property in a given locale/object
  185. HRESULT
  186. CSVDSReader::getCsvValues
  187. (
  188. const long locale,
  189. const wchar_t *object,
  190. const wchar_t *property,
  191. StringList &values
  192. ) const
  193. {
  194. LOG_FUNCTION(CSVDSReader::getCsvValues);
  195. // seek on locale
  196. // read sequentially until find object
  197. // call getPropertyValues on the line found to retrieve values
  198. ASSERT(file!=INVALID_HANDLE_VALUE);
  199. HRESULT hr=S_OK;
  200. do
  201. {
  202. String propertyString(property);
  203. mapOfPositions::const_iterator propertyPos =
  204. propertyPositions.find(propertyString);
  205. if (propertyPos==propertyPositions.end())
  206. {
  207. error=String::format(IDS_PROPERTY_NOT_FOUND_IN_CSV,
  208. property,
  209. fileName.c_str());
  210. hr=E_FAIL;
  211. break;
  212. }
  213. String csvLine;
  214. hr=getObjectLine(locale,object,csvLine);
  215. BREAK_ON_FAILED_HRESULT(hr);
  216. mapOfProperties allValues;
  217. hr=getPropertyValues(csvLine,allValues);
  218. BREAK_ON_FAILED_HRESULT(hr);
  219. values=allValues[property];
  220. } while(0);
  221. LOG_HRESULT(hr);
  222. return hr;
  223. }
  224. // starting from the locale offset
  225. // finds the object and returns its line in csvLine
  226. HRESULT
  227. CSVDSReader::getObjectLine(
  228. const long locale,
  229. const wchar_t *object,
  230. String &csvLine
  231. ) const
  232. {
  233. LOG_FUNCTION(CSVDSReader::getObjectLine);
  234. ASSERT(file!=INVALID_HANDLE_VALUE);
  235. HRESULT hr=S_OK;
  236. do
  237. {
  238. mapOfOffsets::const_iterator offset =
  239. localeOffsets.find(locale);
  240. // locale must have been passed to read
  241. ASSERT(offset!=localeOffsets.end());
  242. String objectStr;
  243. objectStr=String::format(L"CN=%1,CN=%2!3x!",object,locale);
  244. hr=Win::SetFilePointerEx(file,offset->second,0,FILE_BEGIN);
  245. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  246. // first line is the container properties and since we want the
  247. // properties of an object we will ignore it
  248. bool flagEof=false;
  249. hr=ReadLine(file,csvLine);
  250. if(hr==EOF_HRESULT)
  251. {
  252. flagEof=true;
  253. hr=S_OK;
  254. }
  255. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  256. bool found=false;
  257. while(!found && !flagEof)
  258. {
  259. hr=ReadLine(file,csvLine);
  260. if(hr==EOF_HRESULT)
  261. {
  262. flagEof=true;
  263. hr=S_OK;
  264. }
  265. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  266. if(csvLine.length() > objectStr.length())
  267. {
  268. String auxComp=csvLine.substr(1,objectStr.length());
  269. if( auxComp.icompare(objectStr)==0 )
  270. {
  271. found=true;
  272. }
  273. }
  274. }
  275. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  276. if(!found)
  277. {
  278. error = String::format(
  279. IDS_OBJECT_NOT_FOUND_IN_CSV,
  280. object,
  281. locale,
  282. fileName.c_str()
  283. );
  284. hr=E_FAIL;
  285. break;
  286. }
  287. } while(0);
  288. LOG_HRESULT(hr);
  289. return hr;
  290. }
  291. HRESULT CSVDSReader::writeHeader(HANDLE fileOut) const
  292. {
  293. LOG_FUNCTION(CSVDSReader::writeHeader);
  294. ASSERT(fileOut!=INVALID_HANDLE_VALUE);
  295. HRESULT hr=S_OK;
  296. do
  297. {
  298. char suId[3]={'\xFF','\xFE',0};
  299. //uId solves ambiguous Write
  300. AnsiString uId(suId);
  301. hr=FS::Write(fileOut,uId);
  302. BREAK_ON_FAILED_HRESULT(hr);
  303. // 2 to skip the unicode identifier
  304. LARGE_INTEGER pos;
  305. pos.QuadPart=2;
  306. hr=Win::SetFilePointerEx(file,pos,0,FILE_BEGIN);
  307. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  308. String csvLine;
  309. hr=ReadLine(file,csvLine);
  310. // We are breaking for EOF_HRESULT too, since
  311. // there should be more lines in the csv
  312. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  313. hr=FS::WriteLine(fileOut,csvLine);
  314. BREAK_ON_FAILED_HRESULT(hr);
  315. } while(0);
  316. LOG_HRESULT(hr);
  317. return hr;
  318. }
  319. HRESULT
  320. CSVDSReader::makeLocalesCsv
  321. (
  322. HANDLE fileOut,
  323. const long *locales
  324. ) const
  325. {
  326. LOG_FUNCTION(CSVDSReader::makeLocalesCsv);
  327. HRESULT hr=S_OK;
  328. ASSERT(file!=INVALID_HANDLE_VALUE);
  329. ASSERT(fileOut!=INVALID_HANDLE_VALUE);
  330. do
  331. {
  332. LARGE_INTEGER posStartOut;
  333. hr = WinGetVLFilePointer(fileOut, &posStartOut);
  334. BREAK_ON_FAILED_HRESULT(hr);
  335. if (posStartOut.QuadPart==0)
  336. {
  337. hr=writeHeader(fileOut);
  338. BREAK_ON_FAILED_HRESULT(hr);
  339. }
  340. long count=0;
  341. while(locales[count]!=0)
  342. {
  343. long locale=locales[count];
  344. mapOfOffsets::const_iterator offset;
  345. offset = localeOffsets.find(locale);
  346. // locale must have been passed to read
  347. ASSERT(offset!=localeOffsets.end());
  348. hr=Win::SetFilePointerEx(file,offset->second,0,FILE_BEGIN);
  349. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  350. String localeStr=String::format(L"CN=%1!3x!,", locale);
  351. bool flagEof=false;
  352. String csvLine;
  353. hr=ReadLine(file,csvLine);
  354. if(hr==EOF_HRESULT)
  355. {
  356. flagEof=true;
  357. hr=S_OK;
  358. }
  359. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  360. // We know that the first line matches even if it ends with EOF
  361. hr=FS::WriteLine(fileOut,csvLine);
  362. BREAK_ON_FAILED_HRESULT(hr);
  363. bool newContainer=false;
  364. while
  365. (
  366. !flagEof &&
  367. !newContainer
  368. )
  369. {
  370. hr=ReadLine(file,csvLine);
  371. if(hr==EOF_HRESULT)
  372. {
  373. flagEof=true;
  374. hr=S_OK;
  375. }
  376. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  377. // We will deal with the line even if it ends with EOF
  378. size_t posComma=csvLine.find(L",");
  379. if(posComma!=String::npos)
  380. {
  381. String csvLoc=csvLine.substr(posComma+1,localeStr.length());
  382. if (csvLoc.icompare(localeStr) == 0)
  383. {
  384. hr=FS::WriteLine(fileOut,csvLine);
  385. BREAK_ON_FAILED_HRESULT(hr);
  386. }
  387. else
  388. {
  389. newContainer=true;
  390. }
  391. }
  392. else
  393. {
  394. newContainer=true;
  395. }
  396. };
  397. count++;
  398. } // while(locales[count]!=0)
  399. BREAK_ON_FAILED_HRESULT(hr);
  400. } while(0);
  401. LOG_HRESULT(hr);
  402. return hr;
  403. }
  404. HRESULT
  405. CSVDSReader::makeObjectsCsv
  406. (
  407. HANDLE fileOut,
  408. const setOfObjects &objects
  409. ) const
  410. {
  411. LOG_FUNCTION(CSVDSReader::makeObjectsCsv);
  412. HRESULT hr=S_OK;
  413. ASSERT(file!=INVALID_HANDLE_VALUE);
  414. ASSERT(fileOut!=INVALID_HANDLE_VALUE);
  415. do
  416. {
  417. LARGE_INTEGER posStartOut;
  418. hr = WinGetVLFilePointer(fileOut, &posStartOut);
  419. BREAK_ON_FAILED_HRESULT(hr);
  420. if (posStartOut.QuadPart==0)
  421. {
  422. hr=writeHeader(fileOut);
  423. BREAK_ON_FAILED_HRESULT(hr);
  424. }
  425. setOfObjects::const_iterator begin,end;
  426. begin=objects.begin();
  427. end=objects.end();
  428. while(begin!=end)
  429. {
  430. String csvLine;
  431. hr=getObjectLine( begin->second,
  432. begin->first.c_str(),
  433. csvLine);
  434. BREAK_ON_FAILED_HRESULT(hr);
  435. hr=FS::WriteLine(fileOut,csvLine);
  436. BREAK_ON_FAILED_HRESULT(hr);
  437. begin++;
  438. }
  439. BREAK_ON_FAILED_HRESULT(hr);
  440. } while(0);
  441. LOG_HRESULT(hr);
  442. return hr;
  443. }
  444. // auxiliar for getPropertyValues.
  445. // It is out of the class because it can be used elesewhere
  446. String unquote(const String &src)
  447. {
  448. String ret=src;
  449. ret.strip(String::BOTH);
  450. size_t len=ret.size();
  451. if(len>=2 && ret[0]==L'"' && ret[len-1]==L'"')
  452. {
  453. ret=ret.substr(1,len-2);
  454. }
  455. return ret;
  456. }
  457. // extract from line the value of all properties
  458. HRESULT
  459. CSVDSReader::getPropertyValues
  460. (
  461. const String &line,
  462. mapOfProperties &properties
  463. ) const
  464. {
  465. LOG_FUNCTION(CSVDSReader::getPropertyValues);
  466. HRESULT hr=S_OK;
  467. ASSERT(file!=INVALID_HANDLE_VALUE);
  468. ASSERT(!line.empty());
  469. do
  470. {
  471. StringVector objValues;
  472. const wchar_t *csr=line.c_str();
  473. const wchar_t *start=csr;
  474. while(*csr!=0)
  475. {
  476. if (*csr==L',')
  477. {
  478. objValues.push_back(unquote(String(start,csr)));
  479. csr++;
  480. start=csr;
  481. }
  482. else if (*csr==L'"')
  483. {
  484. // We are only advancing up to after the next quote
  485. csr++;
  486. while(*csr!=L'"' && *csr!=0) csr++;
  487. if (*csr==0)
  488. {
  489. error=String::format(IDS_QUOTES_NOT_CLOSED,fileName.c_str());
  490. hr=E_FAIL;
  491. break;
  492. }
  493. csr++;
  494. }
  495. else
  496. {
  497. csr++;
  498. }
  499. }
  500. BREAK_ON_FAILED_HRESULT(hr);
  501. objValues.push_back(unquote(String(start,csr)));
  502. if (objValues.size()!=propertyPositions.size())
  503. {
  504. error=String::format
  505. (
  506. IDS_WRONG_NUMBER_OF_PROPERTIES,
  507. objValues.size(),
  508. propertyPositions.size(),
  509. line.c_str(),
  510. fileName.c_str()
  511. );;
  512. hr=E_FAIL;
  513. break;
  514. }
  515. properties.clear();
  516. mapOfPositions::iterator current=propertyPositions.begin();
  517. mapOfPositions::iterator end=propertyPositions.end();
  518. while(current!=end)
  519. {
  520. String &propValue=objValues[current->second];
  521. StringList values;
  522. if (!propValue.empty())
  523. {
  524. size_t cnt = propValue.tokenize(back_inserter(values),L";");
  525. ASSERT(cnt == values.size());
  526. }
  527. properties[current->first]=values;
  528. current++;
  529. }
  530. BREAK_ON_FAILED_HRESULT(hr);
  531. } while(0);
  532. LOG_HRESULT(hr);
  533. return hr;
  534. }
  535. // Sets the file pointer at the begining so that the next call to
  536. // getNextObject will retrieve the first object.
  537. // I did not take the usual getFirstObject approach, because
  538. // I want to deal want to do something like:
  539. // do
  540. // {
  541. // hr=getNextObject(loc,obj,prop)
  542. // BREAK_ON_FAILED_HRESULT(hr);
  543. // if(hr==S_FALSE) flagEof=true;
  544. // if (loc==0) continue; // line is empty
  545. // // deal with line here
  546. // } while(!flagEOF)
  547. HRESULT
  548. CSVDSReader::initializeGetNext() const
  549. {
  550. LOG_FUNCTION(CSVDSReader::initializeGetNext);
  551. HRESULT hr=S_OK;
  552. ASSERT(file!=INVALID_HANDLE_VALUE);
  553. do
  554. {
  555. hr=Win::SetFilePointerEx(file,startPosition,0,FILE_BEGIN);
  556. BREAK_ON_FAILED_HRESULT(hr);
  557. canCallGetNext=true;
  558. } while(0);
  559. LOG_HRESULT(hr);
  560. return hr;
  561. }
  562. // Get first object in the csv file returning it's name, locale
  563. // and values for the properties in properties
  564. // Returns S_FALSE for no more objects
  565. HRESULT
  566. CSVDSReader::getNextObject
  567. (
  568. long &locale,
  569. String &object,
  570. mapOfProperties &properties
  571. ) const
  572. {
  573. LOG_FUNCTION(CSVDSReader::getNextObject);
  574. HRESULT hr=S_OK;
  575. ASSERT(file!=INVALID_HANDLE_VALUE);
  576. ASSERT(canCallGetNext);
  577. locale=0;
  578. object.erase();
  579. bool flagEOF=false;
  580. do
  581. {
  582. String csvLine;
  583. hr=ReadLine(file,csvLine);
  584. if(hr==EOF_HRESULT)
  585. {
  586. flagEOF=true;
  587. if(csvLine.size()==0)
  588. {
  589. // we are done with success and EOF
  590. break;
  591. }
  592. hr=S_OK;
  593. }
  594. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  595. size_t pos1stComma=csvLine.find(L',');
  596. ASSERT(pos1stComma!=String::npos);
  597. ASSERT(pos1stComma > 4);
  598. object=csvLine.substr(4,pos1stComma - 4);
  599. size_t pos2ndComma = csvLine.find(L',',pos1stComma+1);
  600. ASSERT(pos2ndComma!=String::npos);
  601. ASSERT(pos2ndComma > pos1stComma + 4);
  602. String strLocale=csvLine.substr
  603. (
  604. pos1stComma + 4,
  605. pos2ndComma - pos1stComma - 4
  606. );
  607. if (strLocale.icompare(L"DisplaySpecifiers")==0)
  608. {
  609. // This is a container line.
  610. // The object that we got is actually the locale
  611. // and we have no object
  612. strLocale=object;
  613. object.erase();
  614. }
  615. String::ConvertResult result=strLocale.convert(locale,16);
  616. ASSERT(result==String::CONVERT_SUCCESSFUL);
  617. hr=getPropertyValues(csvLine,properties);
  618. } while(0);
  619. if(flagEOF)
  620. {
  621. hr=S_FALSE;
  622. canCallGetNext=false;
  623. }
  624. LOG_HRESULT(hr);
  625. return hr;
  626. }