⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 diffengine.cpp

📁 类似VC自带的那个windeff,来源于codeproject
💻 CPP
字号:

#include "stdafx.h"
#include "FilePartition.h"
#include "DiffEngine.h"



CDiffEngine::CDiffEngine()
{
	m_szColorText		= "#888888"; // default colors
	m_szColorBackground = "white";
	m_szColorChanged	= "#FFFFBB";
	m_szColorAdded		= "#BBFFBB";
	m_szColorDeleted	= "#FFBBBB";

	m_szFooter = "<br><font size='-2' color='#BBBBBB'>shanzy Designed,2006</font>";
}

// compare f1 (old version) with f2 (new version)
// and build two new copies of those file objects with status on a line by line basis
//
BOOL CDiffEngine::Diff(	/*in*/CFilePartition &f1, /*in*/CFilePartition &f2,
						/*out*/CFilePartition &f1_bis, /*out*/CFilePartition &f2_bis)
{
	f1_bis.SetName( f1.GetName() );
	f2_bis.SetName( f2.GetName() );

	long nbf1Lines = f1.GetNBLines();
	long nbf2Lines = f2.GetNBLines();

	// special empty file case
	if ( nbf1Lines==0 )
	{
		long nLinef2 = 0;
		CString s;
		while ( nLinef2<nbf2Lines )
		{
			f1_bis.AddBlankLine();
			f2_bis.AddString( f2.GetRawLine(nLinef2++), Normal);
		}
		return TRUE;
	}

	long i = 0;
	long nf2CurrentLine = 0;

	while ( i<nbf1Lines )
	{
		// process this line (and possibly update indexes as well)
		long nLinef2 = nf2CurrentLine;

		if ( nLinef2 >= nbf2Lines )
		{
			// it's time to end the game now
			while ( i < nbf1Lines )
			{
				f1_bis.AddString( f1.GetRawLine(i), Deleted);
				f2_bis.AddBlankLine();
				i++;
			}
			break;
		}

		if ( f1.MatchLine(i, f2, /*out*/nLinef2) )
		{
			BOOL bDeleted = FALSE;
			if (nLinef2 > nf2CurrentLine)
			{
				long itmp = nf2CurrentLine;
				bDeleted = f2.MatchLine(nf2CurrentLine, f1, /*out*/itmp) && (itmp<nLinef2);
				if (bDeleted)
				{
					long j = itmp - i;
					while ( j>0 )
					{
						f1_bis.AddString( f1.GetRawLine(i), Deleted);
						f2_bis.AddBlankLine();

						i++;
						j--;
					}
					// please note nf2CurrentLine is not updated

					continue; // jump here to loop iteration
				}
			}

			// matched, so either the lines were identical, or f2 has added one or more lines
			if (nLinef2 > nf2CurrentLine)
			{
				// add blank lines to f1_bis
				long j = nLinef2 - nf2CurrentLine;
				while ( j>0 )
				{
					f1_bis.AddBlankLine();
					f2_bis.AddString( f2.GetRawLine(nLinef2-j), Added );

					j--;
				}
			}

			// exactly matched
			f1_bis.AddString( f1.GetRawLine(i), Normal);
			f2_bis.AddString( f2.GetRawLine(nLinef2), Normal);

			nf2CurrentLine = nLinef2 + 1; // next line in f2

		}
		else
		{
			// this line is not found at all in f2, either it's because it has been changed, or even deleted
			long nLinef1 = i;
			if ( f2.MatchLine(nLinef2, f1, /*out*/nLinef1) )
			{
				// the dual line in f2 can be found in f1, that's because
				// the current line in f1 has been deleted
				f1_bis.AddString( f1.GetRawLine(i), Deleted);
				f2_bis.AddBlankLine();

				// this whole block is flagged as deleted
				if (nLinef1>i+1)
				{
					long j = nLinef1 - (i+1);
					while ( j>0 )
					{
						i++;

						f1_bis.AddString( f1.GetRawLine(i), Deleted);
						f2_bis.AddBlankLine();

						j--;
					}
				}

				// note : nf2CurrentLine is not incremented
			}
			else
			{
				// neither added, nor deleted, so it's flagged as changed
				f1_bis.AddString( f1.GetRawLine(i), Changed);
				f2_bis.AddString( f2.GetRawLine(nLinef2), Changed);

				nf2CurrentLine = nLinef2 + 1; // next line in f2
			}
		}

		i++; // next line in f1
	}

	// are there any remaining lines from f2?
	while ( nf2CurrentLine < nbf2Lines )
	{
		f1_bis.AddBlankLine();
		f2_bis.AddString( f2.GetRawLine(nf2CurrentLine), Added );

		nf2CurrentLine++;
	}


	return TRUE;
}







