X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fio%2FSVNReportParser.cxx;h=72b6169310338b65a3a07800f7feca5c3671dbf2;hb=70c5d605641b628039f75cb8761ce783a17a5bdf;hp=f00973cf2fefc82bb1a9eb7fbc4d21281a3d3cd3;hpb=ecec803388bf6ef6aac4c451a0ff08518295ef73;p=simgear.git diff --git a/simgear/io/SVNReportParser.cxx b/simgear/io/SVNReportParser.cxx index f00973cf..72b61693 100644 --- a/simgear/io/SVNReportParser.cxx +++ b/simgear/io/SVNReportParser.cxx @@ -16,6 +16,10 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +#ifdef HAVE_CONFIG_H +# include +#endif + #include "SVNReportParser.hxx" #include @@ -30,11 +34,16 @@ #include "simgear/misc/sg_path.hxx" #include "simgear/misc/sg_dir.hxx" #include "simgear/debug/logstream.hxx" -#include "simgear/xml/xmlparse.h" #include "simgear/xml/easyxml.hxx" #include "simgear/misc/strutils.hxx" #include "simgear/package/md5.h" +#ifdef SYSTEM_EXPAT +# include +#else +# include "sg_expat.h" +#endif + #include "SVNDirectory.hxx" #include "SVNRepository.hxx" #include "DAVMultiStatus.hxx" @@ -97,12 +106,13 @@ namespace { const char* SVN_ADD_FILE_TAG = SVN_NS "add-file"; const char* SVN_TXDELTA_TAG = SVN_NS "txdelta"; const char* SVN_SET_PROP_TAG = SVN_NS "set-prop"; + const char* SVN_PROP_TAG = SVN_NS "prop"; const char* SVN_DELETE_ENTRY_TAG = SVN_NS "delete-entry"; const char* SVN_DAV_MD5_CHECKSUM = SUBVERSION_DAV_NS ":md5-checksum"; const char* DAV_HREF_TAG = DAV_NS "href"; - const char* DAV_CHECKED_IN_TAG = SVN_NS "checked-in"; + const char* DAV_CHECKED_IN_TAG = DAV_NS "checked-in"; const int svn_txdelta_source = 0; @@ -154,13 +164,9 @@ namespace { headerLength = p - _ptr; _ptr = p; - - if (sourceViewOffset != 0) { - cout << "sourceViewOffset:" << sourceViewOffset << endl; - } } - bool apply(std::vector& output, std::istream& source) + bool apply(std::vector& output, std::istream& source) { unsigned char* pEnd = _ptr + instructionLength; unsigned char* newData = pEnd; @@ -168,7 +174,7 @@ namespace { while (_ptr < pEnd) { int op = ((*_ptr >> 6) & 0x3); if (op >= 3) { - std::cerr << "weird opcode" << endl; + SG_LOG(SG_IO, SG_INFO, "SVNDeltaWindow: bad opcode:" << op); return false; } @@ -180,7 +186,7 @@ namespace { } if (length == 0) { - std::cerr << "malformed stream, 0 length" << std::endl; + SG_LOG(SG_IO, SG_INFO, "SVNDeltaWindow: malformed stream, 0 length" << op); return false; } @@ -190,12 +196,14 @@ namespace { } if (op == svn_txdelta_target) { - while (length > 0) { - output.push_back(output[offset++]); - --length; - } + // this is inefficent, but ranges can overlap. + while (length > 0) { + output.push_back(output[offset++]); + --length; + } } else if (op == svn_txdelta_new) { output.insert(output.end(), newData, newData + length); + newData += length; } else if (op == svn_txdelta_source) { source.seekg(offset); char* sourceBuf = (char*) malloc(length); @@ -203,6 +211,9 @@ namespace { source.read(sourceBuf, length); output.insert(output.end(), sourceBuf, sourceBuf + length); free(sourceBuf); + } else { + SG_LOG(SG_IO, SG_WARN, "bad opcode logic"); + return false; } } // of instruction loop @@ -233,7 +244,7 @@ class SVNReportParser::SVNReportParserPrivate public: SVNReportParserPrivate(SVNRepository* repo) : tree(repo), - status(SVNRepository::NO_ERROR), + status(SVNRepository::SVN_NO_ERROR), parserInited(false), currentPath(repo->fsBase()) { @@ -247,7 +258,7 @@ public: void startElement (const char * name, const char** attributes) { - if (status != SVNRepository::NO_ERROR) { + if (status != SVNRepository::SVN_NO_ERROR) { return; } @@ -264,12 +275,12 @@ public: string fileName(attrs.getValue("name")); SGPath filePath(Dir(currentPath).file(fileName)); currentPath = filePath; - - DAVResource* res = currentDir->collection()->childWithName(fileName); - if (!res || !filePath.exists()) { - // set error condition + + if (!filePath.exists()) { + fail(SVNRepository::SVN_ERROR_FILE_NOT_FOUND); + return; } - + inFile = true; } else if (!strcmp(name, SVN_ADD_DIRECTORY_TAG)) { string dirName(attrs.getValue("name")); @@ -297,10 +308,12 @@ public: } else if (!strcmp(name, SVN_DELETE_ENTRY_TAG)) { string entryName(attrs.getValue("name")); deleteEntry(entryName); - } else if (!strcmp(name, DAV_CHECKED_IN_TAG) || !strcmp(name, DAV_HREF_TAG)) { + } else if (!strcmp(name, DAV_CHECKED_IN_TAG) || + !strcmp(name, DAV_HREF_TAG) || + !strcmp(name, SVN_PROP_TAG)) { // don't warn on these ones } else { - //std::cerr << "unhandled element:" << name << std::endl; + //SG_LOG(SG_IO, SG_WARN, "SVNReportParser: unhandled tag:" << name); } } // of startElement @@ -326,11 +339,12 @@ public: bool decodeTextDelta(const SGPath& outputPath) { - string decoded = strutils::decodeBase64(txDeltaData); + std::vector output, decoded; + strutils::decodeBase64(txDeltaData, decoded); size_t bytesToDecode = decoded.size(); - std::vector output; - unsigned char* p = (unsigned char*) decoded.data(); - if (memcmp(decoded.data(), "SVN\0", DELTA_HEADER_SIZE) != 0) { + + unsigned char* p = decoded.data(); + if (memcmp(p, "SVN\0", DELTA_HEADER_SIZE) != 0) { return false; // bad header } @@ -340,6 +354,11 @@ public: source.open(outputPath.c_str(), std::ios::in | std::ios::binary); while (bytesToDecode > 0) { + if (!SVNDeltaWindow::isWindowComplete(p, bytesToDecode)) { + SG_LOG(SG_IO, SG_WARN, "SVN txdelta broken window"); + return false; + } + SVNDeltaWindow window(p); assert(bytesToDecode >= window.size()); window.apply(output, source); @@ -348,39 +367,40 @@ public: } source.close(); + std::ofstream f; f.open(outputPath.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); - f.write(output.data(), output.size()); - + f.write((char*) output.data(), output.size()); + // compute MD5 while we have the file in memory - MD5_CTX md5; - memset(&md5, 0, sizeof(MD5_CTX)); - MD5Init(&md5); - MD5Update(&md5, (unsigned char*) output.data(), output.size()); - MD5Final(&md5); - decodedFileMd5 = strutils::encodeHex(md5.digest, 16); + memset(&md5Context, 0, sizeof(SG_MD5_CTX)); + SG_MD5Init(&md5Context); + SG_MD5Update(&md5Context, (unsigned char*) output.data(), output.size()); + unsigned char digest[MD5_DIGEST_LENGTH]; + SG_MD5Final(digest, &md5Context); + decodedFileMd5 = strutils::encodeHex(digest, MD5_DIGEST_LENGTH); + return true; } void endElement (const char * name) { - if (status != SVNRepository::NO_ERROR) { + if (status != SVNRepository::SVN_NO_ERROR) { return; } assert(tagStack.back() == name); tagStack.pop_back(); + if (!strcmp(name, SVN_TXDELTA_TAG)) { if (!decodeTextDelta(currentPath)) { - fail(SVNRepository::ERROR_TXDELTA); + fail(SVNRepository::SVN_ERROR_TXDELTA); } } else if (!strcmp(name, SVN_ADD_FILE_TAG)) { - finishFile(currentDir->addChildFile(currentPath.file())); + finishFile(currentPath); } else if (!strcmp(name, SVN_OPEN_FILE_TAG)) { - DAVResource* res = currentDir->collection()->childWithName(currentPath.file()); - assert(res); - finishFile(res); + finishFile(currentPath); } else if (!strcmp(name, SVN_ADD_DIRECTORY_TAG)) { // pop directory currentPath = currentPath.dir(); @@ -400,41 +420,39 @@ public: } else if (!strcmp(name, SVN_DAV_MD5_CHECKSUM)) { // validate against (presumably) just written file if (decodedFileMd5 != md5Sum) { - fail(SVNRepository::ERROR_CHECKSUM); + fail(SVNRepository::SVN_ERROR_CHECKSUM); } } else if (!strcmp(name, SVN_OPEN_DIRECTORY_TAG)) { + currentDir->updateReportComplete(); if (currentDir->parent()) { // pop the collection stack currentDir = currentDir->parent(); } - currentDir->updateReportComplete(); currentPath = currentDir->fsPath(); } else { // std::cout << "element:" << name; } } - void finishFile(DAVResource* res) + void finishFile(const SGPath& path) { - res->setVersionName(currentVersionName); - res->setMD5(md5Sum); - currentPath = currentPath.dir(); + currentPath = path.dir(); inFile = false; } void data (const char * s, int length) { - if (status != SVNRepository::NO_ERROR) { + if (status != SVNRepository::SVN_NO_ERROR) { return; } if (tagStack.back() == SVN_SET_PROP_TAG) { - setPropValue += string(s, length); + setPropValue.append(s, length); } else if (tagStack.back() == SVN_TXDELTA_TAG) { - txDeltaData += string(s, length); + txDeltaData.append(s, length); } else if (tagStack.back() == SVN_DAV_MD5_CHECKSUM) { - md5Sum += string(s, length); + md5Sum.append(s, length); } } @@ -442,7 +460,7 @@ public: string tagN(const unsigned int n) const { - int sz = tagStack.size(); + size_t sz = tagStack.size(); if (n >= sz) { return string(); } @@ -471,6 +489,7 @@ public: bool inFile; unsigned int revision; + SG_MD5_CTX md5Context; string md5Sum, decodedFileMd5; std::string setPropName, setPropValue; }; @@ -525,7 +544,7 @@ SVNReportParser::~SVNReportParser() SVNRepository::ResultCode SVNReportParser::innerParseXML(const char* data, int size) { - if (_d->status != SVNRepository::NO_ERROR) { + if (_d->status != SVNRepository::SVN_NO_ERROR) { return _d->status; } @@ -537,19 +556,19 @@ SVNReportParser::innerParseXML(const char* data, int size) XML_ParserFree(_d->xmlParser); _d->parserInited = false; - return SVNRepository::ERROR_XML; + return SVNRepository::SVN_ERROR_XML; } else if (isEnd) { XML_ParserFree(_d->xmlParser); _d->parserInited = false; } - + return _d->status; } SVNRepository::ResultCode SVNReportParser::parseXML(const char* data, int size) { - if (_d->status != SVNRepository::NO_ERROR) { + if (_d->status != SVNRepository::SVN_NO_ERROR) { return _d->status; } @@ -567,7 +586,7 @@ SVNReportParser::parseXML(const char* data, int size) SVNRepository::ResultCode SVNReportParser::finishParse() { - if (_d->status != SVNRepository::NO_ERROR) { + if (_d->status != SVNRepository::SVN_NO_ERROR) { return _d->status; }