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.

626 lines
14 KiB

  1. #include "headers.hxx"
  2. #include "CSVDSReader.hpp"
  3. #include "resource.h"
  4. #include "global.hpp"
  5. #include <stdio.h>
  6. #include <crtdbg.h>
  7. CSVDSReader::CSVDSReader():file(INVALID_HANDLE_VALUE)
  8. {
  9. }
  10. HRESULT
  11. CSVDSReader::read(
  12. const wchar_t *fileName_,
  13. const long *locales)
  14. {
  15. LOG_FUNCTION(CSVDSReader::read);
  16. localeOffsets.clear();
  17. propertyPositions.clear();
  18. fileName=fileName_;
  19. HRESULT hr=S_OK;
  20. do
  21. {
  22. // fill localeOffsets and property positions
  23. if(!FS::FileExists(fileName))
  24. {
  25. error=fileName;
  26. hr=Win32ToHresult(ERROR_FILE_NOT_FOUND);
  27. break;
  28. }
  29. hr=FS::CreateFile(fileName,file,GENERIC_READ,FILE_SHARE_READ);
  30. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  31. do
  32. {
  33. AnsiString unicodeId;
  34. hr=FS::Read(file, 2, unicodeId);
  35. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  36. if (unicodeId[0]!='\xFF' || unicodeId[1]!='\xFE')
  37. {
  38. error = String::format(IDS_INVALID_CSV_UNICODE_ID,
  39. fileName.c_str());
  40. hr=E_FAIL;
  41. break;
  42. }
  43. hr=parseProperties();
  44. BREAK_ON_FAILED_HRESULT(hr);
  45. hr=parseLocales(locales);
  46. BREAK_ON_FAILED_HRESULT(hr);
  47. } while(0);
  48. if (FAILED(hr))
  49. {
  50. CloseHandle(file);
  51. file=INVALID_HANDLE_VALUE;
  52. break;
  53. }
  54. } while(0);
  55. LOG_HRESULT(hr);
  56. return hr;
  57. }
  58. // Decode first line of the file building propertyPositions
  59. // Expects file to be in the first valid file character (after
  60. // the unicode identifier)
  61. HRESULT CSVDSReader::parseProperties()
  62. {
  63. LOG_FUNCTION(CSVDSReader::parseProperties);
  64. ASSERT(file!=INVALID_HANDLE_VALUE);
  65. HRESULT hr=S_OK;
  66. do
  67. {
  68. String csvLine;
  69. hr=ReadLine(file,csvLine);
  70. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  71. StringList tokens;
  72. size_t token_count = csvLine.tokenize(back_inserter(tokens),L",");
  73. ASSERT(token_count == tokens.size());
  74. StringList::iterator begin=tokens.begin();
  75. StringList::iterator end=tokens.end();
  76. long count=0;
  77. while( begin != end )
  78. {
  79. propertyPositions[begin->to_upper()]=count++;
  80. begin++;
  81. }
  82. } while(0);
  83. LOG_HRESULT(hr);
  84. return hr;
  85. }
  86. // Fill localeOffsets with the starting position of all locales
  87. // Expects file to be in the second line
  88. // Expects the locale order to be the same as the one
  89. // found in the file
  90. HRESULT CSVDSReader::parseLocales(const long *locales)
  91. {
  92. LOG_FUNCTION(CSVDSReader::parseLocales);
  93. ASSERT(file!=INVALID_HANDLE_VALUE);
  94. HRESULT hr=S_OK;
  95. do
  96. {
  97. long count=0;
  98. bool flagEof=false;
  99. while(locales[count]!=0 && !flagEof)
  100. {
  101. long locale=locales[count];
  102. String localeStr=String::format(L"CN=%1!3x!,", locale);
  103. LARGE_INTEGER pos;
  104. hr = WinGetVLFilePointer(file, &pos);
  105. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  106. String csvLine;
  107. hr=ReadLine(file,csvLine);
  108. if(hr==EOF_HRESULT)
  109. {
  110. flagEof=true;
  111. hr=S_OK;
  112. }
  113. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  114. if(csvLine.length() > localeStr.length())
  115. {
  116. csvLine.erase(localeStr.size()+1);
  117. if( localeStr.icompare(&csvLine[1])==0 )
  118. {
  119. localeOffsets[locale]=pos;
  120. count++;
  121. }
  122. }
  123. }
  124. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  125. if(locales[count]!=0)
  126. {
  127. error=String::format(IDS_MISSING_LOCALES,fileName.c_str());
  128. hr=E_FAIL;
  129. break;
  130. }
  131. } while(0);
  132. LOG_HRESULT(hr);
  133. return hr;
  134. }
  135. // get the csv value starting with value to XPValue
  136. // returns S_FALSE if no value is found
  137. HRESULT
  138. CSVDSReader::getCsvValue(
  139. const long locale,
  140. const wchar_t *object,
  141. const wchar_t *property,
  142. const String &value,
  143. String &XPValue) const
  144. {
  145. LOG_FUNCTION(CSVDSReader::getCsvValue);
  146. HRESULT hr=S_OK;
  147. XPValue.erase();
  148. bool found=false;
  149. do
  150. {
  151. StringList values;
  152. hr=getCsvValues(locale,object,property,values);
  153. BREAK_ON_FAILED_HRESULT(hr);
  154. StringList::const_iterator begin,end;
  155. begin=values.begin();
  156. end=values.end();
  157. while(begin!=end && !found)
  158. {
  159. if (_wcsnicmp(begin->c_str(),value.c_str(),value.length())==0)
  160. {
  161. XPValue=*begin;
  162. found=true;
  163. }
  164. begin++;
  165. }
  166. }
  167. while(0);
  168. if (!found)
  169. {
  170. hr=S_FALSE;
  171. }
  172. LOG_HRESULT(hr);
  173. return hr;
  174. }
  175. HRESULT
  176. CSVDSReader::getCsvValues(
  177. const long locale,
  178. const wchar_t *object,
  179. const wchar_t *property,
  180. StringList &values)
  181. const
  182. {
  183. LOG_FUNCTION(CSVDSReader::getCsvValues);
  184. // seek on locale
  185. // read sequentially until find object
  186. // call parseLine on the line found to retrieve values
  187. ASSERT(file!=INVALID_HANDLE_VALUE);
  188. HRESULT hr=S_OK;
  189. do
  190. {
  191. String propertyString(property);
  192. mapOfPositions::const_iterator propertyPos =
  193. propertyPositions.find(propertyString.to_upper());
  194. if (propertyPos==propertyPositions.end())
  195. {
  196. error=String::format(IDS_PROPERTY_NOT_FOUND_IN_CSV,
  197. property,
  198. fileName.c_str());
  199. hr=E_FAIL;
  200. break;
  201. }
  202. String csvLine;
  203. hr=getObjectLine(locale,object,csvLine);
  204. BREAK_ON_FAILED_HRESULT(hr);
  205. hr=parseLine(csvLine.c_str(),propertyPos->second,values);
  206. BREAK_ON_FAILED_HRESULT(hr);
  207. } while(0);
  208. LOG_HRESULT(hr);
  209. return hr;
  210. }
  211. // starting from the locale offset
  212. // finds the object and returns its line in csvLine
  213. HRESULT
  214. CSVDSReader::getObjectLine(
  215. const long locale,
  216. const wchar_t *object,
  217. String &csvLine
  218. ) const
  219. {
  220. LOG_FUNCTION(CSVDSReader::getObjectLine);
  221. ASSERT(file!=INVALID_HANDLE_VALUE);
  222. HRESULT hr=S_OK;
  223. do
  224. {
  225. mapOfOffsets::const_iterator offset =
  226. localeOffsets.find(locale);
  227. // locale must have been passed to read
  228. ASSERT(offset!=localeOffsets.end());
  229. String objectStr;
  230. objectStr=String::format(L"CN=%1,CN=%2!3x!",object,locale);
  231. hr=Win::SetFilePointerEx(file,offset->second,0,FILE_BEGIN);
  232. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  233. // first line is the container properties and since we want the
  234. // properties of an object we will ignore it
  235. bool flagEof=false;
  236. hr=ReadLine(file,csvLine);
  237. if(hr==EOF_HRESULT)
  238. {
  239. flagEof=true;
  240. hr=S_OK;
  241. }
  242. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  243. bool found=false;
  244. while(!found && !flagEof)
  245. {
  246. hr=ReadLine(file,csvLine);
  247. if(hr==EOF_HRESULT)
  248. {
  249. flagEof=true;
  250. hr=S_OK;
  251. }
  252. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  253. if(csvLine.length() > objectStr.length())
  254. {
  255. String auxComp=csvLine.substr(1,objectStr.length());
  256. if( auxComp.icompare(objectStr)==0 )
  257. {
  258. found=true;
  259. }
  260. }
  261. }
  262. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  263. if(!found)
  264. {
  265. error = String::format(
  266. IDS_OBJECT_NOT_FOUND_IN_CSV,
  267. object,
  268. locale,
  269. fileName.c_str()
  270. );
  271. hr=E_FAIL;
  272. break;
  273. }
  274. } while(0);
  275. LOG_HRESULT(hr);
  276. return hr;
  277. }
  278. //Get the values from the line at the position
  279. HRESULT
  280. CSVDSReader::parseLine(
  281. const wchar_t *line,
  282. const long position,
  283. StringList &values) const
  284. {
  285. LOG_FUNCTION(CSVDSReader::parseLine);
  286. ASSERT(line!=NULL);
  287. ASSERT(file!=INVALID_HANDLE_VALUE);
  288. HRESULT hr=S_OK;
  289. do
  290. {
  291. long pos=0;
  292. const wchar_t *csr=line;
  293. const wchar_t *sBegin=line;
  294. size_t count=0;
  295. while(pos<=position && csr!=NULL && *csr!=0)
  296. {
  297. while(*csr==L' ' || *csr==L'\t') csr++;
  298. // The goal of both 'if' and 'else' is setting sBegin and count
  299. // and leaving csr after the next comma
  300. if (*csr==L'"')
  301. {
  302. sBegin=csr+1;
  303. csr=wcschr(sBegin,L'"');
  304. if(csr==NULL)
  305. {
  306. error=String::format(IDS_QUOTES_NOT_CLOSED,fileName.c_str());
  307. break;
  308. }
  309. count=csr-sBegin;
  310. csr=wcschr(csr+1,L',');
  311. if(csr!=NULL) csr++;
  312. }
  313. else
  314. {
  315. sBegin=csr;
  316. csr=wcschr(sBegin,L',');
  317. if(csr!=NULL)
  318. {
  319. count=csr-sBegin;
  320. csr++;
  321. }
  322. else
  323. {
  324. count=wcslen(sBegin);
  325. }
  326. }
  327. pos++;
  328. }
  329. BREAK_ON_FAILED_HRESULT(hr);
  330. String sProp(sBegin,count);
  331. values.clear();
  332. size_t token_count = sProp.tokenize(back_inserter(values),L";");
  333. ASSERT(token_count == values.size());
  334. } while(0);
  335. LOG_HRESULT(hr);
  336. return hr;
  337. }
  338. HRESULT CSVDSReader::writeHeader(HANDLE fileOut) const
  339. {
  340. LOG_FUNCTION(CSVDSReader::writeHeader);
  341. HRESULT hr=S_OK;
  342. do
  343. {
  344. char suId[3]={'\xFF','\xFE',0};
  345. //uId solves ambiguous Write
  346. AnsiString uId(suId);
  347. hr=FS::Write(fileOut,uId);
  348. BREAK_ON_FAILED_HRESULT(hr);
  349. // 2 to skip the unicode identifier
  350. LARGE_INTEGER pos;
  351. pos.QuadPart=2;
  352. hr=Win::SetFilePointerEx(file,pos,0,FILE_BEGIN);
  353. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  354. String csvLine;
  355. hr=ReadLine(file,csvLine);
  356. // We are breaking for EOF_HRESULT too, since
  357. // there should be more lines in the csv
  358. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  359. hr=FS::WriteLine(fileOut,csvLine);
  360. BREAK_ON_FAILED_HRESULT(hr);
  361. } while(0);
  362. LOG_HRESULT(hr);
  363. return hr;
  364. }
  365. HRESULT
  366. CSVDSReader::makeLocalesCsv(
  367. HANDLE fileOut,
  368. const long *locales) const
  369. {
  370. LOG_FUNCTION(CSVDSReader::makeLocalesCsv);
  371. HRESULT hr=S_OK;
  372. ASSERT(file!=INVALID_HANDLE_VALUE);
  373. ASSERT(fileOut!=INVALID_HANDLE_VALUE);
  374. do
  375. {
  376. LARGE_INTEGER posStartOut;
  377. hr = WinGetVLFilePointer(fileOut, &posStartOut);
  378. BREAK_ON_FAILED_HRESULT(hr);
  379. if (posStartOut.QuadPart==0)
  380. {
  381. hr=writeHeader(fileOut);
  382. BREAK_ON_FAILED_HRESULT(hr);
  383. }
  384. long count=0;
  385. String csvLoc;
  386. while(locales[count]!=0)
  387. {
  388. long locale=locales[count];
  389. mapOfOffsets::const_iterator offset;
  390. offset = localeOffsets.find(locale);
  391. // locale must have been passed to read
  392. ASSERT(offset!=localeOffsets.end());
  393. hr=Win::SetFilePointerEx(file,offset->second,0,FILE_BEGIN);
  394. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  395. String localeStr=String::format(L"CN=%1!3x!,", locale);
  396. bool flagEof=false;
  397. String csvLine;
  398. hr=ReadLine(file,csvLine);
  399. if(hr==EOF_HRESULT)
  400. {
  401. flagEof=true;
  402. hr=S_OK;
  403. }
  404. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  405. do
  406. {
  407. hr=FS::WriteLine(fileOut,csvLine);
  408. BREAK_ON_FAILED_HRESULT(hr);
  409. hr=ReadLine(file,csvLine);
  410. if(hr==EOF_HRESULT)
  411. {
  412. flagEof=true;
  413. hr=S_OK;
  414. }
  415. BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
  416. size_t posComma=csvLine.find(L",");
  417. if(posComma!=string::npos)
  418. {
  419. csvLoc=csvLine.substr(posComma+1,localeStr.length());
  420. }
  421. else
  422. {
  423. csvLoc.erase();
  424. }
  425. } while(
  426. !flagEof &&
  427. !csvLoc.empty() &&
  428. ( csvLoc.icompare(localeStr) == 0 )
  429. );
  430. count++;
  431. } // while(locales[count]!=0)
  432. BREAK_ON_FAILED_HRESULT(hr);
  433. } while(0);
  434. LOG_HRESULT(hr);
  435. return hr;
  436. }
  437. HRESULT
  438. CSVDSReader::makeObjectsCsv(
  439. HANDLE fileOut,
  440. const setOfObjects &objects) const
  441. {
  442. LOG_FUNCTION(CSVDSReader::makeObjectsCsv);
  443. HRESULT hr=S_OK;
  444. ASSERT(file!=INVALID_HANDLE_VALUE);
  445. do
  446. {
  447. LARGE_INTEGER posStartOut;
  448. hr = WinGetVLFilePointer(fileOut, &posStartOut);
  449. BREAK_ON_FAILED_HRESULT(hr);
  450. if (posStartOut.QuadPart==0)
  451. {
  452. hr=writeHeader(fileOut);
  453. BREAK_ON_FAILED_HRESULT(hr);
  454. }
  455. setOfObjects::const_iterator begin,end;
  456. begin=objects.begin();
  457. end=objects.end();
  458. while(begin!=end)
  459. {
  460. String csvLine;
  461. hr=getObjectLine( begin->second,
  462. begin->first.c_str(),
  463. csvLine);
  464. BREAK_ON_FAILED_HRESULT(hr);
  465. hr=FS::WriteLine(fileOut,csvLine);
  466. BREAK_ON_FAILED_HRESULT(hr);
  467. begin++;
  468. }
  469. BREAK_ON_FAILED_HRESULT(hr);
  470. } while(0);
  471. LOG_HRESULT(hr);
  472. return hr;
  473. }