// build html report
//



void CDiffEngine::SetTitles(CString &szHeader, CString &szFooter)
{
	m_szHeader = szHeader;
	m_szFooter = szFooter;
}

void CDiffEngine::SetColorStyles(CString &szText, CString &szBackground, CString &szChanged, CString &szAdded, CString &szDeleted)
{
	m_szColorText = szText;
	m_szColorBackground = szBackground;
	m_szColorChanged = szChanged;
	m_szColorAdded = szAdded;
	m_szColorDeleted = szDeleted;
}

CString CDiffEngine::Serialize(	/*in*/CFilePartition &f1, 
								/*in*/CFilePartition &f2)
{

	// eval amount of differences between the two files
	int nAdded_f1, nChanged_f1, nDeleted_f1;
	f1.HowManyChanges(/*out*/nAdded_f1, /*out*/nChanged_f1, /*out*/nDeleted_f1);
	int nAdded_f2, nChanged_f2, nDeleted_f2;
	f2.HowManyChanges(/*out*/nAdded_f2, /*out*/nChanged_f2, /*out*/nDeleted_f2);

	int nTotal = nAdded_f1 + nDeleted_f1 + nChanged_f1 + nAdded_f2 + nDeleted_f2;

	if (nTotal==0)
		m_szHeader += "<font size=-1><b>文件一样!</font><br>";
	else
	{
		TCHAR szTmp[128];
		sprintf(szTmp,"<font size=-1><b>%d 处不同! </font><br>", nTotal);
		m_szHeader += szTmp;
	}



	// write html header
	CString s = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n" \
				"<!-- 文件比较结果, (c) shanzy -- 2006 -->\r\n" \
				"<HTML>\r\n" \
				"<HEAD>\r\n" \
				"<TITLE> 文件比较 </TITLE>\r\n" \
				"<style type='text/css'>\r\n"\
				"<!--\r\n" \
				".N { background-color:white; }\r\n" \
				".C { background-color:" + m_szColorChanged + "; }\r\n" \
				".A { background-color:" + m_szColorAdded + "; }\r\n" \
				".D { background-color:" + m_szColorDeleted + "; }\r\n" \
				"-->\r\n" \
				"</style>\r\n" \
				"</HEAD>\r\n" \
				"\r\n" \
				"<BODY BGCOLOR='#FFFFFF'>\r\n" \
				"\r\n" + m_szHeader + \
				"<table border=0 bgcolor=0 cellpadding=1 cellspacing=1 width=100%><tr><td>\r\n" \
				"<table width=100% bgcolor=white border=0 cellpadding=0 cellspacing=0>\r\n" \
				"<tr bgColor='#EEEEEE' style='color:0'><td width=50%>旧版本(第1个文件)</td><td width=50%>新版本(第2个文件)" \
				"&nbsp;&nbsp;&nbsp;(<b style='background-color:" + m_szColorChanged + ";width:20'>&nbsp;</b>改变的&nbsp;&nbsp;" \
				"<b style='background-color:" + m_szColorAdded + ";width:20'>&nbsp;</b>增加的&nbsp;&nbsp;" \
				"<b style='background-color:" + m_szColorDeleted + ";width:20'>&nbsp;</b>删除的)&nbsp;&nbsp;" \
				"<FORM ACTION='' style='display:inline'><SELECT id='fontoptions' " \
				"onchange='maintable.style.fontSize=this.options[this.selectedIndex].value'>" \
				"<option value='6pt'>6pt<option value='7pt'>7pt<option value='8pt' selected>8pt<option value='9pt'>9pt</SELECT> " \
				"</FORM></td></tr>\r\n" \
				"<tr bgColor='#EEEEEE' style='color:0'><td width=50%><code>" + f1.GetName() + "</code></td><td width=50%><code>" + f2.GetName() + "</code></td></tr>" \
				"</table>\r\n" \
				"</td></tr>\r\n" \
				"</table>\r\n" \
				"\r\n" \
				"<br>\r\n" \
				"\r\n" ;

	long nbLines = f1.GetNBLines();
	if (nbLines==0)
	{
		s += "<br>empty files";
	}
	else
	{
		s += "<table border=0 bgcolor=0 cellpadding=1 cellspacing=1 width=100%><tr><td>" \
			"<table id='maintable' width=100% bgcolor='" + m_szColorBackground + "' cellpadding=0 cellspacing=0 border=0 style='color:" + m_szColorText + ";font-family: Courier New, Helvetica, sans-serif; font-size: 8pt'>\r\n";
	}

	
	char *arrStatus[4] = {
		"",
		" class='C'",
		" class='A'",
		" class='D'" };

	CString sc;

	TCHAR szLine[16];

	// write content
	//
	for (long i=0; i<nbLines; i++)
	{
		sprintf(szLine, "<b>%d</b>", i);
		sc += "<tr><td width=50%" + CString(arrStatus[ f1.GetStatusLine(i) ]) + ">" + 
			  CString(szLine) + 
			  " " +
			  Escape(f1.GetRawLine(i)) + "</td>";
		sc += "<td width=50%" + CString(arrStatus[ f2.GetStatusLine(i) ]) + ">" + 
			  CString(szLine) + 
			  " " +
			  Escape(f2.GetRawLine(i)) + "</td></tr>";
		
	} // for i

	s += sc;

	if (nbLines>0)
		s += "</table></td></tr></table>\r\n";

	// write html footer
	s += m_szFooter + "</BODY>\r\n" \
		"</HTML>\r\n";

	return s;
}



