int CTortoiseGitBlameData::GetEncode(unsigned char *buff, int size, int *bomoffset)
{
	CFileTextLines textlines;
	CFileTextLines::UnicodeType type = textlines.CheckUnicodeType(buff, size);

	if (type == CFileTextLines::UTF8BOM)
	{
		*bomoffset = 3;
		return CP_UTF8;
	}
	if (type == CFileTextLines::UTF8)
		return CP_UTF8;

	if (type == CFileTextLines::UTF16_LE)
		return 1200;
	if (type == CFileTextLines::UTF16_LEBOM)
	{
		*bomoffset = 2;
		return 1200;
	}

	if (type == CFileTextLines::UTF16_BE)
		return 1201;
	if (type == CFileTextLines::UTF16_BEBOM)
	{
		*bomoffset = 2;
		return 1201;
	}

	return GetACP();
}
Beispiel #2
0
BOOL CPatch::OpenUnifiedDiffFile(const CString& filename)
{
    CCrashReport::Instance().AddFile2(filename, nullptr, _T("unified diff file"), CR_AF_MAKE_FILE_COPY);

    CFileTextLines PatchLines;
    if (!PatchLines.Load(filename))
    {
        m_sErrorMessage = PatchLines.GetErrorString();
        return FALSE;
    }
    FreeMemory();

    //now we got all the lines of the patch file
    //in our array - parsing can start...
    return ParsePatchFile(PatchLines);
}
Beispiel #3
0
int CPatch::PatchFile(int nIndex, const CString& sPatchPath, const CString& sSavePath, const CString& sBaseFile, const bool force)
{
	CString sPath = GetFullPath(sPatchPath, nIndex);
	if (PathIsDirectory(sPath))
	{
		m_sErrorMessage.Format(IDS_ERR_PATCH_INVALIDPATCHFILE, (LPCTSTR)sPath);
		return FALSE;
	}
	if (nIndex < 0)
	{
		m_sErrorMessage.Format(IDS_ERR_PATCH_FILENOTINPATCH, (LPCTSTR)sPath);
		return FALSE;
	}

	if (!force && sPath == _T("NUL") && PathFileExists(GetFullPath(sPatchPath, nIndex, 1)))
		return FALSE;

	if (GetFullPath(sPatchPath, nIndex, 1) == _T("NUL") && !PathFileExists(sPath))
		return 2;

	CString sLine;
	CString sPatchFile = sBaseFile.IsEmpty() ? sPath : sBaseFile;
	if (PathFileExists(sPatchFile))
	{
		CCrashReport::Instance().AddFile2(sPatchFile, NULL, _T("File to patch"), CR_AF_MAKE_FILE_COPY);
	}
	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;
}
Beispiel #4
0
BOOL CPatch::ParserGitPatch(CFileTextLines &PatchLines,int nIndex)
{
	CString sLine;
	EOL ending = EOL_NOENDING;

	int state = 0;
	Chunks * chunks = NULL;
	Chunk * chunk = NULL;
	int nAddLineCount = 0;
	int nRemoveLineCount = 0;
	int nContextLineCount = 0;
	for ( ;nIndex<PatchLines.GetCount(); nIndex++)
	{
		sLine = PatchLines.GetAt(nIndex);
		ending = PatchLines.GetLineEnding(nIndex);
		if (ending != EOL_NOENDING)
			ending = EOL_AUTOLINE;
		
		switch (state)
		{
			case 0:	
			{
				// diff --git
				if( sLine.Find(_T("diff --git"))==0)
				{
					if (chunks)
					{
						//this is a new file diff, so add the last one to 
						//our array.
						m_arFileDiffs.Add(chunks);
					}
					chunks = new Chunks();

				}
				
				//index
				if( sLine.Find(_T("index"))==0 )
				{
					int dotstart=sLine.Find(_T(".."));
					if(dotstart>=0)
					{
						chunks->sRevision = sLine.Mid(dotstart-7,7);
						chunks->sRevision2 = sLine.Mid(dotstart+2,7);
					}
				}

				//---
				if( sLine.Find(_T("--- "))==0 )
				{
					if (sLine.Left(3).Compare(_T("---"))!=0)
					{
						//no starting "---" found
						//seems to be either garbage or just
						//a binary file. So start over...
						state = 0;
						nIndex--;
						if (chunks)
						{
							delete chunks;
							chunks = NULL;
						}
						break;
					}
				
					sLine = sLine.Mid(3);	//remove the "---"
					sLine =sLine.Trim();
					//at the end of the filepath there's a revision number...
					int bracket = sLine.ReverseFind('(');
					if (bracket < 0)
					// some patch files can have another '(' char, especially ones created in Chinese OS
						bracket = sLine.ReverseFind(0xff08);
				
					if (bracket < 0)
					{
						if (chunks->sFilePath.IsEmpty())
							chunks->sFilePath = sLine.Trim();
					}
					else
						chunks->sFilePath = sLine.Left(bracket-1).Trim();
					
					if (chunks->sFilePath.Find('\t')>=0)
					{
						chunks->sFilePath = chunks->sFilePath.Left(chunks->sFilePath.Find('\t'));
					}
					if (chunks->sFilePath.Find(_T('"')) == 0 && chunks->sFilePath.ReverseFind(_T('"')) == chunks->sFilePath.GetLength() - 1)
						chunks->sFilePath=chunks->sFilePath.Mid(1, chunks->sFilePath.GetLength() - 2);
					if( chunks->sFilePath.Find(_T("a/")) == 0 )
						chunks->sFilePath=chunks->sFilePath.Mid(2);

					if( chunks->sFilePath.Find(_T("b/")) == 0 )
						chunks->sFilePath=chunks->sFilePath.Mid(2);


					chunks->sFilePath.Replace(_T('/'),_T('\\'));

					if (chunks->sFilePath == _T("\\dev\\null") || chunks->sFilePath == _T("/dev/null"))
						chunks->sFilePath  = _T("NUL");
				}
				
				// +++
				if( sLine.Find(_T("+++ ")) == 0 )
				{
					sLine = sLine.Mid(3);	//remove the "---"
					sLine =sLine.Trim();
				
					//at the end of the filepath there's a revision number...
					int bracket = sLine.ReverseFind('(');
					if (bracket < 0)
					// some patch files can have another '(' char, especially ones created in Chinese OS
						bracket = sLine.ReverseFind(0xff08);

					if (bracket < 0)
						chunks->sFilePath2 = sLine.Trim();
					else
						chunks->sFilePath2 = sLine.Left(bracket-1).Trim();
					if (chunks->sFilePath2.Find('\t')>=0)
					{
						chunks->sFilePath2 = chunks->sFilePath2.Left(chunks->sFilePath2.Find('\t'));
					}
					if (chunks->sFilePath2.Find(_T('"')) == 0 && chunks->sFilePath2.ReverseFind(_T('"')) == chunks->sFilePath2.GetLength() - 1)
						chunks->sFilePath2=chunks->sFilePath2.Mid(1, chunks->sFilePath2.GetLength() - 2);
					if( chunks->sFilePath2.Find(_T("a/")) == 0 )
						chunks->sFilePath2=chunks->sFilePath2.Mid(2);

					if( chunks->sFilePath2.Find(_T("b/")) == 0 )
						chunks->sFilePath2=chunks->sFilePath2.Mid(2);

					chunks->sFilePath2.Replace(_T('/'),_T('\\'));

					if (chunks->sFilePath2 == _T("\\dev\\null") || chunks->sFilePath2 == _T("/dev/null"))
						chunks->sFilePath2  = _T("NUL");
				}
				
				//@@ -xxx,xxx +xxx,xxx @@
				if( sLine.Find(_T("@@")) == 0 )
				{
					sLine = sLine.Mid(2);
					sLine = sLine.Trim();
					chunk = new Chunk();
					CString sRemove = sLine.Left(sLine.Find(' '));
					CString sAdd = sLine.Mid(sLine.Find(' '));
					chunk->lRemoveStart = (-_ttol(sRemove));
					if (sRemove.Find(',')>=0)
					{
						sRemove = sRemove.Mid(sRemove.Find(',')+1);
						chunk->lRemoveLength = _ttol(sRemove);
					}
					else
					{
						chunk->lRemoveStart = 0;
						chunk->lRemoveLength = (-_ttol(sRemove));
					}
					chunk->lAddStart = _ttol(sAdd);
					if (sAdd.Find(',')>=0)
					{
						sAdd = sAdd.Mid(sAdd.Find(',')+1);
						chunk->lAddLength = _ttol(sAdd);
					}
					else
					{
						chunk->lAddStart = 1;
						chunk->lAddLength = _ttol(sAdd);
					}
					
					state =5;
				}
			} 
		break;
		
		
		case 5: //[ |+|-] <sourceline>
			{
				//this line is either a context line (with a ' ' in front)
				//a line added (with a '+' in front)
				//or a removed line (with a '-' in front)
				TCHAR type;
				if (sLine.IsEmpty())
					type = ' ';
				else
					type = sLine.GetAt(0);
				if (type == ' ')
				{
					//it's a context line - we don't use them here right now
					//but maybe in the future the patch algorithm can be
					//extended to use those in case the file to patch has
					//already changed and no base file is around...
					chunk->arLines.Add(RemoveUnicodeBOM(sLine.Mid(1)));
					chunk->arLinesStates.Add(PATCHSTATE_CONTEXT);
					chunk->arEOLs.push_back(ending);
					nContextLineCount++;
				}
				else if (type == '\\')
				{
					//it's a context line (sort of): 
					//warnings start with a '\' char (e.g. "\ No newline at end of file")
					//so just ignore this...
				}
				else if (type == '-')
				{
					//a removed line
					chunk->arLines.Add(RemoveUnicodeBOM(sLine.Mid(1)));
					chunk->arLinesStates.Add(PATCHSTATE_REMOVED);
					chunk->arEOLs.push_back(ending);
					nRemoveLineCount++;
				}
				else if (type == '+')
				{
					//an added line
					chunk->arLines.Add(RemoveUnicodeBOM(sLine.Mid(1)));
					chunk->arLinesStates.Add(PATCHSTATE_ADDED);
					chunk->arEOLs.push_back(ending);
					nAddLineCount++;
				}
				else
				{
					//none of those lines! what the hell happened here?
					m_sErrorMessage.Format(IDS_ERR_PATCH_UNKOWNLINETYPE, nIndex);
					goto errorcleanup;
				}
				if ((chunk->lAddLength == (nAddLineCount + nContextLineCount)) &&
					chunk->lRemoveLength == (nRemoveLineCount + nContextLineCount))
				{
					//chunk is finished
					if (chunks)
						chunks->chunks.Add(chunk);
					else
						delete chunk;
					chunk = NULL;
					nAddLineCount = 0;
					nContextLineCount = 0;
					nRemoveLineCount = 0;
					state = 0;
				}
			} 
		break;
		default:
			ASSERT(FALSE);
		} // switch (state) 
	} // for ( ;nIndex<m_PatchLines.GetCount(); nIndex++) 
	if (chunk)
	{
		m_sErrorMessage.LoadString(IDS_ERR_PATCH_CHUNKMISMATCH);
		goto errorcleanup;
	}
	if (chunks)
		m_arFileDiffs.Add(chunks);
	return TRUE;

errorcleanup:
	if (chunk)
		delete chunk;
	if (chunks)
	{
		for (int i=0; i<chunks->chunks.GetCount(); i++)
		{
			delete chunks->chunks.GetAt(i);
		}
		chunks->chunks.RemoveAll();
		delete chunks;
	}
	FreeMemory();
	return FALSE;
}
Beispiel #5
0
BOOL CPatch::OpenUnifiedDiffFile(const CString& filename)
{
	CString sLine;
	EOL ending = EOL_NOENDING;
	INT_PTR nIndex = 0;
	INT_PTR nLineCount = 0;
	CCrashReport::Instance().AddFile2(filename, NULL, _T("unified diff file"), CR_AF_MAKE_FILE_COPY);

	CFileTextLines PatchLines;
	if (!PatchLines.Load(filename))
	{
		m_sErrorMessage = PatchLines.GetErrorString();
		return FALSE;
	}
	m_UnicodeType = PatchLines.GetUnicodeType();
	FreeMemory();
	nLineCount = PatchLines.GetCount();
	//now we got all the lines of the patch file
	//in our array - parsing can start...

	for(nIndex=0;nIndex<PatchLines.GetCount();nIndex++)
	{
		sLine = PatchLines.GetAt(nIndex);
		if(sLine.Left(10).Compare(_T("diff --git")) == 0)
		{
			this->m_IsGitPatch=true;
			break;
		}
	}

	//first, skip possible garbage at the beginning
	//garbage is finished when a line starts with "Index: "
	//and the next line consists of only "=" characters
	if( !m_IsGitPatch )
	{
		for (nIndex=0; nIndex<PatchLines.GetCount(); nIndex++)
		{
			sLine = PatchLines.GetAt(nIndex);

			if (sLine.Left(4).Compare(_T("--- "))==0)
				break;
			if ((nIndex+1)<PatchLines.GetCount())
			{
				sLine = PatchLines.GetAt(nIndex+1);

				if(sLine.IsEmpty()&&m_IsGitPatch)
					continue;

				sLine.Remove('=');
				if (sLine.IsEmpty())
					break;
			}
		}
	}

	if ((PatchLines.GetCount()-nIndex) < 2)
	{
		//no file entry found.
		m_sErrorMessage.LoadString(IDS_ERR_PATCH_NOINDEX);
		return FALSE;
	}

	if( m_IsGitPatch )
		return ParserGitPatch(PatchLines,nIndex);

	//from this point on we have the real unified diff data
	int state = 0;
	Chunks * chunks = NULL;
	Chunk * chunk = NULL;
	int nAddLineCount = 0;
	int nRemoveLineCount = 0;
	int nContextLineCount = 0;
	for ( ;nIndex<PatchLines.GetCount(); nIndex++)
	{
		sLine = PatchLines.GetAt(nIndex);
		ending = PatchLines.GetLineEnding(nIndex);
		if (ending != EOL_NOENDING)
			ending = EOL_AUTOLINE;
		if (state == 0)
		{
			if ((sLine.Left(4).Compare(_T("--- "))==0)&&((sLine.Find('\t') >= 0)||this->m_IsGitPatch))
			{
				state = 2;
				if (chunks)
				{
					//this is a new file diff, so add the last one to 
					//our array.
					m_arFileDiffs.Add(chunks);
				}
				chunks = new Chunks();
				
				int nTab = sLine.Find('\t');

				int filestart = 4;
				if(m_IsGitPatch)
				{
					nTab=sLine.GetLength();
					filestart = 6;
				}

				if (nTab >= 0)
				{
					chunks->sFilePath = sLine.Mid(filestart, nTab-filestart).Trim();
				}
			}
		}
		switch (state)
		{
		case 0:	//Index: <filepath>
			{
				CString nextLine;
				if ((nIndex+1)<PatchLines.GetCount())
				{
					nextLine = PatchLines.GetAt(nIndex+1);
					if (!nextLine.IsEmpty())
					{
						nextLine.Remove('=');
						if (nextLine.IsEmpty())
						{
							if (chunks)
							{
								//this is a new file diff, so add the last one to 
								//our array.
								m_arFileDiffs.Add(chunks);
							}
							chunks = new Chunks();
							int nColon = sLine.Find(':');
							if (nColon >= 0)
							{
								chunks->sFilePath = sLine.Mid(nColon+1).Trim();
								if (chunks->sFilePath.Find('\t')>=0)
									chunks->sFilePath.Left(chunks->sFilePath.Find('\t')).TrimRight();
								if (chunks->sFilePath.Right(9).Compare(_T("(deleted)"))==0)
									chunks->sFilePath.Left(chunks->sFilePath.GetLength()-9).TrimRight();
								if (chunks->sFilePath.Right(7).Compare(_T("(added)"))==0)
									chunks->sFilePath.Left(chunks->sFilePath.GetLength()-7).TrimRight();
							}
							state++;
						}
					}
				}
				if (state == 0)
				{
					if (nIndex > 0)
					{
						nIndex--;
						state = 4;
						if (chunks == NULL)
						{
							//the line
							//Index: <filepath>
							//was not found at the start of a file diff!
							break;
						}
					}
				}
			} 
		break;
		case 1:	//====================
			{
				sLine.Remove('=');
				if (sLine.IsEmpty())
				{
					// if the next line is already the start of the chunk,
					// then the patch/diff file was not created by svn. But we
					// still try to use it
					if (PatchLines.GetCount() > (nIndex + 1))
					{

						if (PatchLines.GetAt(nIndex+1).Left(2).Compare(_T("@@"))==0)
						{
							state += 2;
						}
					}
					state++;
				}
				else
				{
					//the line
					//=========================
					//was not found
					m_sErrorMessage.Format(IDS_ERR_PATCH_NOEQUATIONCHARLINE, nIndex);
					goto errorcleanup;
				}
			}
		break;
		case 2:	//--- <filepath>
			{
				if (sLine.Left(3).Compare(_T("---"))!=0)
				{
					//no starting "---" found
					//seems to be either garbage or just
					//a binary file. So start over...
					state = 0;
					nIndex--;
					if (chunks)
					{
						delete chunks;
						chunks = NULL;
					}
					break;
				}
				sLine = sLine.Mid(3);	//remove the "---"
				sLine =sLine.Trim();
				//at the end of the filepath there's a revision number...
				int bracket = sLine.ReverseFind('(');
				if (bracket < 0)
					// some patch files can have another '(' char, especially ones created in Chinese OS
					bracket = sLine.ReverseFind(0xff08);
				CString num = sLine.Mid(bracket);		//num = "(revision xxxxx)"
				num = num.Mid(num.Find(' '));
				num = num.Trim(_T(" )"));
				// here again, check for the Chinese bracket
				num = num.Trim(0xff09);
				chunks->sRevision = num;
				if (bracket < 0)
				{
					if (chunks->sFilePath.IsEmpty())
						chunks->sFilePath = sLine.Trim();
				}
				else
					chunks->sFilePath = sLine.Left(bracket-1).Trim();
				if (chunks->sFilePath.Find('\t')>=0)
				{
					chunks->sFilePath = chunks->sFilePath.Left(chunks->sFilePath.Find('\t'));
				}
				state++;
			}
		break;
		case 3:	//+++ <filepath>
			{
				if (sLine.Left(3).Compare(_T("+++"))!=0)
				{
					//no starting "+++" found
					m_sErrorMessage.Format(IDS_ERR_PATCH_NOADDFILELINE, nIndex);
					goto errorcleanup;
				}
				sLine = sLine.Mid(3);	//remove the "---"
				sLine =sLine.Trim();
				//at the end of the filepath there's a revision number...
				int bracket = sLine.ReverseFind('(');
				if (bracket < 0)
					// some patch files can have another '(' char, especially ones created in Chinese OS
					bracket = sLine.ReverseFind(0xff08);
				CString num = sLine.Mid(bracket);		//num = "(revision xxxxx)"
				num = num.Mid(num.Find(' '));
				num = num.Trim(_T(" )"));
				// here again, check for the Chinese bracket
				num = num.Trim(0xff09);
				chunks->sRevision2 = num;
				if (bracket < 0)
					chunks->sFilePath2 = sLine.Trim();
				else
					chunks->sFilePath2 = sLine.Left(bracket-1).Trim();
				if (chunks->sFilePath2.Find('\t')>=0)
				{
					chunks->sFilePath2 = chunks->sFilePath2.Left(chunks->sFilePath2.Find('\t'));
				}
				state++;
			}
		break;
		case 4:	//@@ -xxx,xxx +xxx,xxx @@
			{
				//start of a new chunk
				if (sLine.Left(2).Compare(_T("@@"))!=0)
				{
					//chunk doesn't start with "@@"
					//so there's garbage in between two file diffs
					state = 0;
					if (chunk)
					{
						delete chunk;
						chunk = 0;
						if (chunks)
						{
							for (int i=0; i<chunks->chunks.GetCount(); i++)
							{
								delete chunks->chunks.GetAt(i);
							}
							chunks->chunks.RemoveAll();
							delete chunks;
							chunks = NULL;
						}
					}
					break;		//skip the garbage
				}
				sLine = sLine.Mid(2);
				sLine = sLine.Trim();
				chunk = new Chunk();
				CString sRemove = sLine.Left(sLine.Find(' '));
				CString sAdd = sLine.Mid(sLine.Find(' '));
				chunk->lRemoveStart = (-_ttol(sRemove));
				if (sRemove.Find(',')>=0)
				{
					sRemove = sRemove.Mid(sRemove.Find(',')+1);
					chunk->lRemoveLength = _ttol(sRemove);
				}
				else
				{
					chunk->lRemoveStart = 0;
					chunk->lRemoveLength = (-_ttol(sRemove));
				}
				chunk->lAddStart = _ttol(sAdd);
				if (sAdd.Find(',')>=0)
				{
					sAdd = sAdd.Mid(sAdd.Find(',')+1);
					chunk->lAddLength = _ttol(sAdd);
				}
				else
				{
					chunk->lAddStart = 1;
					chunk->lAddLength = _ttol(sAdd);
				}
				state++;
			}
		break;
		case 5: //[ |+|-] <sourceline>
			{
				//this line is either a context line (with a ' ' in front)
				//a line added (with a '+' in front)
				//or a removed line (with a '-' in front)
				TCHAR type;
				if (sLine.IsEmpty())
					type = ' ';
				else
					type = sLine.GetAt(0);
				if (type == ' ')
				{
					//it's a context line - we don't use them here right now
					//but maybe in the future the patch algorithm can be
					//extended to use those in case the file to patch has
					//already changed and no base file is around...
					chunk->arLines.Add(RemoveUnicodeBOM(sLine.Mid(1)));
					chunk->arLinesStates.Add(PATCHSTATE_CONTEXT);
					chunk->arEOLs.push_back(ending);
					nContextLineCount++;
				}
				else if (type == '\\')
				{
					//it's a context line (sort of): 
					//warnings start with a '\' char (e.g. "\ No newline at end of file")
					//so just ignore this...
				}
				else if (type == '-')
				{
					//a removed line
					chunk->arLines.Add(RemoveUnicodeBOM(sLine.Mid(1)));
					chunk->arLinesStates.Add(PATCHSTATE_REMOVED);
					chunk->arEOLs.push_back(ending);
					nRemoveLineCount++;
				}
				else if (type == '+')
				{
					//an added line
					chunk->arLines.Add(RemoveUnicodeBOM(sLine.Mid(1)));
					chunk->arLinesStates.Add(PATCHSTATE_ADDED);
					chunk->arEOLs.push_back(ending);
					nAddLineCount++;
				}
				else
				{
					//none of those lines! what the hell happened here?
					m_sErrorMessage.Format(IDS_ERR_PATCH_UNKOWNLINETYPE, nIndex);
					goto errorcleanup;
				}
				if ((chunk->lAddLength == (nAddLineCount + nContextLineCount)) &&
					chunk->lRemoveLength == (nRemoveLineCount + nContextLineCount))
				{
					//chunk is finished
					if (chunks)
						chunks->chunks.Add(chunk);
					else
						delete chunk;
					chunk = NULL;
					nAddLineCount = 0;
					nContextLineCount = 0;
					nRemoveLineCount = 0;
					state = 0;
				}
			} 
		break;
		default:
			ASSERT(FALSE);
		} // switch (state) 
	} // for ( ;nIndex<m_PatchLines.GetCount(); nIndex++) 
	if (chunk)
	{
		m_sErrorMessage.LoadString(IDS_ERR_PATCH_CHUNKMISMATCH);
		goto errorcleanup;
	}
	if (chunks)
		m_arFileDiffs.Add(chunks);
	return TRUE;
errorcleanup:
	if (chunk)
		delete chunk;
	if (chunks)
	{
		for (int i=0; i<chunks->chunks.GetCount(); i++)
		{
			delete chunks->chunks.GetAt(i);
		}
		chunks->chunks.RemoveAll();
		delete chunks;
	}
	FreeMemory();
	return FALSE;
}
Beispiel #6
0
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;
}