00001
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "stdmisc.h"
00024
00025 #include "nel/misc/diff_tool.h"
00026 #include "nel/misc/path.h"
00027
00028 using namespace NLMISC;
00029 using namespace std;
00030
00031
00032 namespace STRING_MANAGER
00033 {
00034
00035 uint64 makePhraseHash(const TPhrase &phrase)
00036 {
00037 ucstring text;
00038 text = phrase.Parameters;
00039 for (uint i=0; i<phrase.Clauses.size(); ++i)
00040 {
00041 text += phrase.Clauses[i].Conditions;
00042 text += phrase.Clauses[i].Identifier;
00043 text += phrase.Clauses[i].Text;
00044 }
00045
00046 return CI18N::makeHash(text);
00047 }
00048
00049
00050
00051
00052 bool parseHashFromComment(const ucstring &comments, uint64 &hashValue)
00053 {
00054 string str = comments.toString();
00055
00056 string::size_type pos = str.find("HASH_VALUE ");
00057 if (pos == string::npos)
00058 return false;
00059
00060 string hashStr = str.substr(pos + 11, 16);
00061
00062 hashValue = CI18N::stringToHash(hashStr);
00063 return true;
00064 }
00065
00066
00067 uint32 countLine(const ucstring &text, const ucstring::const_iterator upTo)
00068 {
00069 uint32 ret = 1;
00070 ucstring::const_iterator first(text.begin());
00071
00072 for (; first != upTo; ++first)
00073 {
00074 if (*first == '\n')
00075 ret++;
00076 }
00077
00078 return ret;
00079 }
00080
00081 bool loadStringFile(const std::string filename, vector<TStringInfo> &stringInfos, bool forceRehash, ucchar openMark, ucchar closeMark, bool specialCase)
00082 {
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 ucstring text;
00122
00123 CI18N::readTextFile(filename, text, false, false, true, CI18N::LINE_FMT_CRLF);
00124
00125
00126
00127
00128 ucstring::const_iterator first(text.begin()), last(text.end());
00129 std::string lastLabel("nothing");
00130
00131 while (first != last)
00132 {
00133 TStringInfo si;
00134 CI18N::skipWhiteSpace(first, last, &si.Comments);
00135
00136 if (first == last)
00137 {
00138
00139 if (si.Comments.find(ucstring("// DIFF SWAP ")) != ucstring::npos)
00140 {
00141 stringInfos.push_back(si);
00142 }
00143 break;
00144 }
00145
00146
00147 if (CI18N::matchToken("#fileline", first, last))
00148 {
00149
00150 uint32 lineCounter =0;
00151 CI18N::skipLine(first, last, lineCounter);
00152
00153
00154 continue;
00155 }
00156
00157 if (!CI18N::parseLabel(first, last, si.Identifier))
00158 {
00159 uint32 line = countLine(text, first);
00160 nlwarning("DT: Fatal : In '%s', line %u: Invalid label after '%s'\n",
00161 filename.c_str(),
00162 line,
00163 lastLabel.c_str());
00164 return false;
00165 }
00166 lastLabel = si.Identifier;
00167
00168 CI18N::skipWhiteSpace(first, last, &si.Comments);
00169
00170 if (!CI18N::parseMarkedString(openMark, closeMark, first, last, si.Text))
00171 {
00172 uint32 line = countLine(text, first);
00173 nlwarning("DT: Fatal : In '%s', line %u: Invalid text value for label %s\n",
00174 filename.c_str(),
00175 line,
00176 lastLabel.c_str());
00177 return false;
00178 }
00179
00180 if (specialCase)
00181 {
00182 CI18N::skipWhiteSpace(first, last, &si.Comments);
00183
00184 if (!CI18N::parseMarkedString(openMark, closeMark, first, last, si.Text2))
00185 {
00186 uint32 line = countLine(text, first);
00187 nlwarning("DT: Fatal: In '%s' line %u: Invalid text2 value label %s\n",
00188 filename.c_str(),
00189 line,
00190 lastLabel.c_str());
00191 return false;
00192 }
00193
00194 }
00195
00196 if (forceRehash || !parseHashFromComment(si.Comments, si.HashValue))
00197 {
00198
00199 si.HashValue = CI18N::makeHash(si.Text);
00200
00201 }
00202 else
00203 {
00204
00205
00206 }
00207 stringInfos.push_back(si);
00208 }
00209
00210
00211
00212 {
00213 bool error = false;
00214 set<string> unik;
00215 set<string>::iterator it;
00216 for (uint i=0; i<stringInfos.size(); ++i)
00217 {
00218 it = unik.find(stringInfos[i].Identifier);
00219 if (it != unik.end())
00220 {
00221 nlwarning("DT: loadStringFile : identifier '%s' exist twice", stringInfos[i].Identifier.c_str() );
00222 error = true;
00223 }
00224 else
00225 unik.insert(stringInfos[i].Identifier);
00226
00227 }
00228 if (error)
00229 return false;
00230 }
00231
00232 return true;
00233 }
00234
00235
00236 ucstring prepareStringFile(const vector<TStringInfo> &strings, bool removeDiffComments, bool noDiffInfo)
00237 {
00238 ucstring diff;
00239
00240 vector<TStringInfo>::const_iterator first(strings.begin()), last(strings.end());
00241 for (; first != last; ++first)
00242 {
00243 ucstring str;
00244 const TStringInfo &si = *first;
00245 string comment = si.Comments.toString();
00246 vector<string> lines;
00247 explode(comment, string("\n"), lines, true);
00248
00249 uint i;
00250 for (i=0; i<lines.size(); ++i)
00251 {
00252 if (removeDiffComments)
00253 {
00254 if (lines[i].find("// DIFF ") != string::npos)
00255 {
00256 lines.erase(lines.begin()+i);
00257 --i;
00258 continue;
00259 }
00260 }
00261 if (lines[i].find("// INDEX ") != string::npos)
00262 {
00263 lines.erase(lines.begin()+i);
00264 --i;
00265 }
00266 else if (lines[i].find("// HASH_VALUE ") != string::npos)
00267 {
00268 lines.erase(lines.begin()+i);
00269 --i;
00270 }
00271 }
00272
00273 comment.erase();
00274 for (i=0; i<lines.size(); ++i)
00275 {
00276 comment += lines[i] + "\n";
00277 }
00278 si.Comments = ucstring(comment);
00279
00280 str = si.Comments;
00281 if (!si.Identifier.empty() || !si.Text.empty())
00282 {
00283
00284
00285 if (!noDiffInfo)
00286 {
00287 str += ucstring("// HASH_VALUE ") + CI18N::hashToString(si.HashValue)+ nl;
00288 str += ucstring("// INDEX ") + NLMISC::toString("%u", first-strings.begin())+ nl;
00289 }
00290 str += si.Identifier + '\t';
00291
00292 ucstring text = CI18N::makeMarkedString('[', ']', si.Text);;
00293 ucstring text2;
00294
00295 ucstring::size_type pos;
00296 const ucstring nlTag("\\n");
00297 while ((pos = text.find(nlTag)) != ucstring::npos)
00298 {
00299 text2 += text.substr(0, pos+2) + nl + "\t";
00300 text = text.substr(pos+2);
00301 }
00302 text2 += text;
00303 str += text2 + nl + nl;
00304
00305 }
00306
00307
00308 diff += str;
00309 }
00310
00311 return diff;
00312 }
00313
00314
00315 bool readPhraseFile(const std::string &filename, vector<TPhrase> &phrases, bool forceRehash)
00316 {
00317 ucstring doc;
00318
00319 CI18N::readTextFile(filename, doc, false, false, true, CI18N::LINE_FMT_CRLF);
00320
00321 return readPhraseFileFromString(doc, filename, phrases, forceRehash);
00322 }
00323
00324 bool readPhraseFileFromString(ucstring const& doc, const std::string &filename, vector<TPhrase> &phrases, bool forceRehash)
00325 {
00326 std::string lastRead("nothing");
00327
00328 ucstring::const_iterator first(doc.begin()), last(doc.end());
00329 while (first != last)
00330 {
00331 TPhrase phrase;
00332
00333 CI18N::skipWhiteSpace(first, last, &phrase.Comments);
00334
00335 if (first == last)
00336 {
00337 if (!phrase.Comments.empty())
00338 {
00339
00340 phrases.push_back(phrase);
00341 }
00342 break;
00343 }
00344
00345
00346 if (CI18N::matchToken("#fileline", first, last))
00347 {
00348
00349 uint32 lineCounter =0;
00350 CI18N::skipLine(first, last, lineCounter);
00351
00352
00353 continue;
00354 }
00355
00356 if (!CI18N::parseLabel(first, last, phrase.Identifier))
00357 {
00358 uint32 line = countLine(doc, first);
00359 nlwarning("DT: In '%s' line %u: Error parsing phrase identifier after %s\n",
00360 filename.c_str(),
00361 line,
00362 lastRead.c_str());
00363 return false;
00364 }
00365
00366 lastRead = phrase.Identifier;
00367 CI18N::skipWhiteSpace(first, last, &phrase.Comments);
00368 if (!CI18N::parseMarkedString('(', ')', first, last, phrase.Parameters))
00369 {
00370 uint32 line = countLine(doc, first);
00371 nlwarning("DT: in '%s', line %u: Error parsing parameter list for phrase %s\n",
00372 filename.c_str(),
00373 line,
00374 phrase.Identifier.c_str());
00375 return false;
00376 }
00377 CI18N::skipWhiteSpace(first, last, &phrase.Comments);
00378 if (first == last || *first != '{')
00379 {
00380 uint32 line = countLine(doc, first);
00381 nlwarning("DT: In '%s', line %u: Error parsing block opening '{' in phase %s\n",
00382 filename.c_str(),
00383 line,
00384 phrase.Identifier.c_str());
00385 return false;
00386 }
00387 ++first;
00388
00389 ucstring temp;
00390
00391 while (first != last && *first != '}')
00392 {
00393 TClause clause;
00394
00395 clause.Comments = temp;
00396 temp.erase();
00397
00398 CI18N::skipWhiteSpace(first, last, &clause.Comments);
00399 if (first == last)
00400 {
00401 nlwarning("DT: Found end of file in non closed block for phrase %s\n", phrase.Identifier.c_str());
00402 return false;
00403 }
00404
00405 if (*first == '}')
00406 break;
00407
00408
00409 ucstring cond;
00410 while (first != last && *first == '(')
00411 {
00412 if (!CI18N::parseMarkedString('(', ')', first, last, cond))
00413 {
00414 uint32 line = countLine(doc, first);
00415 nlwarning("DT: In '%s' line %u: Error parsing conditional expression in phrase %s, clause %u\n",
00416 filename.c_str(),
00417 line,
00418 phrase.Identifier.c_str(),
00419 phrase.Clauses.size()+1);
00420 return false;
00421 }
00422 clause.Conditions += "(" + cond + ") ";
00423 CI18N::skipWhiteSpace(first, last, &clause.Comments);
00424 }
00425 if (first == last)
00426 {
00427 nlwarning("DT: in '%s': Found end of file in non closed block for phrase %s\n",
00428 filename.c_str(),
00429 phrase.Identifier.c_str());
00430 return false;
00431 }
00432
00433 CI18N::parseLabel(first, last, clause.Identifier);
00434 CI18N::skipWhiteSpace(first, last, &temp);
00435
00436 if (CI18N::parseMarkedString('[', ']', first, last, clause.Text))
00437 {
00438
00439 clause.Comments += temp;
00440 temp.erase();
00441 }
00442 else
00443 {
00444 uint32 line = countLine(doc, first);
00445 nlwarning("DT: in '%s' line %u: Error reading text for clause %u (%s) in phrase %s\n",
00446 filename.c_str(),
00447 line,
00448 phrase.Clauses.size()+1,
00449 clause.Identifier.c_str(),
00450 phrase.Identifier.c_str());
00451 return false;
00452
00453 }
00454
00455 phrase.Clauses.push_back(clause);
00456 }
00457 CI18N::skipWhiteSpace(first, last);
00458 if (first == last || *first != '}')
00459 {
00460 uint32 line = countLine(doc, first);
00461 nlwarning("DT: in '%s' line %u: Missing block closing tag '}' in phrase %s\n",
00462 filename.c_str(),
00463 line,
00464 phrase.Identifier.c_str());
00465 return false;
00466 }
00467 ++first;
00468
00469
00470 if (forceRehash || !parseHashFromComment(phrase.Comments, phrase.HashValue))
00471 {
00472
00473 phrase.HashValue = makePhraseHash(phrase);
00474 if (forceRehash)
00475 {
00476
00477 ucstring::size_type pos = phrase.Comments.find(ucstring("// HASH_VALUE"));
00478 if (pos != ucstring::npos)
00479 {
00480 phrase.Comments = phrase.Comments.substr(0, pos);
00481 }
00482 }
00483 }
00484
00485
00486 phrases.push_back(phrase);
00487 }
00488
00489
00490 {
00491 bool error = false;
00492 set<string> unik;
00493 set<string>::iterator it;
00494 for (uint i=0; i<phrases.size(); ++i)
00495 {
00496 it = unik.find(phrases[i].Identifier);
00497 if (it != unik.end())
00498 {
00499 nlwarning("DT: readPhraseFile : identifier '%s' exist twice", phrases[i].Identifier.c_str() );
00500 error = true;
00501 }
00502 else
00503 unik.insert(phrases[i].Identifier);
00504 }
00505 if (error)
00506 return false;
00507 }
00508
00509 return true;
00510 }
00511 ucstring tabLines(uint nbTab, const ucstring &str)
00512 {
00513 ucstring ret;
00514 ucstring tabs;
00515
00516 for (uint i =0; i<nbTab; ++i)
00517 tabs.push_back('\t');
00518
00519 ret = tabs;
00520 ucstring::const_iterator first(str.begin()), last(str.end());
00521 for (; first != last; ++first)
00522 {
00523 ret += *first;
00524 if (*first == '\n')
00525 ret += tabs;
00526 }
00527
00528 while (ret[ret.size()-1] == '\t')
00529 ret = ret.substr(0, ret.size()-1);
00530
00531 return ret;
00532 }
00533
00534 ucstring preparePhraseFile(const vector<TPhrase> &phrases, bool removeDiffComments)
00535 {
00536 ucstring ret;
00537 vector<TPhrase>::const_iterator first(phrases.begin()), last(phrases.end());
00538 for (; first != last; ++first)
00539 {
00540 const TPhrase &p = *first;
00541
00542 if (removeDiffComments)
00543 {
00544 string comment = p.Comments.toString();
00545 vector<string> lines;
00546 explode(comment, string("\n"), lines, true);
00547
00548 uint i;
00549 for (i=0; i<lines.size(); ++i)
00550 {
00551 if (lines[i].find("// DIFF ") != string::npos)
00552 {
00553 lines.erase(lines.begin()+i);
00554 --i;
00555 }
00556 }
00557
00558 comment.erase();
00559 for (i=0; i<lines.size(); ++i)
00560 {
00561 comment += lines[i] + "\n";
00562 }
00563 p.Comments = ucstring(comment);
00564 }
00565 ret += p.Comments;
00566
00567 if (!p.Identifier.empty() || !p.Clauses.empty())
00568 {
00569 if (p.Comments.find(ucstring("// HASH_VALUE ")) == ucstring::npos)
00570 {
00571
00572 ret += ucstring("// HASH_VALUE ")+CI18N::hashToString(p.HashValue) + nl;
00573 }
00574 ret += p.Identifier + " ("+p.Parameters + ")" + nl;
00575 ret += '{';
00576 ret += nl;
00577 for (uint i=0; i<p.Clauses.size(); ++i)
00578 {
00579 const TClause &c = p.Clauses[i];
00580 if (!c.Comments.empty())
00581 {
00582 ucstring comment = tabLines(1, c.Comments);
00583 ret += comment;
00584 }
00585 if (!c.Conditions.empty())
00586 {
00587 ucstring cond = tabLines(1, c.Conditions);
00588 ret += cond + nl;
00589 }
00590 ret += '\t';
00591
00592
00593 ucstring text = CI18N::makeMarkedString('[', ']', c.Text);;
00594 ucstring text2;
00595
00596 ucstring::size_type pos;
00597 const ucstring nlTag("\\n");
00598 while ((pos = text.find(nlTag)) != ucstring::npos)
00599 {
00600 text2 += text.substr(0, pos+2) + nl;
00601 text = text.substr(pos+2);
00602 }
00603 text2 += text;
00604
00605 text.swap(text2);
00606
00607 text = tabLines(3, text);
00608
00609 text = text.substr(3);
00610 ret += '\t' + c.Identifier + '\t' + text + nl + nl;
00611 }
00612 ret += '}';
00613 }
00614 ret += nl + nl;
00615 }
00616
00617 return ret;
00618 }
00619
00620 bool loadExcelSheet(const string filename, TWorksheet &worksheet, bool checkUnique)
00621 {
00622
00623 CIFile fp;
00624 if(!fp.open(filename))
00625 {
00626 nldebug("DT: Can't open file [%s]\n", filename.c_str());
00627 return true;
00628 }
00629 fp.close();
00630
00631 ucstring str;
00632 CI18N::readTextFile(filename, str, false, false, false, CI18N::LINE_FMT_CRLF);
00633
00634 if (!readExcelSheet(str, worksheet, checkUnique))
00635 return false;
00636
00637 return true;
00638 }
00639
00640 bool readExcelSheet(const ucstring &str, TWorksheet &worksheet, bool checkUnique)
00641 {
00642 if(str.empty())
00643 return true;
00644
00645
00646 vector<ucchar> strArray;
00647
00648 strArray.resize(str.size()+1);
00649 strArray[strArray.size()-1]= 0;
00650 memcpy(&strArray[0], &str[0], str.size()*sizeof(ucchar));
00651
00652
00653
00654 vector<ucchar*> lines;
00655 lines.reserve(500);
00656 ucstring::size_type pos = 0;
00657 ucstring::size_type lastPos = 0;
00658 while ((pos = str.find(nl, lastPos)) != ucstring::npos)
00659 {
00660 if (pos>lastPos)
00661 {
00662 strArray[pos]= 0;
00663
00664 lines.push_back(&strArray[lastPos]);
00665 }
00666 lastPos = pos + 2;
00667 }
00668
00669
00670 if (lastPos < str.size())
00671 {
00672 pos= str.size();
00673 strArray[pos]= 0;
00674
00675 lines.push_back(&strArray[lastPos]);
00676 }
00677
00678
00679
00680
00681 uint newColCount= 0;
00682 uint i;
00683 for (i=0; i<lines.size(); ++i)
00684 {
00685 uint numCells;
00686 numCells= 0;
00687
00688 ucchar *first= lines[i];
00689 for (; *first != 0; ++first)
00690 {
00691 if (*first == '\t')
00692 {
00693 numCells++;
00694 }
00695 else if (*first == '"' && first==lines[i])
00696 {
00697
00698 first++;
00699 while (*first != 0 && *first != '"' && *(first+1) != 0 && *(first+1) != '"')
00700 {
00701 first++;
00702 if (*first != 0 && *first == '"')
00703 {
00704
00705 first++;
00706 }
00707 }
00708 }
00709 }
00710
00711 numCells++;
00712
00713
00714 if (newColCount != max(newColCount, numCells))
00715 {
00716 newColCount = max(newColCount, numCells);
00717 nldebug("At line %u, numCol changed to %u",
00718 i, newColCount);
00719 }
00720 }
00721
00722
00723
00724
00725 while (worksheet.ColCount < newColCount)
00726 worksheet.insertColumn(worksheet.ColCount);
00727
00728
00729 uint startLine= worksheet.size();
00730 worksheet.resize(startLine + lines.size());
00731
00732
00733
00734 ucstring cell;
00735 for (i=0; i<lines.size(); ++i)
00736 {
00737 uint numCells;
00738 numCells= 0;
00739 cell.erase();
00740
00741 ucchar *first= lines[i];
00742 for (; *first != 0; ++first)
00743 {
00744 if (*first == '\t')
00745 {
00746
00747 worksheet.setData(startLine + i, numCells, cell);
00748 numCells++;
00749 cell.erase();
00750 }
00751 else if (*first == '"' && first==lines[i])
00752 {
00753
00754 first++;
00755 while (*first != 0 && *first != '"' && *(first+1) != 0 && *(first+1) != '"')
00756 {
00757 cell += *first;
00758 first++;
00759 if (*first != 0 && *first == '"')
00760 {
00761
00762 first++;
00763 }
00764 }
00765 }
00766 else
00767 {
00768 cell += *first;
00769 }
00770 }
00771
00773 worksheet.setData(startLine + i, numCells, cell);
00774 numCells++;
00775 nlassertex(numCells<=newColCount, ("readExcelSheet: bad row format: at line %u, the row has %u cell, max is %u", i, numCells, newColCount));
00776
00777 }
00778
00779
00780
00781 if (checkUnique)
00782 {
00783 if (worksheet.size() > 0)
00784 {
00785
00786 uint nameCol = 0;
00787 while (nameCol < worksheet.ColCount && (*worksheet.getData(0, nameCol).begin() == uint16('*') || worksheet.getData(0, nameCol) == ucstring("DIFF_CMD")))
00788 ++nameCol;
00789
00790 if (nameCol < worksheet.ColCount )
00791 {
00792
00793 bool error = false;
00794 set<ucstring> unik;
00795 set<ucstring>::iterator it;
00796 for (uint j=0; j<worksheet.size(); ++j)
00797 {
00798 it = unik.find(worksheet.getData(j, nameCol));
00799 if (it != unik.end())
00800 {
00801 nlwarning("DT: readExcelSheet : identifier '%s' exist twice", worksheet.getData(j, nameCol).toString().c_str() );
00802 error = true;
00803 }
00804 else
00805 unik.insert(worksheet.getData(j, nameCol));
00806 }
00807 if (error)
00808 return false;
00809 }
00810 }
00811 }
00812
00813 return true;
00814 }
00815
00816 void makeHashCode(TWorksheet &sheet, bool forceRehash)
00817 {
00818 if (!sheet.Data.empty())
00819 {
00820 TWorksheet::TRow::iterator it = find(sheet.Data[0].begin(), sheet.Data[0].end(), ucstring("*HASH_VALUE"));
00821 if (forceRehash || it == sheet.Data[0].end())
00822 {
00823
00824 if (it == sheet.Data[0].end())
00825 {
00826 sheet.insertColumn(0);
00827 sheet.Data[0][0] = ucstring("*HASH_VALUE");
00828 }
00829
00830
00831 vector<bool> columnOk;
00832 columnOk.resize(sheet.ColCount, false);
00833 for (uint k=1; k<sheet.ColCount; ++k)
00834 {
00835 if (sheet.Data[0][k].find(ucstring("*")) != 0 && sheet.Data[0][k].find(ucstring("DIFF ")) != 0)
00836 {
00837 columnOk[k]= true;
00838 }
00839 }
00840
00841
00842 ucstring str;
00843 for (uint j=1; j<sheet.Data.size(); ++j)
00844 {
00845 str.erase();
00846 for (uint k=1; k<sheet.ColCount; ++k)
00847 {
00848 if (columnOk[k])
00849 {
00850 str += sheet.Data[j][k];
00851 }
00852 }
00853 uint64 hash = CI18N::makeHash(str);
00854 CI18N::hashToUCString(hash, sheet.Data[j][0]);
00855 }
00856 }
00857 else
00858 {
00859 uint index = it - sheet.Data[0].begin();
00860 for (uint j=1; j<sheet.Data.size(); ++j)
00861 {
00862 ucstring &field = sheet.Data[j][index];
00863
00864 if (!field.empty() && field[0] == '_')
00865 field = field.substr(1);
00866 }
00867 }
00868 }
00869 }
00870
00871 ucstring prepareExcelSheet(const TWorksheet &worksheet)
00872 {
00873 if(worksheet.Data.empty())
00874 return ucstring();
00875
00876
00877 uint approxSize= 0;
00878 for (uint i=0; i<worksheet.Data.size(); ++i)
00879 {
00880 for (uint j=0; j<worksheet.Data[i].size(); ++j)
00881 {
00882 approxSize+= worksheet.Data[i][j].size() + 1;
00883 }
00884 approxSize++;
00885 }
00886
00887
00888 vector<bool> hashValue;
00889 hashValue.resize(worksheet.Data[0].size());
00890 for (uint j=0; j<worksheet.Data[0].size(); ++j)
00891 {
00892 hashValue[j]= worksheet.Data[0][j] == ucstring("*HASH_VALUE");
00893 }
00894
00895
00896 ucstring text;
00897 text.reserve(approxSize*2);
00898 for (uint i=0; i<worksheet.Data.size(); ++i)
00899 {
00900 for (uint j=0; j<worksheet.Data[i].size(); ++j)
00901 {
00902 if (i > 0 && hashValue[j] && (!worksheet.Data[i][j].empty() && worksheet.Data[i][j][0] != '_'))
00903 text += "_";
00904 text += worksheet.Data[i][j];
00905 if (j != worksheet.Data[i].size()-1)
00906 text += '\t';
00907 }
00908 text += nl;
00909 }
00910
00911 return text;
00912 }
00913
00914
00915
00916
00917
00918
00919
00920 }
00921