xmlfileex.cpp
来自「管理项目进度工具的原代码」· C++ 代码 · 共 306 行
CPP
306 行
// xmlfileex.cpp: implementation of the CXmlFileEx class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "xmlfileex.h"
#include "stringres.h"
#include "enstring.h"
#include "iencryption.h"
#include "passworddialog.h"
#include "..\3rdparty\base64coder.h"
#include "..\3rdparty\xmlnodewrapper.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CString CXmlFileEx::s_sPasswordExplanation(ENCRYPT_ENTERPWD);
CString CXmlFileEx::s_sDecryptFailed(ENCRYPT_DECRYPTFAILED);
const LPCTSTR ENCODEDDATA = "ENCODEDDATA";
const LPCTSTR ENCODEDDATALEN = "DATALEN";
CXmlFileEx::CXmlFileEx(LPCTSTR szRootItemName, LPCTSTR szPassword)
: CXmlFile(szRootItemName), m_pEncryptor(NULL), m_sPassword(szPassword)
{
}
CXmlFileEx::~CXmlFileEx()
{
}
void CXmlFileEx::SetUIStrings(UINT nIDPasswordExplanation,
UINT nIDDecryptFailed)
{
s_sPasswordExplanation.LoadString(nIDPasswordExplanation);
s_sDecryptFailed.LoadString(nIDDecryptFailed);
}
BOOL CXmlFileEx::Encrypt(LPCTSTR szPassword)
{
if (!szPassword)
szPassword = m_sPassword;
if (!(*szPassword) || !InitEncryptor())
return FALSE;
// 1. export everything below the root to a string
CXmlDocumentWrapper doc;
doc.LoadXML("<a></a>");
CXmlNodeWrapper nodeDoc(doc.AsNode());
CString sXml;
POSITION pos = m_xiRoot.GetFirstItemPos();
int nNode = 0;
while (pos)
{
const CXmlItem* pXI = m_xiRoot.GetNextItem(pos);
ASSERT (pXI);
while (pXI)
{
CString sItem = pXI->GetName();
CXmlNodeWrapper nodeChild(nodeDoc.InsertNode(nNode++, (LPCTSTR)sItem));
ASSERT (nodeChild.IsValid());
Export(pXI, &nodeChild);
sXml += nodeChild.GetXML();
// siblings if there are any
pXI = pXI->GetSibling();
}
}
// 2. encrypt it
unsigned char* pEncrypted = NULL;
int nLenEncrypted = 0;
if (!m_pEncryptor->Encrypt((unsigned char*)(LPCTSTR)sXml, sXml.GetLength() + 1, szPassword, // RB - Added sPassword parameter instead of NULL
pEncrypted, nLenEncrypted))
return FALSE;
// 3. convert the binary to a string
Base64Coder b64;
b64.Encode(pEncrypted, nLenEncrypted);
const char* pEncodedDataBuffer = b64.EncodedMessage();
// 4. replace file contents with a single CDATA item
m_xiRoot.DeleteAllItems();
m_xiRoot.AddItem(ENCODEDDATA, pEncodedDataBuffer, TRUE);
m_xiRoot.AddItem("DATALEN", nLenEncrypted);
// 5. cleanup
m_pEncryptor->FreeBuffer(pEncrypted);
return TRUE;
}
BOOL CXmlFileEx::IsEncrypted()
{
return (GetItemValueI(ENCODEDDATALEN) > 0);
}
BOOL CXmlFileEx::Decrypt(LPCTSTR szPassword)
{
if (!IsEncrypted())
return TRUE; // nothing to do
// we don't try to decrypt if no encryption capabilities
if (!CanEncrypt())
{
m_nFileError = XFL_NOENCRYPTIONDLL;
return FALSE;
}
if (!szPassword)
szPassword = m_sPassword;
CXmlItem* pXI = GetEncryptedBlock();
if (pXI && !pXI->GetSibling())
{
// else keep getting password till success or user cancels
while (TRUE)
{
CString sPassword(szPassword);
if (sPassword.IsEmpty())
{
CString sExplanation(s_sPasswordExplanation);
if (sExplanation.Find("%s") != -1)
sExplanation.Format(s_sPasswordExplanation, GetFileName());
if (!CPasswordDialog::RetrievePassword(FALSE, sPassword, sExplanation))
{
// RB - Set m_nFileError to avoid "The selected task list could not be opened..." message when cancelling
m_nFileError = XFL_CANCELLED;
return FALSE;
}
}
CString sFile;
if (Decrypt(pXI->GetValue(), sFile, sPassword))
{
m_sPassword = sPassword;
sFile.TrimLeft();
sFile.TrimRight();
sFile = "<ROOT>" + sFile + "</ROOT>";
// delete the cdata item
m_xiRoot.DeleteItem(pXI);
try
{
CXmlDocumentWrapper doc;
// reparse decrypted xml
if (doc.LoadXML(sFile))
{
CXmlNodeWrapper node(doc.AsNode());
return ParseItem(m_xiRoot, &node);
}
}
catch (...)
{
m_nFileError = XFL_BADMSXML;
}
return FALSE;
}
// RB - Added code to format the error message before calling AfxMessage
else
{
CString sMessage(s_sDecryptFailed);
if (sMessage.Find("%s") != -1)
sMessage.Format(s_sDecryptFailed, GetFileName());
if (IDNO == AfxMessageBox(sMessage, MB_YESNO))
{
m_nFileError = XFL_CANCELLED;
return FALSE;
}
// else user will try again
}
}
}
// else
m_nFileError = XFL_UNKNOWNENCRYPTION;
return FALSE;
}
CXmlItem* CXmlFileEx::GetEncryptedBlock()
{
CXmlItem* pXI = NULL;
int nDataLen = GetItemValueI(ENCODEDDATALEN);
if (nDataLen)
{
pXI = GetItem(ENCODEDDATA);
if (!pXI)
{
// backwards compatibility
pXI = GetItem("CDATA");
if (!pXI)
{
// missing tags (last ditched effort)
pXI = &m_xiRoot;
}
}
}
return pXI;
}
BOOL CXmlFileEx::Load(LPCTSTR szFilePath, LPCTSTR szRootItemName, IXmlParse* pCallback, BOOL bDecrypt)
{
m_bDecrypt = bDecrypt;
return CXmlFile::Load(szFilePath, szRootItemName, pCallback);
}
BOOL CXmlFileEx::Open(LPCTSTR szFilePath, XF_OPEN nOpenFlags, BOOL bDecrypt)
{
m_bDecrypt = bDecrypt;
return CXmlFile::Open(szFilePath, nOpenFlags);
}
BOOL CXmlFileEx::LoadEx(LPCTSTR szRootItemName, IXmlParse* pCallback)
{
if (!CXmlFile::LoadEx(szRootItemName, pCallback))
return FALSE;
// we assume the file is encrypted if it contains a single CDATA element
if (m_bDecrypt)
return Decrypt();
return TRUE;
}
BOOL CXmlFileEx::Decrypt(LPCTSTR szInput, CString& sOutput, LPCTSTR szPassword)
{
if (!InitEncryptor())
return FALSE;
// 1. convert the input string back to binary
Base64Coder b64;
b64.Decode(szInput);
DWORD nReqBufLen = 0;
unsigned char* pDecodedDataBuffer = b64.DecodedMessage(nReqBufLen);
nReqBufLen = GetItemValueI("DATALEN");
// 2. decrypt it
unsigned char* pDecrypted = NULL;
int nLenDecrypted = 0;
if (!m_pEncryptor->Decrypt((unsigned char*)pDecodedDataBuffer, nReqBufLen, szPassword,
pDecrypted, nLenDecrypted))
return FALSE;
// 3. result should be a null-terminated string
sOutput = pDecrypted;
// 4. cleanup
m_pEncryptor->FreeBuffer(pDecrypted);
return TRUE;
}
BOOL CXmlFileEx::InitEncryptor()
{
if (m_pEncryptor)
return TRUE;
m_pEncryptor = CreateEncryptionInterface("EncryptDecrypt.dll");
return (m_pEncryptor != NULL);
}
BOOL CXmlFileEx::CanEncrypt()
{
return CXmlFileEx().InitEncryptor();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?