BOOL CPatch::StripPrefixes(const CString& path) { int nSlashesMax = 0; for (int i=0; i<GetNumberOfFiles(); i++) { CString filename = GetFilename(i); filename.Replace('/','\\'); int nSlashes = filename.Replace('\\','/'); nSlashesMax = max(nSlashesMax,nSlashes); } for (int nStrip=1;nStrip<nSlashesMax;nStrip++) { m_nStrip = nStrip; if ( CountMatches(path) > GetNumberOfFiles()/3 ) { // Use current m_nStrip return TRUE; } } // Stripping doesn't help so reset it again m_nStrip = 0; return FALSE; }
CString GitPatch::CheckPatchPath(const CString& path) { // first check if the path already matches if (CountMatches(path) > (GetNumberOfFiles() / 3)) return path; CSysProgressDlg progress; CString tmp; progress.SetTitle(IDS_PATCH_SEARCHPATHTITLE); progress.SetShowProgressBar(false); tmp.LoadString(IDS_PATCH_SEARCHPATHLINE1); progress.SetLine(1, tmp); progress.ShowModeless(AfxGetMainWnd()); // now go up the tree and try again CString upperpath = path; while (upperpath.ReverseFind('\\')>0) { upperpath = upperpath.Left(upperpath.ReverseFind('\\')); progress.SetLine(2, upperpath, true); if (progress.HasUserCancelled()) return path; if (CountMatches(upperpath) > (GetNumberOfFiles()/3)) return upperpath; } // still no match found. So try sub folders bool isDir = false; CString subpath; CDirFileEnum filefinder(path); while (filefinder.NextFile(subpath, &isDir)) { if (progress.HasUserCancelled()) return path; if (!isDir) continue; if (GitAdminDir::IsAdminDirPath(subpath)) continue; progress.SetLine(2, subpath, true); if (CountMatches(subpath) > (GetNumberOfFiles()/3)) return subpath; } // if a patch file only contains newly added files // we can't really find the correct path. // But: we can compare paths strings without the filenames // and check if at least those match upperpath = path; while (upperpath.ReverseFind('\\')>0) { upperpath = upperpath.Left(upperpath.ReverseFind('\\')); progress.SetLine(2, upperpath, true); if (progress.HasUserCancelled()) return path; if (CountDirMatches(upperpath) > (GetNumberOfFiles()/3)) return upperpath; } return path; }
CString CPatch::CheckPatchPath(const CString& path) { //first check if the path already matches if (CountMatches(path) > (GetNumberOfFiles()/3)) return path; //now go up the tree and try again CString upperpath = path; while (upperpath.ReverseFind('\\')>0) { upperpath = upperpath.Left(upperpath.ReverseFind('\\')); if (CountMatches(upperpath) > (GetNumberOfFiles()/3)) return upperpath; } //still no match found. So try sub folders bool isDir = false; CString subpath; CDirFileEnum filefinder(path); while (filefinder.NextFile(subpath, &isDir)) { if (!isDir) continue; if (g_GitAdminDir.IsAdminDirPath(subpath)) continue; if (CountMatches(subpath) > (GetNumberOfFiles()/3)) return subpath; } // if a patch file only contains newly added files // we can't really find the correct path. // But: we can compare paths strings without the filenames // and check if at least those match upperpath = path; while (upperpath.ReverseFind('\\')>0) { upperpath = upperpath.Left(upperpath.ReverseFind('\\')); if (CountDirMatches(upperpath) > (GetNumberOfFiles()/3)) return upperpath; } return path; }
int CPatch::CountMatches(const CString& path) { int matches = 0; for (int i=0; i<GetNumberOfFiles(); ++i) { CString temp = GetFilename(i); temp.Replace('/', '\\'); if (PathIsRelative(temp)) temp = path + _T("\\")+ temp; if (PathFileExists(temp)) matches++; } return matches; }
int GitPatch::CountMatches(const CString& path) const { int matches = 0; for (int i=0; i<GetNumberOfFiles(); ++i) { CString temp = GetStrippedPath(i); temp.Replace('/', '\\'); if ((PathIsRelative(temp)) || ((temp.GetLength() > 1) && (temp[0]=='\\') && (temp[1]!='\\')) ) temp = path + _T("\\")+ temp; if (PathFileExists(temp)) ++matches; } return matches; }
int GitPatch::CountDirMatches(const CString& path) const { int matches = 0; for (int i=0; i<GetNumberOfFiles(); ++i) { CString temp = GetStrippedPath(i); temp.Replace('/', '\\'); if (PathIsRelative(temp)) temp = path + _T("\\")+ temp; // remove the filename temp = temp.Left(temp.ReverseFind('\\')); if (PathFileExists(temp)) ++matches; } return matches; }
BOOL CPatch::PatchFile(const CString& sPath, const CString& sSavePath, const CString& sBaseFile) { if (PathIsDirectory(sPath)) { m_sErrorMessage.Format(IDS_ERR_PATCH_INVALIDPATCHFILE, (LPCTSTR)sPath); return FALSE; } // find the entry in the patch file which matches the full path given in sPath. int nIndex = -1; // use the longest path that matches int nMaxMatch = 0; for (int i=0; i<GetNumberOfFiles(); i++) { CString temppath = sPath; CString temp = GetFilename(i); temppath.Replace('/', '\\'); temp.Replace('/', '\\'); if (temppath.Mid(temppath.GetLength()-temp.GetLength()-1, 1).CompareNoCase(_T("\\"))==0) { temppath = temppath.Right(temp.GetLength()); if ((temp.CompareNoCase(temppath)==0)) { if (nMaxMatch < temp.GetLength()) { nMaxMatch = temp.GetLength(); nIndex = i; } } } else if (temppath.CompareNoCase(temp)==0) { if ((nIndex < 0)&&(! temp.IsEmpty())) { nIndex = i; } } } if (nIndex < 0) { m_sErrorMessage.Format(IDS_ERR_PATCH_FILENOTINPATCH, (LPCTSTR)sPath); return FALSE; } CString sLine; CString sPatchFile = sBaseFile.IsEmpty() ? sPath : sBaseFile; if (PathFileExists(sPatchFile)) { g_crasher.AddFile((LPCSTR)(LPCTSTR)sPatchFile, (LPCSTR)(LPCTSTR)_T("File to patch")); } CFileTextLines PatchLines; CFileTextLines PatchLinesResult; PatchLines.Load(sPatchFile); PatchLinesResult = PatchLines; //.Copy(PatchLines); PatchLines.CopySettings(&PatchLinesResult); Chunks * chunks = m_arFileDiffs.GetAt(nIndex); for (int i=0; i<chunks->chunks.GetCount(); i++) { Chunk * chunk = chunks->chunks.GetAt(i); LONG lRemoveLine = chunk->lRemoveStart; LONG lAddLine = chunk->lAddStart; for (int j=0; j<chunk->arLines.GetCount(); j++) { CString sPatchLine = chunk->arLines.GetAt(j); EOL ending = chunk->arEOLs[j]; if ((m_UnicodeType != CFileTextLines::UTF8)&&(m_UnicodeType != CFileTextLines::UTF8BOM)) { if ((PatchLines.GetUnicodeType()==CFileTextLines::UTF8)||(m_UnicodeType == CFileTextLines::UTF8BOM)) { // convert the UTF-8 contents in CString sPatchLine into a CStringA sPatchLine = CUnicodeUtils::GetUnicode(CStringA(sPatchLine)); } } int nPatchState = (int)chunk->arLinesStates.GetAt(j); switch (nPatchState) { case PATCHSTATE_REMOVED: { if ((lAddLine > PatchLines.GetCount())||(PatchLines.GetCount()==0)) { m_sErrorMessage.Format(IDS_ERR_PATCH_DOESNOTMATCH, _T(""), (LPCTSTR)sPatchLine); return FALSE; } if (lAddLine == 0) lAddLine = 1; if ((sPatchLine.Compare(PatchLines.GetAt(lAddLine-1))!=0)&&(!HasExpandedKeyWords(sPatchLine))) { m_sErrorMessage.Format(IDS_ERR_PATCH_DOESNOTMATCH, (LPCTSTR)sPatchLine, (LPCTSTR)PatchLines.GetAt(lAddLine-1)); return FALSE; } if (lAddLine > PatchLines.GetCount()) { m_sErrorMessage.Format(IDS_ERR_PATCH_DOESNOTMATCH, (LPCTSTR)sPatchLine, _T("")); return FALSE; } PatchLines.RemoveAt(lAddLine-1); } break; case PATCHSTATE_ADDED: { if (lAddLine == 0) lAddLine = 1; PatchLines.InsertAt(lAddLine-1, sPatchLine, ending); lAddLine++; } break; case PATCHSTATE_CONTEXT: { if (lAddLine > PatchLines.GetCount()) { m_sErrorMessage.Format(IDS_ERR_PATCH_DOESNOTMATCH, _T(""), (LPCTSTR)sPatchLine); return FALSE; } if (lAddLine == 0) lAddLine++; if (lRemoveLine == 0) lRemoveLine++; if ((sPatchLine.Compare(PatchLines.GetAt(lAddLine-1))!=0) && (!HasExpandedKeyWords(sPatchLine)) && (lRemoveLine <= PatchLines.GetCount()) && (sPatchLine.Compare(PatchLines.GetAt(lRemoveLine-1))!=0)) { if ((lAddLine < PatchLines.GetCount())&&(sPatchLine.Compare(PatchLines.GetAt(lAddLine))==0)) lAddLine++; else if (((lAddLine + 1) < PatchLines.GetCount())&&(sPatchLine.Compare(PatchLines.GetAt(lAddLine+1))==0)) lAddLine += 2; else if ((lRemoveLine < PatchLines.GetCount())&&(sPatchLine.Compare(PatchLines.GetAt(lRemoveLine))==0)) lRemoveLine++; else { m_sErrorMessage.Format(IDS_ERR_PATCH_DOESNOTMATCH, (LPCTSTR)sPatchLine, (LPCTSTR)PatchLines.GetAt(lAddLine-1)); return FALSE; } } lAddLine++; lRemoveLine++; } break; default: ASSERT(FALSE); break; } // switch (nPatchState) } // for (j=0; j<chunk->arLines.GetCount(); j++) } // for (int i=0; i<chunks->chunks.GetCount(); i++) if (!sSavePath.IsEmpty()) { PatchLines.Save(sSavePath, false); } return TRUE; }