diff_tool.cpp

Go to the documentation of this file.
00001 
00004 /* Copyright, 2000, 2001, 2002 Nevrax Ltd.
00005  *
00006  * This file is part of NEVRAX NEL.
00007  * NEVRAX NEL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2, or (at your option)
00010  * any later version.
00011 
00012  * NEVRAX NEL is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00015  * General Public License for more details.
00016 
00017  * You should have received a copy of the GNU General Public License
00018  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00019  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00020  * MA 02111-1307, USA.
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 /*  uint8 *buffer = 0;
00084     uint    size;
00085 
00086     try
00087     {
00088         CIFile fp(filename);
00089         size = fp.getFileSize();
00090         buffer = new uint8[size];
00091         fp.serialBuffer(buffer, size);
00092     }
00093     catch(Exception &e)
00094     {
00095         nlinfo("Can't open file [%s] (%s)\n", filename.c_str(), e.what());
00096         return true;
00097     }
00098 */
00099 /*  FILE *fp = fopen(filename.c_str(), "rb");
00100 
00101     if (fp == NULL)
00102     {
00103         nlinfo("Can't open file [%s]\n", filename.c_str());
00104         if (buffer != 0)
00105             delete [] buffer;
00106         return true;
00107     }
00108 
00109     // move to end of file
00110     fseek(fp, 0, SEEK_END);
00111 
00112     fpos_t  pos;
00113     fgetpos(fp, &pos);
00114 
00115     uint8 *buffer = new uint8[uint(pos)];
00116 
00117     rewind(fp);
00118     uint size = fread(buffer, 1, uint(pos), fp);
00119     fclose (fp);
00120 */
00121     ucstring text;
00122 
00123     CI18N::readTextFile(filename, text, false, false, true, CI18N::LINE_FMT_CRLF);
00124 //  CI18N::readTextBuffer(buffer, size, text);
00125 //  delete [] buffer;
00126 
00127     // ok, parse the file now.
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             // check if there is only swap command remaining in comment
00139             if (si.Comments.find(ucstring("// DIFF SWAP ")) != ucstring::npos)
00140             {
00141                 stringInfos.push_back(si);
00142             }
00143             break;
00144         }
00145 
00146         // try to read a #fileline preprocessor command
00147         if (CI18N::matchToken("#fileline", first, last))
00148         {
00149             // for now, just skip
00150             uint32 lineCounter =0;  // we count line another way
00151             CI18N::skipLine(first, last, lineCounter);
00152 
00153             // begin parse of next line
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             // compute the hash value from text.
00199             si.HashValue = CI18N::makeHash(si.Text);
00200 //          nldebug("Generating hash for %s as %s", si.Identifier.c_str(), CI18N::hashToString(si.HashValue).c_str());
00201         }
00202         else
00203         {
00204 //          nldebug("Comment = [%s]", si.Comments.toString().c_str());
00205 //          nldebug("Retrieving hash for %s as %s", si.Identifier.c_str(), CI18N::hashToString(si.HashValue).c_str());
00206         }
00207         stringInfos.push_back(si);
00208     }
00209 
00210 
00211     // check identifier uniqueness
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             // add hash value comment if needed
00284 //          if (si.Comments.find(ucstring("// HASH_VALUE ")) == ucstring::npos)
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             // add new line and tab after each \n tag
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;//.substr(0, pos+2);
00303             str += text2 + nl + nl;
00304 //          str += CI18N::makeMarkedString('[', ']', si.Text) + nl + nl;
00305         }
00306 
00307 //      nldebug("Adding string [%s]", str.toString().c_str());
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         // parse the phrase
00333         CI18N::skipWhiteSpace(first, last, &phrase.Comments);
00334 
00335         if (first == last)
00336         {
00337             if (!phrase.Comments.empty())
00338             {
00339                 // push the resulting comment
00340                 phrases.push_back(phrase);
00341             }
00342             break;
00343         }
00344 
00345         // try to read a #fileline preprocessor command
00346         if (CI18N::matchToken("#fileline", first, last))
00347         {
00348             // for now, just skip
00349             uint32 lineCounter =0;  // we count line another way
00350             CI18N::skipLine(first, last, lineCounter);
00351 
00352             // begin parse of next line
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 //      nldebug("DT: parsing phrase '%s'", phrase.Identifier.c_str());
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             // append the comment preread at previous pass
00395             clause.Comments = temp;
00396             temp.erase();
00397             // parse the clauses
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             // skip the conditional expression
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             // read the idnetifier (if any)
00433             CI18N::parseLabel(first, last, clause.Identifier);
00434             CI18N::skipWhiteSpace(first, last, &temp);
00435             // read the text
00436             if (CI18N::parseMarkedString('[', ']', first, last, clause.Text))
00437             {
00438                 // the last read comment is for this clause.
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         // handle hash value.
00470         if (forceRehash || !parseHashFromComment(phrase.Comments, phrase.HashValue))
00471         {
00472             // the hash is not in the comment, compute it.
00473             phrase.HashValue = makePhraseHash(phrase);
00474             if (forceRehash)
00475             {
00476                 // the has is perhaps in the comment
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 //      nldebug("DT : storing phrase '%s'", phrase.Identifier.c_str());
00486         phrases.push_back(phrase);
00487     }
00488 
00489     // check identifier uniqueness
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                 // add the hash value.
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; // + '\r'+'\n';
00584                 }
00585                 if (!c.Conditions.empty())
00586                 {
00587                     ucstring cond = tabLines(1, c.Conditions);
00588                     ret += cond + nl;
00589                 }
00590                 ret += '\t';
00591 //              ucstring text = CI18N::makeMarkedString('[', ']', c.Text);
00592 
00593                 ucstring text = CI18N::makeMarkedString('[', ']', c.Text);;
00594                 ucstring text2;
00595                 // add new line and tab after each \n tag
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;//.substr(0, pos+2);
00604 
00605                 text.swap(text2);
00606 
00607                 text = tabLines(3, text);
00608                 // remove begin tabs
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     // Yoyo: must test with CIFile because can be packed into a .bnp on client...
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     // copy the str to a big ucchar array => Avoid allocation / free
00646     vector<ucchar>  strArray;
00647     // append a '\0'
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     // **** Build array of lines. just point to strArray, and fill 0 where appropriated
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 //          nldebug("Found line : [%s]", ucstring(&strArray[lastPos]).toString().c_str());
00664             lines.push_back(&strArray[lastPos]);
00665         }
00666         lastPos = pos + 2;
00667     }
00668 
00669     // Must add last line if no \r\n ending
00670     if (lastPos < str.size())
00671     {
00672         pos= str.size();
00673         strArray[pos]= 0;
00674 //      nldebug("Found line : [%s]", ucstring(&strArray[lastPos]).toString().c_str());
00675         lines.push_back(&strArray[lastPos]);
00676     }
00677 
00678 //  nldebug("Found %u lines", lines.size());
00679 
00680     // **** Do 2 pass.1st count the cell number, then fill. => avoid reallocation
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                 // read a quoted field.
00698                 first++;
00699                 while (*first != 0 && *first != '"' && *(first+1) != 0 && *(first+1) != '"')
00700                 {
00701                     first++;
00702                     if (*first != 0 && *first == '"')
00703                     {
00704                         // skip this
00705                         first++;
00706                     }
00707                 }
00708             }
00709         }
00710         // last cell
00711         numCells++;
00712 
00713         // take max cell of all lines
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     // **** alloc / enlarge worksheet
00724     // enlarge Worksheet column size, as needed
00725     while (worksheet.ColCount < newColCount)
00726         worksheet.insertColumn(worksheet.ColCount);
00727 
00728     // enlarge Worksheet row size, as needed
00729     uint    startLine= worksheet.size();
00730     worksheet.resize(startLine + lines.size());
00731 
00732 
00733     // **** fill worksheet
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 //              nldebug("Found cell [%s]", cell.toString().c_str());
00747                 worksheet.setData(startLine + i, numCells, cell);
00748                 numCells++;
00749                 cell.erase();
00750             }
00751             else if (*first == '"' && first==lines[i])
00752             {
00753                 // read a quoted field.
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                         // skip this
00762                         first++;
00763                     }
00764                 }
00765             }
00766             else
00767             {
00768                 cell += *first;
00769             }
00770         }
00771 //      nldebug("Found cell [%s]", cell.toString().c_str());
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 //      nldebug("Found %u cells in line %u", numCells, i);
00777     }
00778 
00779 
00780     // **** identifier uniqueness checking.
00781     if (checkUnique)
00782     {
00783         if (worksheet.size() > 0)
00784         {
00785             // look for the first non '* tagged' or 'DIFF_CMD' column
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                 // ok we can check unikness
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             // we need to generate HASH_VALUE column !
00824             if (it == sheet.Data[0].end())
00825             {
00826                 sheet.insertColumn(0);
00827                 sheet.Data[0][0] = ucstring("*HASH_VALUE");
00828             }
00829 
00830             // Check columns
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             // make hash for each line
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     // **** First pass: count approx the size
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     // Hash value for each column?
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     // **** Second pass: fill
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 }   // namespace STRING_MANAGER
00921 

Generated on Thu Jan 7 08:26:33 2010 for NeL by  doxygen 1.6.1