void CTortoiseGitBlameData::ParseBlameOutput(BYTE_VECTOR &data, CGitHashMap & HashToRev, DWORD dateFormat, bool bRelativeTimes) { std::map<CGitHash, CString> hashToFilename; std::vector<CGitHash> hashes; std::vector<int> originalLineNumbers; std::vector<CString> filenames; std::vector<BYTE_VECTOR> rawLines; std::vector<CString> authors; std::vector<CString> dates; CGitHash hash; int originalLineNumber = 0; int finalLineNumber = 0; int numberOfSubsequentLines = 0; CString filename; int pos = 0; bool expectHash = true; while (pos >= 0 && (size_t)pos < data.size()) { if (data[pos] == 0) { ++pos; continue; } int lineBegin = pos; int lineEnd = data.find('\n', lineBegin); if (lineEnd < 0) lineEnd = (int)data.size(); if (lineEnd > lineBegin) { if (data[lineBegin] != '\t') { if (expectHash) { expectHash = false; if (lineEnd - lineBegin > 40) { hash.ConvertFromStrA((char*)&data[lineBegin]); int hashEnd = lineBegin + 40; int originalLineNumberBegin = hashEnd + 1; int originalLineNumberEnd = data.find(' ', originalLineNumberBegin); if (originalLineNumberEnd >= 0) { originalLineNumber = atoi(CStringA((LPCSTR)&data[originalLineNumberBegin], originalLineNumberEnd - originalLineNumberBegin)); int finalLineNumberBegin = originalLineNumberEnd + 1; int finalLineNumberEnd = (numberOfSubsequentLines == 0) ? data.find(' ', finalLineNumberBegin) : lineEnd; if (finalLineNumberEnd >= 0) { finalLineNumber = atoi(CStringA((LPCSTR)&data[finalLineNumberBegin], finalLineNumberEnd - finalLineNumberBegin)); if (numberOfSubsequentLines == 0) { int numberOfSubsequentLinesBegin = finalLineNumberEnd + 1; int numberOfSubsequentLinesEnd = lineEnd; numberOfSubsequentLines = atoi(CStringA((LPCSTR)&data[numberOfSubsequentLinesBegin], numberOfSubsequentLinesEnd - numberOfSubsequentLinesBegin)); } } else { // parse error finalLineNumber = 0; numberOfSubsequentLines = 0; } } else { // parse error finalLineNumber = 0; numberOfSubsequentLines = 0; } auto it = hashToFilename.find(hash); if (it != hashToFilename.end()) filename = it->second; else filename.Empty(); } else { // parse error finalLineNumber = 0; numberOfSubsequentLines = 0; } } else { int tokenBegin = lineBegin; int tokenEnd = data.find(' ', tokenBegin); if (tokenEnd >= 0) { if (!strncmp("filename", (const char*)&data[tokenBegin], tokenEnd - tokenBegin)) { int filenameBegin = tokenEnd + 1; int filenameEnd = lineEnd; CStringA filenameA = CStringA((LPCSTR)&data[filenameBegin], filenameEnd - filenameBegin); filename = UnquoteFilename(filenameA); auto r = hashToFilename.insert(std::make_pair(hash, filename)); if (!r.second) { r.first->second = filename; } } } } } else { expectHash = true; // remove <TAB> at start BYTE_VECTOR line; if (lineEnd - 1 > lineBegin) line.append(&data[lineBegin + 1], lineEnd-lineBegin - 1); hashes.push_back(hash); filenames.push_back(filename); originalLineNumbers.push_back(originalLineNumber); rawLines.push_back(line); --numberOfSubsequentLines; } } pos = lineEnd + 1; } for (auto it = hashes.begin(), it_end = hashes.end(); it != it_end; ++it) { CGitHash hash = *it; CString err; GitRev* pRev = GetRevForHash(HashToRev, hash, &err); if (pRev) { authors.push_back(pRev->GetAuthorName()); dates.push_back(CLoglistUtils::FormatDateAndTime(pRev->GetAuthorDate(), dateFormat, true, bRelativeTimes)); } else { MessageBox(nullptr, err, _T("TortoiseGit"), MB_ICONERROR); authors.push_back(CString()); dates.push_back(CString()); } } m_Hash.swap(hashes); m_OriginalLineNumbers.swap(originalLineNumbers); m_Filenames.swap(filenames); m_RawLines.swap(rawLines); m_Authors.swap(authors); m_Dates.swap(dates); // reset detected and applied encoding m_encode = -1; m_Utf8Lines.clear(); }
void CTortoiseGitBlameData::ParseBlameOutput(BYTE_VECTOR &data, CGitHashMap & HashToRev, DWORD dateFormat, bool bRelativeTimes) { std::unordered_map<CGitHash, CString> hashToFilename; std::vector<CGitHash> hashes; std::vector<int> originalLineNumbers; std::vector<CString> filenames; std::vector<BYTE_VECTOR> rawLines; std::vector<CString> authors; std::vector<CString> dates; CGitHash hash; int originalLineNumber = 0; int numberOfSubsequentLines = 0; CString filename; size_t pos = 0; bool expectHash = true; while (pos < data.size()) { if (data[pos] == 0) { ++pos; continue; } size_t lineBegin = pos; size_t lineEnd = data.find('\n', lineBegin); if (lineEnd == BYTE_VECTOR::npos) lineEnd = data.size(); if (lineEnd > lineBegin) { if (data[lineBegin] != '\t') { if (expectHash) { expectHash = false; if (lineEnd - lineBegin > 2 * GIT_HASH_SIZE) { hash = CGitHash::FromHexStr(reinterpret_cast<char*>(&data[lineBegin])); size_t hashEnd = lineBegin + 2 * GIT_HASH_SIZE; size_t originalLineNumberBegin = hashEnd + 1; size_t originalLineNumberEnd = data.find(' ', originalLineNumberBegin); if (originalLineNumberEnd != BYTE_VECTOR::npos) { originalLineNumber = atoi(CStringA(reinterpret_cast<LPCSTR>(&data[originalLineNumberBegin]), static_cast<int>(originalLineNumberEnd - originalLineNumberBegin))); size_t finalLineNumberBegin = originalLineNumberEnd + 1; size_t finalLineNumberEnd = (numberOfSubsequentLines == 0) ? data.find(' ', finalLineNumberBegin) : lineEnd; if (finalLineNumberEnd != BYTE_VECTOR::npos) { if (numberOfSubsequentLines == 0) { size_t numberOfSubsequentLinesBegin = finalLineNumberEnd + 1; size_t numberOfSubsequentLinesEnd = lineEnd; numberOfSubsequentLines = atoi(CStringA(reinterpret_cast<LPCSTR>(&data[numberOfSubsequentLinesBegin]), static_cast<int>(numberOfSubsequentLinesEnd - numberOfSubsequentLinesBegin))); } } else { // parse error numberOfSubsequentLines = 0; } } else { // parse error numberOfSubsequentLines = 0; } auto it = hashToFilename.find(hash); if (it != hashToFilename.end()) filename = it->second; else filename.Empty(); } else { // parse error numberOfSubsequentLines = 0; } } else { size_t tokenBegin = lineBegin; size_t tokenEnd = data.find(' ', tokenBegin); if (tokenEnd != BYTE_VECTOR::npos) { if (!strncmp("filename", reinterpret_cast<const char*>(&data[tokenBegin]), tokenEnd - tokenBegin)) { size_t filenameBegin = tokenEnd + 1; size_t filenameEnd = lineEnd; CStringA filenameA = CStringA(reinterpret_cast<LPCSTR>(&data[filenameBegin]), static_cast<int>(filenameEnd - filenameBegin)); filename = UnquoteFilename(filenameA); auto r = hashToFilename.emplace(hash, filename); if (!r.second) { r.first->second = filename; } } } } } else { expectHash = true; // remove <TAB> at start BYTE_VECTOR line; if (lineEnd - 1 > lineBegin) line.append(&data[lineBegin + 1], lineEnd-lineBegin - 1); while (!line.empty() && line[line.size() - 1] == 13) line.pop_back(); hashes.push_back(hash); filenames.push_back(filename); originalLineNumbers.push_back(originalLineNumber); rawLines.push_back(line); --numberOfSubsequentLines; } } pos = lineEnd + 1; } for (const auto& hash2 : hashes) { CString err; GitRev* pRev = GetRevForHash(HashToRev, hash2, &err); if (pRev) { authors.push_back(pRev->GetAuthorName()); dates.push_back(CLoglistUtils::FormatDateAndTime(pRev->GetAuthorDate(), dateFormat, true, bRelativeTimes)); } else { MessageBox(nullptr, err, L"TortoiseGit", MB_ICONERROR); authors.emplace_back(); dates.emplace_back(); } } m_Hash.swap(hashes); m_OriginalLineNumbers.swap(originalLineNumbers); m_Filenames.swap(filenames); m_RawLines.swap(rawLines); m_Authors.swap(authors); m_Dates.swap(dates); // reset detected and applied encoding m_encode = -1; m_Utf8Lines.clear(); }