// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdmisc.h" #include "nel/misc/diff_tool.h" #include "nel/misc/path.h" using namespace NLMISC; using namespace std; #ifdef DEBUG_NEW #define new DEBUG_NEW #endif namespace STRING_MANAGER { uint64 makePhraseHash(const TPhrase &phrase) { ucstring text; text = phrase.Parameters; for (uint i=0; i &stringInfos, bool forceRehash, ucchar openMark, ucchar closeMark, bool specialCase) { /* uint8 *buffer = 0; uint size; try { CIFile fp(filename); size = fp.getFileSize(); buffer = new uint8[size]; fp.serialBuffer(buffer, size); } catch(const Exception &e) { nlinfo("Can't open file [%s] (%s)\n", filename.c_str(), e.what()); return true; } */ /* FILE *fp = fopen(filename.c_str(), "rb"); if (fp == NULL) { nlinfo("Can't open file [%s]\n", filename.c_str()); if (buffer != 0) delete [] buffer; return true; } // move to end of file fseek(fp, 0, SEEK_END); fpos_t pos; fgetpos(fp, &pos); uint8 *buffer = new uint8[uint(pos)]; rewind(fp); uint size = fread(buffer, 1, uint(pos), fp); fclose (fp); */ ucstring text; CI18N::readTextFile(filename, text, false, false, true, CI18N::LINE_FMT_CRLF); // CI18N::readTextBuffer(buffer, size, text); // delete [] buffer; // ok, parse the file now. ucstring::const_iterator first(text.begin()), last(text.end()); std::string lastLabel("nothing"); while (first != last) { TStringInfo si; CI18N::skipWhiteSpace(first, last, &si.Comments); if (first == last) { // check if there is only swap command remaining in comment if (si.Comments.find(ucstring("// DIFF SWAP ")) != ucstring::npos) { stringInfos.push_back(si); } break; } // try to read a #fileline preprocessor command if (CI18N::matchToken("#fileline", first, last)) { // for now, just skip uint32 lineCounter =0; // we count line another way CI18N::skipLine(first, last, lineCounter); // begin parse of next line continue; } if (!CI18N::parseLabel(first, last, si.Identifier)) { uint32 line = countLine(text, first); nlwarning("DT: Fatal : In '%s', line %u: Invalid label after '%s'\n", filename.c_str(), line, lastLabel.c_str()); return false; } lastLabel = si.Identifier; CI18N::skipWhiteSpace(first, last, &si.Comments); if (!CI18N::parseMarkedString(openMark, closeMark, first, last, si.Text)) { uint32 line = countLine(text, first); nlwarning("DT: Fatal : In '%s', line %u: Invalid text value for label %s\n", filename.c_str(), line, lastLabel.c_str()); return false; } if (specialCase) { CI18N::skipWhiteSpace(first, last, &si.Comments); if (!CI18N::parseMarkedString(openMark, closeMark, first, last, si.Text2)) { uint32 line = countLine(text, first); nlwarning("DT: Fatal: In '%s' line %u: Invalid text2 value label %s\n", filename.c_str(), line, lastLabel.c_str()); return false; } } if (forceRehash || !parseHashFromComment(si.Comments, si.HashValue)) { // compute the hash value from text. si.HashValue = CI18N::makeHash(si.Text); // nldebug("Generating hash for %s as %s", si.Identifier.c_str(), CI18N::hashToString(si.HashValue).c_str()); } else { // nldebug("Comment = [%s]", si.Comments.toString().c_str()); // nldebug("Retrieving hash for %s as %s", si.Identifier.c_str(), CI18N::hashToString(si.HashValue).c_str()); } stringInfos.push_back(si); } // check identifier uniqueness { bool error = false; set unik; set::iterator it; for (uint i=0; i &strings, bool removeDiffComments, bool noDiffInfo) { ucstring diff; vector::const_iterator first(strings.begin()), last(strings.end()); for (; first != last; ++first) { ucstring str; const TStringInfo &si = *first; string comment = si.Comments.toString(); vector lines; explode(comment, string("\n"), lines, true); uint i; for (i=0; i &phrases, bool forceRehash) { ucstring doc; CI18N::readTextFile(filename, doc, false, false, true, CI18N::LINE_FMT_CRLF); return readPhraseFileFromString(doc, filename, phrases, forceRehash); } bool readPhraseFileFromString(ucstring const& doc, const std::string &filename, vector &phrases, bool forceRehash) { std::string lastRead("nothing"); ucstring::const_iterator first(doc.begin()), last(doc.end()); while (first != last) { TPhrase phrase; // parse the phrase CI18N::skipWhiteSpace(first, last, &phrase.Comments); if (first == last) { if (!phrase.Comments.empty()) { // push the resulting comment phrases.push_back(phrase); } break; } // try to read a #fileline preprocessor command if (CI18N::matchToken("#fileline", first, last)) { // for now, just skip uint32 lineCounter =0; // we count line another way CI18N::skipLine(first, last, lineCounter); // begin parse of next line continue; } if (!CI18N::parseLabel(first, last, phrase.Identifier)) { uint32 line = countLine(doc, first); nlwarning("DT: In '%s' line %u: Error parsing phrase identifier after %s\n", filename.c_str(), line, lastRead.c_str()); return false; } // nldebug("DT: parsing phrase '%s'", phrase.Identifier.c_str()); lastRead = phrase.Identifier; CI18N::skipWhiteSpace(first, last, &phrase.Comments); if (!CI18N::parseMarkedString('(', ')', first, last, phrase.Parameters)) { uint32 line = countLine(doc, first); nlwarning("DT: in '%s', line %u: Error parsing parameter list for phrase %s\n", filename.c_str(), line, phrase.Identifier.c_str()); return false; } CI18N::skipWhiteSpace(first, last, &phrase.Comments); if (first == last || *first != '{') { uint32 line = countLine(doc, first); nlwarning("DT: In '%s', line %u: Error parsing block opening '{' in phase %s\n", filename.c_str(), line, phrase.Identifier.c_str()); return false; } ++first; ucstring temp; while (first != last && *first != '}') { TClause clause; // append the comment preread at previous pass clause.Comments = temp; temp.erase(); // parse the clauses CI18N::skipWhiteSpace(first, last, &clause.Comments); if (first == last) { nlwarning("DT: Found end of file in non closed block for phrase %s\n", phrase.Identifier.c_str()); return false; } if (*first == '}') break; // skip the conditional expression ucstring cond; while (first != last && *first == '(') { if (!CI18N::parseMarkedString('(', ')', first, last, cond)) { uint32 line = countLine(doc, first); nlwarning("DT: In '%s' line %u: Error parsing conditional expression in phrase %s, clause %u\n", filename.c_str(), line, phrase.Identifier.c_str(), phrase.Clauses.size()+1); return false; } clause.Conditions += "(" + cond + ") "; CI18N::skipWhiteSpace(first, last, &clause.Comments); } if (first == last) { nlwarning("DT: in '%s': Found end of file in non closed block for phrase %s\n", filename.c_str(), phrase.Identifier.c_str()); return false; } // read the idnetifier (if any) CI18N::parseLabel(first, last, clause.Identifier); CI18N::skipWhiteSpace(first, last, &temp); // read the text if (CI18N::parseMarkedString('[', ']', first, last, clause.Text)) { // the last read comment is for this clause. clause.Comments += temp; temp.erase(); } else { uint32 line = countLine(doc, first); nlwarning("DT: in '%s' line %u: Error reading text for clause %u (%s) in phrase %s\n", filename.c_str(), line, phrase.Clauses.size()+1, clause.Identifier.c_str(), phrase.Identifier.c_str()); return false; } phrase.Clauses.push_back(clause); } CI18N::skipWhiteSpace(first, last); if (first == last || *first != '}') { uint32 line = countLine(doc, first); nlwarning("DT: in '%s' line %u: Missing block closing tag '}' in phrase %s\n", filename.c_str(), line, phrase.Identifier.c_str()); return false; } ++first; // handle hash value. if (forceRehash || !parseHashFromComment(phrase.Comments, phrase.HashValue)) { // the hash is not in the comment, compute it. phrase.HashValue = makePhraseHash(phrase); if (forceRehash) { // the has is perhaps in the comment ucstring::size_type pos = phrase.Comments.find(ucstring("// HASH_VALUE")); if (pos != ucstring::npos) { phrase.Comments = phrase.Comments.substr(0, pos); } } } // nldebug("DT : storing phrase '%s'", phrase.Identifier.c_str()); phrases.push_back(phrase); } // check identifier uniqueness { bool error = false; set unik; set::iterator it; for (uint i=0; i &phrases, bool removeDiffComments) { ucstring ret; vector::const_iterator first(phrases.begin()), last(phrases.end()); for (; first != last; ++first) { const TPhrase &p = *first; if (removeDiffComments) { string comment = p.Comments.toString(); vector lines; explode(comment, string("\n"), lines, true); uint i; for (i=0; i Avoid allocation / free vector strArray; // append a '\0' strArray.resize(str.size()+1); strArray[strArray.size()-1]= 0; memcpy(&strArray[0], &str[0], str.size()*sizeof(ucchar)); // **** Build array of lines. just point to strArray, and fill 0 where appropriated vector lines; lines.reserve(500); ucstring::size_type pos = 0; ucstring::size_type lastPos = 0; while ((pos = str.find(nl, lastPos)) != ucstring::npos) { if (pos>lastPos) { strArray[pos]= 0; // nldebug("Found line : [%s]", ucstring(&strArray[lastPos]).toString().c_str()); lines.push_back(&strArray[lastPos]); } lastPos = pos + 2; } // Must add last line if no \r\n ending if (lastPos < str.size()) { pos= str.size(); strArray[pos]= 0; // nldebug("Found line : [%s]", ucstring(&strArray[lastPos]).toString().c_str()); lines.push_back(&strArray[lastPos]); } // nldebug("Found %u lines", lines.size()); // **** Do 2 pass.1st count the cell number, then fill. => avoid reallocation uint newColCount= 0; uint i; for (i=0; i 0) { // look for the first non '* tagged' or 'DIFF_CMD' column uint nameCol = 0; while (nameCol < worksheet.ColCount && (*worksheet.getData(0, nameCol).begin() == uint16('*') || worksheet.getData(0, nameCol) == ucstring("DIFF_CMD"))) ++nameCol; if (nameCol < worksheet.ColCount ) { // ok we can check unikness bool error = false; set unik; set::iterator it; for (uint j=0; j columnOk; columnOk.resize(sheet.ColCount, false); for (uint k=1; k hashValue; hashValue.resize(worksheet.Data[0].size()); for (uint j=0; j 0 && hashValue[j] && (!worksheet.Data[i][j].empty() && worksheet.Data[i][j][0] != '_')) text += "_"; text += worksheet.Data[i][j]; if (j != worksheet.Data[i].size()-1) text += '\t'; } text += nl; } return text; } } // namespace STRING_MANAGER