CString CDiffEngine::Escape(CString &s) // a helper aimed to make sure tag symbols are passed as content
{
	CString o;
	long nSize = s.GetLength();
	if (nSize==0) return CString("&nbsp;");

	TCHAR c;
	BOOL bIndentation = TRUE;

	for (long i=0; i<nSize; i++)
	{
		c = s.GetAt(i);
		if (bIndentation && (c==' ' || c=='\t'))
		{
			if (c==' ')
				o += "&nbsp;";
			else
				o += "&nbsp;&nbsp;&nbsp;&nbsp;";
			continue;
		}
		bIndentation = FALSE;

		if (c=='<')
			o += "&lt;";
		else if (c=='>')
			o += "&gt;";
		else if (c=='&')
			o += "&amp;";
		else
			o += c;
	}
	return o;
}


BOOL CDiffEngine::ExportAsHtml(/*in*/CString &szFilename, /*in*/CString &szContent)
{
	CStdioFile f;
	if ( !f.Open(szFilename, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary) )
	{
		TCHAR szError[MAX_PATH];
		sprintf(szError, "错误 : 不能创建 %s\r\n", szFilename.GetBuffer(0) );
		OutputDebugString(szError);
		return FALSE;
	}

	f.Write(szContent.GetBuffer(0), szContent.GetLength());

	f.Close();

	return TRUE;
}


BOOL CDiffEngine::ExportAsStdout(/*in*/CString &szContent)
{
	printf ("%s", szContent.GetBuffer(0));
	return TRUE;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -