Refactoring

This commit is contained in:
Oleg Korshul
2021-05-23 13:55:43 +03:00
parent 50733e3979
commit 1e42d594b7
7 changed files with 505 additions and 436 deletions

View File

@ -1,165 +0,0 @@
#ifndef _ZIPFOLDER_H_
#define _ZIPFOLDER_H_
#include "./../../../../OfficeUtils/src/ZipBuffer.h"
#include "./../../../common/File.h"
#include "./../../../common/Directory.h"
class IZipFolder
{
public:
virtual bool read (const std::wstring& path, BYTE*& data, DWORD& length) = 0;
virtual void write (const std::wstring& path, BYTE* data, DWORD length) = 0;
virtual void move (const std::wstring& sSrc, const std::wstring& sDst) = 0;
virtual bool exists(const std::wstring& path) = 0;
virtual void remove(const std::wstring& path) = 0;
virtual void createDirectory(const std::wstring& path) = 0;
virtual void writeZipFolder(BYTE*& data, DWORD& length) = 0;
virtual void writeXml(const std::wstring& path, const std::wstring& xml) = 0;
virtual std::vector<std::wstring> getFiles(const std::wstring& path, bool bIsRecursion) = 0;
};
class CZipFolder : public IZipFolder
{
std::wstring m_sFolder;
public:
CZipFolder(const std::wstring& folder) : m_sFolder(folder) {}
virtual bool read (const std::wstring& path, BYTE*& data, DWORD& length)
{
if (NSFile::CFileBinary::Exists(path))
return NSFile::CFileBinary::ReadAllBytes(path, &data, length);
return false;
}
virtual void write (const std::wstring& path, BYTE* data, DWORD length)
{
NSFile::CFileBinary::Remove(path);
NSFile::CFileBinary oFile;
oFile.CreateFileW(path);
oFile.WriteFile(data, length);
oFile.CloseFile();
}
virtual void move (const std::wstring& sSrc, const std::wstring& sDst)
{
NSFile::CFileBinary::Move(sSrc, sDst);
}
virtual bool exists(const std::wstring& path)
{
return NSFile::CFileBinary::Exists(path);
}
virtual void remove(const std::wstring& path)
{
NSFile::CFileBinary::Remove(path);
}
virtual void createDirectory(const std::wstring& path)
{
if (!NSDirectory::Exists(path))
NSDirectory::CreateDirectory(path);
}
virtual void writeZipFolder(BYTE*& data, DWORD& length)
{
}
virtual void writeXml(const std::wstring& path, const std::wstring& xml)
{
std::string sXmlUtf8 = U_TO_UTF8(xml);
write(path, (BYTE*)sXmlUtf8.c_str(), (DWORD)sXmlUtf8.length());
}
virtual std::vector<std::wstring> getFiles(const std::wstring& path, bool bIsRecursion)
{
return NSDirectory::GetFiles(path, bIsRecursion);
}
};
class CZipFolderMemory : public IZipFolder
{
CZipBuffer* m_zlib;
public:
CZipFolderMemory(BYTE* data, DWORD length)
{
m_zlib = new CZipBuffer(data, length);
}
std::string normalPath(const std::wstring& path)
{
if (!path.empty() && path[0] == L'/')
return U_TO_UTF8(path.substr(1));
return U_TO_UTF8(path);
}
virtual bool read (const std::wstring& path, BYTE*& data, DWORD& length)
{
std::string sPath = normalPath(path);
m_zlib->getFile(sPath, data, length);
if (length)
return true;
return false;
}
virtual void write (const std::wstring& path, BYTE* data, DWORD length)
{
std::string sPath = normalPath(path);
BYTE* copyData = new BYTE[length];
memcpy(copyData, data, length);
m_zlib->addFile(sPath, copyData, length);
}
virtual void move (const std::wstring& sSrc, const std::wstring& sDst)
{
std::string sSrcPath = normalPath(sSrc);
BYTE* data; DWORD length;
m_zlib->getFile(sSrcPath, data, length);
BYTE* copyData = new BYTE[length];
memcpy(copyData, data, length);
m_zlib->removeFile(sSrcPath);
m_zlib->addFile(normalPath(sDst), copyData, length);
}
virtual bool exists(const std::wstring& path)
{
std::string sPath = normalPath(path);
std::vector<std::string> sPaths = m_zlib->getPaths();
return std::find(sPaths.begin(), sPaths.end(), sPath) != sPaths.end();
}
virtual void remove(const std::wstring& path)
{
std::string sPath = normalPath(path);
m_zlib->removeFile(sPath);
}
virtual void createDirectory(const std::wstring& path)
{
}
virtual void writeZipFolder(BYTE*& data, DWORD& length)
{
m_zlib->save(data, length);
m_zlib->close();
}
virtual void writeXml(const std::wstring& path, const std::wstring& xml)
{
std::string sXmlUtf8 = U_TO_UTF8(xml);
write(path, (BYTE*)sXmlUtf8.c_str(), (DWORD)sXmlUtf8.length());
}
virtual std::vector<std::wstring> getFiles(const std::wstring& path, bool bIsRecursion)
{
std::string sPath = normalPath(path);
std::vector<std::string> sPaths = m_zlib->getPaths();
std::vector<std::wstring> sRes;
for (std::string& i : sPaths)
{
if (bIsRecursion)
{
if (i.find(sPath) == 0)
sRes.push_back(L'/' + UTF8_TO_U(i));
}
else
{
size_t nFindDirectory = i.find(sPath);
if (nFindDirectory == 0)
{
nFindDirectory = i.find_first_of("\\/", sPath.length());
if (nFindDirectory != std::wstring::npos && i.find_first_of("\\/", nFindDirectory + 1) == std::wstring::npos)
sRes.push_back(L'/' + UTF8_TO_U(i));
}
}
}
return sRes;
}
};
#endif //_ZIPFOLDER_H_

View File

@ -1,6 +1,6 @@
#include "./../include/OOXMLSigner.h"
#include "./../include/ZipFolder.h"
#include "./../src/XmlTransform.h"
#include "./ZipFolder.h"
#include "./XmlTransform.h"
#include <cstdio>
#include <ctime>
#include <time.h>
@ -9,8 +9,7 @@ class COOXMLSigner_private
{
public:
ICertificate* m_certificate;
IZipFolder* m_pZipFolder;
std::wstring m_sFolder;
IFolder* m_pFolder;
std::wstring m_date;
@ -28,37 +27,21 @@ public:
public:
COOXMLSigner_private(const std::wstring& sFolder, ICertificate* pContext)
{
m_sFolder = sFolder;
m_pZipFolder = new CZipFolder(sFolder);
m_pFolder = new CFolderSystem(sFolder);
m_certificate = pContext;
m_date = L"2017-04-21T08:30:21Z";
std::time_t rawtime;
std::tm* timeinfo;
char buffer1[100];
char buffer2[100];
std::time(&rawtime);
timeinfo = std::gmtime(&rawtime);
std::strftime(buffer1, 100, "%Y-%m-%d", timeinfo);
std::strftime(buffer2, 100, "%H:%M:%S", timeinfo);
std::string date = (std::string(buffer1) + "T" + std::string(buffer2) + "Z");
m_date = NSFile::CUtf8Converter::GetUnicodeFromCharPtr(date);
m_signed_info.WriteString("<CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315\"/>");
m_signed_info.WriteString("<SignatureMethod Algorithm=\"");
m_signed_info.WriteString(ICertificate::GetSignatureMethodA(m_certificate->GetHashAlg()));
m_signed_info.WriteString("\"/>");
OpenFolder();
}
COOXMLSigner_private(BYTE* data, DWORD length, ICertificate* pContext)
{
m_sFolder = L"";
m_pZipFolder = new CZipFolderMemory(data, length);
m_pFolder = new CZipFolderMemory(data, length);
m_certificate = pContext;
OpenFolder();
}
void OpenFolder()
{
m_date = L"2017-04-21T08:30:21Z";
std::time_t rawtime;
@ -80,22 +63,18 @@ public:
m_signed_info.WriteString(ICertificate::GetSignatureMethodA(m_certificate->GetHashAlg()));
m_signed_info.WriteString("\"/>");
}
~COOXMLSigner_private()
{
RELEASEOBJECT(m_pFolder);
}
std::wstring GetReference(const std::wstring& file, const std::wstring& content_type)
{
std::wstring sXml = L"<Reference URI=\"" + file + L"?ContentType=" + content_type + L"\">";
std::wstring sXml = L"<Reference URI=\"/" + file + L"?ContentType=" + content_type + L"\">";
sXml += (L"<DigestMethod Algorithm=\"" + ICertificate::GetDigestMethod(m_certificate->GetHashAlg()) + L"\"/>");
sXml += L"<DigestValue>";
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(m_sFolder + file, pData, dwLen);
std::string sTmp = m_certificate->GetHash(pData, dwLen, m_certificate->GetHashAlg());
sXml += UTF8_TO_U(sTmp);
sXml += m_pFolder->getFileHashW(file, m_certificate);
sXml += L"</DigestValue>";
sXml += L"</Reference>";
return sXml;
@ -136,21 +115,8 @@ public:
return file.substr(file.find(L",") + 1);
}
BYTE* pData = NULL;
DWORD dwLen = 0;
if (!m_pZipFolder->read(file, pData, dwLen))
return L"";
char* pDataC = NULL;
int nLen = 0;
NSFile::CBase64Converter::Encode(pData, (int)dwLen, pDataC, nLen, NSBase64::B64_BASE64_FLAG_NOCRLF);
std::wstring sReturn = NSFile::CUtf8Converter::GetUnicodeFromCharPtr(pDataC, (LONG)nLen, FALSE);
RELEASEARRAYOBJECTS(pData);
RELEASEARRAYOBJECTS(pDataC);
return sReturn;
std::string sRet = m_pFolder->getFileBase64(file);
return UTF8_TO_U(sRet);
}
std::wstring GetImageBase64(BYTE* data, DWORD length)
{
@ -167,23 +133,13 @@ public:
std::wstring GetRelsReference(const std::wstring& file)
{
BYTE* pData = NULL;
DWORD dwLen = 0;
if (!m_pZipFolder->read(m_sFolder + file, pData, dwLen))
return L"";
COOXMLRelationships oRels(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen), false);
COOXMLRelationships oRels(file, m_pFolder);
if (oRels.rels.size() == 0)
return L"";
if (L"/_rels/.rels" == file)
if (L"_rels/.rels" == file)
{
BYTE* pDataNew = new BYTE[dwLen];
memcpy(pDataNew, pData, dwLen);
long nLength = dwLen;
oRels.CheckOriginSigs(pDataNew, nLength);
m_pZipFolder->write(m_sFolder + file, pDataNew, nLength);
RELEASEARRAYOBJECTS(pDataNew);
oRels.CheckOriginSigs(file);
// удалим все лишнее
std::vector<COOXMLRelationship>::iterator i = oRels.rels.begin();
@ -199,7 +155,7 @@ public:
}
NSStringUtils::CStringBuilder builder;
builder.WriteString(L"<Reference URI=\"");
builder.WriteString(L"<Reference URI=\"/");
builder.WriteString(file);
builder.WriteString(L"?ContentType=application/vnd.openxmlformats-package.relationships+xml\">");
builder.WriteString(oRels.GetTransforms());
@ -220,17 +176,13 @@ public:
{
std::wstring sRelsFolder = folder + L"/_rels";
std::vector<std::wstring> arFiles = m_pZipFolder->getFiles(sRelsFolder, false);
std::vector<std::wstring> arFiles = m_pFolder->getFiles(sRelsFolder, false);
std::map<std::wstring, bool> arSigFiles;
for (std::vector<std::wstring>::iterator iter = arFiles.begin(); iter != arFiles.end(); iter++)
{
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(*iter, pData, dwLen);
XmlUtils::CXmlNode oNodeRels;
if (!oNodeRels.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen)))
XmlUtils::CXmlNode oNodeRels = m_pFolder->getNodeFromFile(*iter);
if (!oNodeRels.IsValid())
continue;
XmlUtils::CXmlNodes oNodesRels = oNodeRels.GetNodes(L"Relationship");
int nCount = oNodesRels.GetCount();
@ -240,10 +192,10 @@ public:
oNodesRels.GetAt(nIndex, oNodeRel);
std::wstring sTarget = oNodeRel.GetAttribute(L"Target");
if (!sTarget.empty() && arSigFiles.find(sTarget) == arSigFiles.end() && m_pZipFolder->exists(folder + L"/" + sTarget))
if (!sTarget.empty() && arSigFiles.find(sTarget) == arSigFiles.end() && m_pFolder->exists(folder + L"/" + sTarget))
arSigFiles.insert(std::pair<std::wstring, bool>(sTarget, true));
}
m_pZipFolder->remove(*iter);
m_pFolder->remove(*iter);
}
int nCountSigs = (int)arSigFiles.size();
@ -263,13 +215,13 @@ public:
oBuilder.WriteString(L"</Relationships>");
m_pZipFolder->writeXml(sFile, oBuilder.GetData());
m_pFolder->writeXml(sFile, oBuilder.GetData());
// теперь перебьем все имена файлов
std::vector<std::wstring> arSigs;
std::vector<std::wstring> arFilesXml = m_pZipFolder->getFiles(folder, false);
std::vector<std::wstring> arFilesXml = m_pFolder->getFiles(folder, false);
for (std::vector<std::wstring>::iterator iter = arFilesXml.begin(); iter != arFilesXml.end(); iter++)
{
std::wstring sXmlFileName = NSFile::GetFileName(*iter);
@ -280,7 +232,7 @@ public:
if (find == arSigFiles.end())
{
// ненужная xml
m_pZipFolder->remove(*iter);
m_pFolder->remove(*iter);
continue;
}
@ -290,12 +242,12 @@ public:
std::sort(arSigs.begin(), arSigs.end());
for (std::vector<std::wstring>::iterator iter = arSigs.begin(); iter != arSigs.end(); iter++)
{
m_pZipFolder->move(folder + L"/" + *iter, folder + L"/onlyoffice_" + *iter);
m_pFolder->move(folder + L"/" + *iter, folder + L"/onlyoffice_" + *iter);
}
int nSigNumber = 1;
for (std::vector<std::wstring>::iterator iter = arSigs.begin(); iter != arSigs.end(); iter++)
{
m_pZipFolder->move(folder + L"/onlyoffice_" + *iter, folder + L"/sig" + std::to_wstring(nSigNumber++) + L".xml");
m_pFolder->move(folder + L"/onlyoffice_" + *iter, folder + L"/sig" + std::to_wstring(nSigNumber++) + L".xml");
}
return (int)arSigs.size();
@ -303,14 +255,7 @@ public:
void ParseContentTypes()
{
std::wstring file = m_sFolder + L"/[Content_Types].xml";
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(file, pData, dwLen);
XmlUtils::CXmlNode oNode;
oNode.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen));
XmlUtils::CXmlNode oNode = m_pFolder->getNodeFromFile(L"/[Content_Types].xml");
XmlUtils::CXmlNodes nodesDefaults;
oNode.GetNodes(L"Default", nodesDefaults);
@ -343,27 +288,22 @@ public:
ParseContentTypes();
// 2) Parse files in directory
std::vector<std::wstring> files = m_pZipFolder->getFiles(m_sFolder, true);
std::vector<std::wstring> files = m_pFolder->getFiles(L"", true);
// 3) Check each file
std::wstring sFolder = m_sFolder;
NSStringUtils::string_replace(sFolder, L"\\", L"/");
std::wstring sFolder = L"";
for (std::vector<std::wstring>::iterator i = files.begin(); i != files.end(); i++)
{
std::wstring sCheckFile = *i;
NSStringUtils::string_replace(sCheckFile, L"\\", L"/");
if (0 != sCheckFile.find(sFolder))
continue;
// make cool filename
sCheckFile = sCheckFile.substr(sFolder.length());
sCheckFile = m_pFolder->getLocalFilePath(sCheckFile);
// check needed file
if (0 == sCheckFile.find(L"/_xmlsignatures") ||
0 == sCheckFile.find(L"/docProps") ||
0 == sCheckFile.find(L"/[Content_Types].xml") ||
0 == sCheckFile.find(L"/[trash]"))
if (0 == sCheckFile.find(L"_xmlsignatures") ||
0 == sCheckFile.find(L"docProps") ||
0 == sCheckFile.find(L"[Content_Types].xml") ||
0 == sCheckFile.find(L"[trash]"))
continue;
// check rels and add to needed array
@ -429,14 +369,8 @@ public:
void CorrectContentTypes(int nCountSignatures)
{
std::wstring file = m_sFolder + L"/[Content_Types].xml";
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(file, pData, dwLen);
XmlUtils::CXmlNode oNode;
oNode.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen));
std::wstring file = L"[Content_Types].xml";
XmlUtils::CXmlNode oNode = m_pFolder->getNodeFromFile(file);
NSStringUtils::CStringBuilder oBuilder;
oBuilder.WriteString(L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
@ -483,7 +417,7 @@ public:
oBuilder.WriteNodeEnd(oNode.GetName());
m_pZipFolder->writeXml(file, oBuilder.GetData());
m_pFolder->writeXml(file, oBuilder.GetData());
}
void SetGuid(const std::wstring& guid)
@ -654,25 +588,25 @@ public:
int AddSignatureReference()
{
std::wstring sDirectory = m_sFolder + L"/_xmlsignatures";
std::wstring sDirectory = L"/_xmlsignatures";
m_pZipFolder->createDirectory(sDirectory);
m_pFolder->createDirectory(sDirectory);
// remove old .sig file
std::vector<std::wstring> arFiles = m_pZipFolder->getFiles(sDirectory, false);
std::vector<std::wstring> arFiles = m_pFolder->getFiles(sDirectory, false);
for (std::vector<std::wstring>::iterator i = arFiles.begin(); i != arFiles.end(); i++)
{
if (NSFile::GetFileExtention(*i) == L"sigs")
{
m_pZipFolder->remove(*i);
m_pFolder->remove(*i);
}
}
std::wstring sOriginName = L"origin.sigs";
if (!m_pZipFolder->exists(sDirectory + L"/" + sOriginName))
m_pZipFolder->write(sDirectory + L"/" + sOriginName, NULL, 0);
if (!m_pFolder->exists(sDirectory + L"/" + sOriginName))
m_pFolder->write(sDirectory + L"/" + sOriginName, NULL, 0);
m_pZipFolder->createDirectory(sDirectory + L"/_rels");
m_pFolder->createDirectory(sDirectory + L"/_rels");
int nSignNum = GetCountSigns(sDirectory);
@ -714,9 +648,17 @@ public:
int nSignNum = AddSignatureReference();
m_pZipFolder->writeXml(m_sFolder + L"/_xmlsignatures/sig" + std::to_wstring(nSignNum + 1) + L".xml", builderResult.GetData());
m_pFolder->writeXml(L"_xmlsignatures/sig" + std::to_wstring(nSignNum + 1) + L".xml", builderResult.GetData());
IFolder::CBuffer* buffer = m_pFolder->finalize();
if (buffer)
{
pFiletoWrite = buffer->Buffer;
dwLenFiletoWrite = buffer->Size;
buffer->UnsetDestroy();
delete buffer;
}
m_pZipFolder->writeZipFolder(pFiletoWrite, dwLenFiletoWrite);
return (sSignedXml.empty()) ? 1 : 0;
}
};

View File

@ -1,6 +1,6 @@
#include "./XmlTransform.h"
#include "./../include/OOXMLVerifier.h"
#include "./../include/ZipFolder.h"
#include "./ZipFolder.h"
class COOXMLSignature_private
{
@ -13,7 +13,7 @@ public:
std::string m_sImageInvalidBase64;
std::wstring m_sFolder;
IZipFolder* m_pZipFolder;
IFolder* m_pFolder;
std::wstring m_sFile;
std::string m_sDate;
@ -401,7 +401,7 @@ public:
sFile = sFile.substr(0, nPos);
sFile = m_sFolder + sFile;
if (!m_pZipFolder->exists(sFile))
if (!m_pFolder->exists(sFile))
return OOXML_SIGNATURE_INVALID;
XmlUtils::CXmlNode nodeMethod = node.ReadNode(L"DigestMethod");
@ -422,11 +422,7 @@ public:
if (!nodeTransform.IsValid())
{
// simple hash
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(sFile, pData, dwLen);
sCalcValue = m_cert->GetHash(pData, dwLen, nAlg);
sCalcValue = m_pFolder->getFileHash(sFile, m_cert, nAlg);
sValue = U_TO_UTF8((node.ReadNodeText(L"DigestValue")));
MakeBase64_NOCRLF(sValue);
}
@ -437,10 +433,8 @@ public:
if (!oTransforms.GetValid())
return OOXML_SIGNATURE_NOTSUPPORTED;
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(sFile, pData, dwLen);
std::string sXml = oTransforms.Transform(std::string((char*)pData, dwLen));
std::string sXml = m_pFolder->readXml(sFile);
sXml = oTransforms.Transform(sXml);
sCalcValue = m_cert->GetHash(sXml, nAlg);
sValue = U_TO_UTF8((node.ReadNodeText(L"DigestValue")));
@ -565,81 +559,26 @@ void COOXMLSignature::Check()
class COOXMLVerifier_private
{
public:
std::wstring m_sFolder;
IZipFolder* m_pZipFolder;
IFolder* m_pFolder;
std::vector<COOXMLSignature*> m_arSignatures;
std::vector<std::wstring> m_arSignaturesFiles;
public:
COOXMLVerifier_private(const std::wstring& sFolder)
{
m_sFolder = sFolder;
m_pZipFolder = new CZipFolder(sFolder);
// check .sig file
std::vector<std::wstring> arFiles = m_pZipFolder->getFiles(m_sFolder + L"/_xmlsignatures", false);
bool bIsFound = false;
for (std::vector<std::wstring>::iterator i = arFiles.begin(); i != arFiles.end(); i++)
{
if (NSFile::GetFileExtention(*i) == L"sigs")
{
bIsFound = true;
break;
}
}
if (!bIsFound)
return;
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(m_sFolder + L"/[Content_Types].xml", pData, dwLen);
XmlUtils::CXmlNode oContentTypes;
if (!oContentTypes.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen)))
return;
XmlUtils::CXmlNodes oOverrides = oContentTypes.GetNodes(L"Override");
int nCount = oOverrides.GetCount();
for (int i = 0; i < nCount; i++)
{
XmlUtils::CXmlNode node;
oOverrides.GetAt(i, node);
if (node.GetAttributeA("ContentType") != "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml")
continue;
std::wstring sFile = m_sFolder + node.GetAttribute("PartName");
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(sFile, pData, dwLen);
XmlUtils::CXmlNode nodeSig;
if (!nodeSig.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen)))
continue;
if (nodeSig.GetName() != L"Signature")
continue;
COOXMLSignature* pSignature = new COOXMLSignature();
pSignature->m_internal->m_sFile = sFile;
pSignature->m_internal->m_node = nodeSig;
pSignature->m_internal->m_sFolder = m_sFolder;
pSignature->m_internal->m_pZipFolder = m_pZipFolder;
pSignature->Check();
m_arSignatures.push_back(pSignature);
m_arSignaturesFiles.push_back(sFile);
}
m_pFolder = new CFolderSystem(sFolder);
OpenFolder();
}
COOXMLVerifier_private(BYTE* data, DWORD length)
{
m_sFolder = L"";
m_pZipFolder = new CZipFolderMemory(data, length);
m_pFolder = new CZipFolderMemory(data, length);
OpenFolder();
}
void OpenFolder()
{
// check .sig file
std::vector<std::wstring> arFiles = m_pZipFolder->getFiles(m_sFolder + L"/_xmlsignatures", false);
std::vector<std::wstring> arFiles = m_pFolder->getFiles(L"_xmlsignatures", false);
bool bIsFound = false;
for (std::vector<std::wstring>::iterator i = arFiles.begin(); i != arFiles.end(); i++)
{
@ -653,12 +592,8 @@ public:
if (!bIsFound)
return;
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(m_sFolder + L"/[Content_Types].xml", pData, dwLen);
XmlUtils::CXmlNode oContentTypes;
if (!oContentTypes.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen)))
XmlUtils::CXmlNode oContentTypes = m_pFolder->getNodeFromFile(L"[Content_Types].xml");
if (!oContentTypes.IsValid())
return;
XmlUtils::CXmlNodes oOverrides = oContentTypes.GetNodes(L"Override");
@ -672,13 +607,9 @@ public:
if (node.GetAttributeA("ContentType") != "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml")
continue;
std::wstring sFile = m_sFolder + node.GetAttribute("PartName");
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(sFile, pData, dwLen);
XmlUtils::CXmlNode nodeSig;
if (!nodeSig.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen)))
std::wstring sFile = node.GetAttribute("PartName");
XmlUtils::CXmlNode nodeSig = m_pFolder->getNodeFromFile(sFile);
if (!nodeSig.IsValid())
continue;
if (nodeSig.GetName() != L"Signature")
@ -687,14 +618,14 @@ public:
COOXMLSignature* pSignature = new COOXMLSignature();
pSignature->m_internal->m_sFile = sFile;
pSignature->m_internal->m_node = nodeSig;
pSignature->m_internal->m_sFolder = m_sFolder;
pSignature->m_internal->m_pZipFolder = m_pZipFolder;
pSignature->m_internal->m_pFolder = m_pFolder;
pSignature->Check();
m_arSignatures.push_back(pSignature);
m_arSignaturesFiles.push_back(sFile);
}
}
~COOXMLVerifier_private()
{
for (std::vector<COOXMLSignature*>::iterator i = m_arSignatures.begin(); i != m_arSignatures.end(); i++)
@ -703,6 +634,7 @@ public:
RELEASEOBJECT(v);
}
m_arSignatures.clear();
RELEASEOBJECT(m_pFolder);
}
void RemoveSignature(const std::string& sGuid)
@ -733,19 +665,12 @@ public:
}
if (!sFile.empty())
m_pZipFolder->remove(sFile);
m_pFolder->remove(sFile);
if (!bIsRemoveAll && sFile.empty())
return;
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(m_sFolder + L"/[Content_Types].xml", pData, dwLen);
XmlUtils::CXmlNode oContentTypes;
if (!oContentTypes.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen)))
return;
XmlUtils::CXmlNode oContentTypes = m_pFolder->getNodeFromFile(L"[Content_Types].xml");
std::wstring sXml = L"<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">";
XmlUtils::CXmlNodes oNodes;
if (oContentTypes.GetNodes(L"*", oNodes))
@ -768,7 +693,7 @@ public:
}
else
{
std::wstring sFileFound = sFile.substr(m_sFolder.length());
std::wstring sFileFound = m_pFolder->getLocalFilePath(sFile);
if (L"Override" == oNode.GetName() &&
L"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml" == oNode.GetAttribute(L"ContentType") &&
sFileFound == oNode.GetAttribute(L"PartName"))
@ -780,20 +705,16 @@ public:
}
sXml += L"</Types>";
m_pZipFolder->writeXml(m_sFolder + L"/[Content_Types].xml", sXml);
m_pFolder->writeXml(L"[Content_Types].xml", sXml);
if (bIsRemoveAll)
{
std::vector<std::wstring> arrDeleteFiles = m_pZipFolder->getFiles(m_sFolder + L"/_xmlsignatures", true);
std::vector<std::wstring> arrDeleteFiles = m_pFolder->getFiles(L"_xmlsignatures", true);
for (const std::wstring& sPath : arrDeleteFiles)
m_pZipFolder->remove(sPath);
m_pFolder->remove(sPath);
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(m_sFolder + L"/_rels/.rels", pData, dwLen);
XmlUtils::CXmlNode oRels;
if (!oRels.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen)))
XmlUtils::CXmlNode oRels = m_pFolder->getNodeFromFile(L"_rels/.rels");
if (!oRels.IsValid())
return;
sXml = L"<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
@ -816,23 +737,18 @@ public:
}
sXml += L"</Relationships>";
m_pZipFolder->writeXml(m_sFolder + L"/_rels/.rels", sXml);
m_pFolder->writeXml(L"_rels/.rels", sXml);
}
else
{
std::wstring sFileFound = sFile.substr(m_sFolder.length());
std::wstring::size_type posRemove = sFileFound.find(L"/_xmlsignatures/");
std::wstring sFileFound = m_pFolder->getLocalFilePath(sFile);
std::wstring::size_type posRemove = sFileFound.find(L"_xmlsignatures/");
if (std::wstring::npos != posRemove)
sFileFound = sFileFound.substr(posRemove + 16);
sFileFound = sFileFound.substr(posRemove + 15);
std::wstring sOriginRels = m_sFolder + L"/_xmlsignatures/_rels/origin.sigs.rels";
BYTE* pData = NULL;
DWORD dwLen = 0;
m_pZipFolder->read(sOriginRels, pData, dwLen);
XmlUtils::CXmlNode oRels;
if (!oRels.FromXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, dwLen)))
std::wstring sOriginRels = L"_xmlsignatures/_rels/origin.sigs.rels";
XmlUtils::CXmlNode oRels = m_pFolder->getNodeFromFile(sOriginRels);
if (!oRels.IsValid())
return;
sXml = L"<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
@ -856,7 +772,7 @@ public:
}
sXml += L"</Relationships>";
m_pZipFolder->writeXml(sOriginRels, sXml);
m_pFolder->writeXml(sOriginRels, sXml);
}
}
};
@ -890,16 +806,20 @@ COOXMLSignature* COOXMLVerifier::GetSignature(const int& index)
void COOXMLVerifier::RemoveSignature(const std::string& sGuid)
{
BYTE* pData = NULL;
DWORD dwLen = 0;
std::wstring sFolder = m_internal->m_sFolder;
if (sFolder.empty())
m_internal->m_pZipFolder->writeZipFolder(pData, dwLen);
m_internal->RemoveSignature(sGuid);
IFolder::CBuffer* buffer = m_internal->m_pFolder->finalize();
std::wstring folder = m_internal->m_pFolder->getFullFilePath(L"");
RELEASEOBJECT(m_internal);
if (sFolder.empty())
m_internal = new COOXMLVerifier_private(pData, dwLen);
if (buffer)
{
m_internal = new COOXMLVerifier_private(buffer->Buffer, buffer->Size);
buffer->UnsetDestroy();
delete buffer;
}
else
m_internal = new COOXMLVerifier_private(sFolder);
{
m_internal = new COOXMLVerifier_private(folder);
}
}

View File

@ -1,10 +1,10 @@
#ifndef _XML_RELS_H_
#define _XML_RELS_H_
#include "../../../xml/include/xmlutils.h"
#include "../../../common/StringBuilder.h"
#include "../../../common/File.h"
#include "../../../common/Directory.h"
#include "./ZipFolder.h"
class COOXMLRelationship
{
@ -67,11 +67,13 @@ class COOXMLRelationships
{
public:
std::vector<COOXMLRelationship> rels;
IFolder* m_pFolder;
public:
COOXMLRelationships()
{
m_pFolder = NULL;
}
COOXMLRelationships(const std::string& xml, std::map<std::wstring, bool>* check_need = NULL)
@ -83,18 +85,20 @@ public:
FromXmlNode(oNode, check_need);
}
COOXMLRelationships(const std::wstring& xml, const bool& is_file, std::map<std::wstring, bool>* check_need = NULL)
COOXMLRelationships(const std::wstring& xml, IFolder* pFolder, std::map<std::wstring, bool>* check_need = NULL)
{
XmlUtils::CXmlNode oNode;
if (!is_file)
if (NULL == pFolder)
{
if (!oNode.FromXmlString(xml))
return;
}
else
{
if (!oNode.FromXmlFile(xml))
m_pFolder = pFolder;
oNode = pFolder->getNodeFromFile(xml);
if (!oNode.IsValid())
return;
}
@ -161,16 +165,16 @@ public:
return builder.GetData();
}
void CheckOriginSigs(BYTE*& pData, LONG& nSize)
void CheckOriginSigs(const std::wstring& file)
{
int rId = 0;
std::wstring sReplace = L"";
std::string sReplace = "";
std::vector<COOXMLRelationship>::iterator i = rels.begin();
while (i != rels.end())
{
if (0 == i->target.find(L"_xmlsignatures/"))
{
sReplace = i->target;
sReplace = U_TO_UTF8(i->target);
break;
}
@ -187,31 +191,27 @@ public:
if (!sReplace.empty())
{
if (sReplace == L"_xmlsignatures/origin.sigs")
if (sReplace == "_xmlsignatures/origin.sigs")
return;
std::wstring sXml = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, nSize);
NSStringUtils::string_replace(sXml, sReplace, L"_xmlsignatures/origin.sigs");
RELEASEARRAYOBJECTS(pData);
NSFile::CUtf8Converter::GetUtf8StringFromUnicode(sXml.c_str(), sXml.length(), pData, nSize);
std::string sXmlA = m_pFolder->readXml(file);
NSStringUtils::string_replaceA(sXmlA, sReplace, "_xmlsignatures/origin.sigs");
m_pFolder->writeXmlA(file, sXmlA);
return;
}
std::wstring sXml = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pData, nSize);
std::string sXmlA = m_pFolder->readXml(file);
std::wstring::size_type pos = sXml.rfind(L"</Relationships>");
if (pos == std::wstring::npos)
std::string::size_type pos = sXmlA.rfind("</Relationships>");
if (pos == std::string::npos)
return;
rId++;
std::wstring sRet = sXml.substr(0, pos);
sRet += (L"<Relationship Id=\"rId" + std::to_wstring(rId) + L"\" \
std::string sRet = sXmlA.substr(0, pos);
sRet += ("<Relationship Id=\"rId" + std::to_string(rId) + "\" \
Type=\"http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin\" Target=\"_xmlsignatures/origin.sigs\"/>\
</Relationships>");
RELEASEARRAYOBJECTS(pData);
NSFile::CUtf8Converter::GetUtf8StringFromUnicode(sRet.c_str(), sRet.length(), pData, nSize);
m_pFolder->writeXmlA(file, sRet);
}
};

View File

@ -0,0 +1,352 @@
#ifndef _ZIPFOLDER_H_
#define _ZIPFOLDER_H_
#include "./../../../../OfficeUtils/src/ZipBuffer.h"
#include "./../../../common/File.h"
#include "./../../../common/Directory.h"
#include "../../../xml/include/xmlutils.h"
#include "./../include/XmlCertificate.h"
class IFolder
{
public:
class CBuffer
{
public:
BYTE* Buffer;
DWORD Size;
private:
bool m_bIsDestroy;
CBuffer(BYTE* data = NULL, DWORD size = 0, bool destroy = false)
{
Buffer = data;
Size = size;
m_bIsDestroy = destroy;
}
public:
~CBuffer()
{
if (m_bIsDestroy && Buffer != NULL)
delete [] Buffer;
}
void UnsetDestroy()
{
m_bIsDestroy = false;
}
friend class IFolder;
friend class CFolderSystem;
friend class CZipFolderMemory;
};
public:
// полный путь по локальному
virtual std::wstring getFullFilePath(const std::wstring& path) = 0;
// локальный путь по полному (без первого '/')
virtual std::wstring getLocalFilePath(const std::wstring& path) = 0;
// чтение файла в буффер. промежуточный класс нужен, чтобы
// одна реализация могли отдавать память напрямую, а другая выделять и не хранить у себя
virtual bool read(const std::wstring& path, CBuffer*& buffer) = 0;
// запись данных в файл
virtual void write(const std::wstring& path, BYTE* data, DWORD length) = 0;
// работа с файлами
virtual void move(const std::wstring& src, const std::wstring& dst) = 0;
virtual bool exists(const std::wstring& path) = 0;
virtual void remove(const std::wstring& path) = 0;
// работа с директориями
virtual void createDirectory(const std::wstring& path) = 0;
virtual std::vector<std::wstring> getFiles(const std::wstring& path, bool recursion) = 0;
// финализация
virtual CBuffer* finalize() { return NULL; }
// чтение ноды
virtual XmlUtils::CXmlNode getNodeFromFile(const std::wstring& path) = 0;
// вспомогательные функции
void writeXml(const std::wstring& path, const std::wstring& xml)
{
std::string sXmlUtf8 = U_TO_UTF8(xml);
write(path, (BYTE*)sXmlUtf8.c_str(), (DWORD)sXmlUtf8.length());
}
void writeXmlA(const std::wstring& path, const std::string& xml)
{
write(path, (BYTE*)xml.c_str(), (DWORD)xml.length());
}
std::string readXml(const std::wstring& path)
{
CBuffer* buffer = NULL;
if (!read(path, buffer))
return "";
std::string sXmlUtf8((char*)buffer->Buffer, (size_t)buffer->Size);
delete buffer;
return sXmlUtf8;
}
std::string getFileBase64(const std::wstring& path)
{
CBuffer* buffer = NULL;
if (!read(path, buffer))
return "";
char* pData = NULL;
int nLen = 0;
NSFile::CBase64Converter::Encode(buffer->Buffer, (int)buffer->Size, pData, nLen, NSBase64::B64_BASE64_FLAG_NOCRLF);
std::string sRet(pData, (size_t)nLen);
RELEASEARRAYOBJECTS(pData);
delete buffer;
return sRet;
}
std::string getFileHash(const std::wstring& path, ICertificate* certificate, int nAlg = -1)
{
CBuffer* buffer = NULL;
if (!read(path, buffer))
return "";
std::string sRet = certificate->GetHash(buffer->Buffer, buffer->Size, (nAlg == -1) ? certificate->GetHashAlg() : nAlg);
delete buffer;
return sRet;
}
std::wstring getFileHashW(const std::wstring& path, ICertificate* certificate, int nAlg = -1)
{
std::string sTmp = getFileHash(path, certificate, nAlg);
return UTF8_TO_U(sTmp);
}
};
class CFolderSystem : public IFolder
{
std::wstring m_sFolder;
void correct_folder(std::wstring& folder)
{
if (!folder.empty() && folder[folder.length() - 1] == '/')
folder.erase(folder.length() - 1, 1);
}
public:
CFolderSystem(const std::wstring& folder)
{
m_sFolder = folder;
#ifdef _WIN32
NSStringUtils::string_replace(m_sFolder, L"\\", L"/");
#endif
correct_folder(m_sFolder);
}
virtual std::wstring getFullFilePath(const std::wstring& path)
{
std::wstring full_path = path;
#ifdef _WIN32
NSStringUtils::string_replace(full_path, L"\\", L"/");
#endif
if (0 == full_path.find(m_sFolder))
return full_path;
if (!full_path.empty() && full_path[0] == L'/')
return m_sFolder + full_path;
return m_sFolder + L"/" + full_path;
}
virtual std::wstring getLocalFilePath(const std::wstring& path)
{
std::wstring local_path = path;
#ifdef _WIN32
NSStringUtils::string_replace(local_path, L"\\", L"/");
#endif
if (0 == local_path.find(m_sFolder))
return local_path.substr(m_sFolder.length() + 1);
if (!local_path.empty() && local_path[0] == L'/')
return local_path.substr(1);
return local_path;
}
virtual bool read(const std::wstring& path, CBuffer*& buffer)
{
buffer = NULL;
std::wstring sPath = getFullFilePath(path);
if (NSFile::CFileBinary::Exists(sPath))
{
BYTE* pData = NULL;
DWORD nSize = 0;
if (NSFile::CFileBinary::ReadAllBytes(sPath, &pData, nSize))
{
buffer = new CBuffer(pData, nSize, true);
return true;
}
}
return false;
}
virtual void write(const std::wstring& path, BYTE* data, DWORD length)
{
std::wstring sPath = getFullFilePath(path);
NSFile::CFileBinary::Remove(sPath);
NSFile::CFileBinary oFile;
oFile.CreateFileW(sPath);
oFile.WriteFile(data, length);
oFile.CloseFile();
}
virtual void move(const std::wstring& sSrc, const std::wstring& sDst)
{
NSFile::CFileBinary::Move(getFullFilePath(sSrc), getFullFilePath(sDst));
}
virtual bool exists(const std::wstring& path)
{
return NSFile::CFileBinary::Exists(getFullFilePath(path));
}
virtual void remove(const std::wstring& path)
{
NSFile::CFileBinary::Remove(getFullFilePath(path));
}
virtual void createDirectory(const std::wstring& path)
{
std::wstring sPath = getFullFilePath(path);
if (!NSDirectory::Exists(sPath))
NSDirectory::CreateDirectory(sPath);
}
virtual std::vector<std::wstring> getFiles(const std::wstring& path, bool bIsRecursion)
{
std::wstring folder = getFullFilePath(path);
correct_folder(folder);
std::vector<std::wstring> files = NSDirectory::GetFiles(folder, bIsRecursion);
#ifdef _WIN32
for (std::vector<std::wstring>::iterator i = files.begin(); i != files.end(); i++)
{
NSStringUtils::string_replace(*i, L"\\", L"/");
}
#endif
return files;
}
virtual XmlUtils::CXmlNode getNodeFromFile(const std::wstring& path)
{
XmlUtils::CXmlNode node;
node.FromXmlFile(getFullFilePath(path));
return node;
}
};
class CZipFolderMemory : public IFolder
{
CZipBuffer* m_zlib;
protected:
std::string getLocalFilePathA(const std::wstring& path)
{
if (!path.empty() && path[0] == L'/')
return U_TO_UTF8(path.substr(1));
return U_TO_UTF8(path);
}
public:
CZipFolderMemory(BYTE* data, DWORD length)
{
m_zlib = new CZipBuffer(data, length);
}
virtual std::wstring getFullFilePath(const std::wstring& path)
{
return path;
}
virtual std::wstring getLocalFilePath(const std::wstring& path)
{
if (!path.empty() && path[0] == L'/')
return path.substr(1);
return path;
}
virtual bool read(const std::wstring& path, CBuffer*& buffer)
{
buffer = NULL;
std::string sPath = getLocalFilePathA(path);
BYTE* pData = NULL;
DWORD nSize = 0;
m_zlib->getFile(sPath, pData, nSize);
if (nSize)
{
buffer = new CBuffer(pData, nSize, false);
return true;
}
return false;
}
virtual void write(const std::wstring& path, BYTE* data, DWORD length)
{
std::string sPath = getLocalFilePathA(path);
BYTE* copyData = new BYTE[length];
memcpy(copyData, data, length);
m_zlib->addFile(sPath, copyData, length);
}
virtual void move(const std::wstring& sSrc, const std::wstring& sDst)
{
// TODO: убрать копирование памяти
std::string sSrcPath = getLocalFilePathA(sSrc);
BYTE* data; DWORD length;
m_zlib->getFile(sSrcPath, data, length);
BYTE* copyData = new BYTE[length];
memcpy(copyData, data, length);
m_zlib->removeFile(sSrcPath);
m_zlib->addFile(getLocalFilePathA(sDst), copyData, length);
}
virtual bool exists(const std::wstring& path)
{
std::string sPath = getLocalFilePathA(path);
std::vector<std::string> sPaths = m_zlib->getPaths();
return std::find(sPaths.begin(), sPaths.end(), sPath) != sPaths.end();
}
virtual void remove(const std::wstring& path)
{
std::string sPath = getLocalFilePathA(path);
m_zlib->removeFile(sPath);
}
virtual void createDirectory(const std::wstring& path)
{
}
virtual std::vector<std::wstring> getFiles(const std::wstring& path, bool bIsRecursion)
{
std::string sPath = getLocalFilePathA(path);
std::vector<std::string> sPaths = m_zlib->getPaths();
std::vector<std::wstring> sRes;
for (std::string& i : sPaths)
{
if (bIsRecursion)
{
if (i.find(sPath) == 0)
sRes.push_back(L'/' + UTF8_TO_U(i));
}
else
{
size_t nFindDirectory = i.find(sPath);
if (nFindDirectory == 0)
{
nFindDirectory = i.find_first_of("\\/", sPath.length());
if (nFindDirectory != std::wstring::npos && i.find_first_of("\\/", nFindDirectory + 1) == std::wstring::npos)
sRes.push_back(L'/' + UTF8_TO_U(i));
}
}
}
return sRes;
}
virtual CBuffer* finalize()
{
BYTE* data = NULL;
DWORD length = 0;
m_zlib->save(data, length);
m_zlib->close();
return new CBuffer(data, length, true);
}
virtual XmlUtils::CXmlNode getNodeFromFile(const std::wstring& path)
{
CBuffer* buffer = NULL;
XmlUtils::CXmlNode node;
if (!read(path, buffer))
return node;
std::string sUtf8((char*)buffer->Buffer, (size_t)buffer->Size);
node.FromXmlStringA(sUtf8);
delete buffer;
return node;
}
};
#endif //_ZIPFOLDER_H_

View File

@ -7,6 +7,9 @@
//#define USE_MS_CRYPTO
#endif
#define USE_SIGN
//#define USE_VERIFY
int main()
{
std::wstring sTestDir = NSFile::GetProcessDirectory() + L"/../../";
@ -25,6 +28,7 @@ int main()
BYTE* pDataDst = NULL;
unsigned long nLenDst = 0;
#ifdef USE_SIGN
#if 0
COOXMLSigner oSigner(sTestDir + L"file", pCertificate);
oSigner.Sign(pDataDst, nLenDst);
@ -41,10 +45,23 @@ int main()
oFileDst.CreateFileW(sTestDir + L"/file2.docx");
oFileDst.WriteFile(pDataDst, nLenDst);
oFileDst.CloseFile();
#endif
#endif
RELEASEARRAYOBJECTS(pDataDst);
#ifdef USE_VERIFY
#if 1
COOXMLVerifier oVerifier(sTestDir + L"file");
int nCount = oVerifier.GetSignatureCount();
for (int i = 0; i < nCount; i++)
{
COOXMLSignature* pSign = oVerifier.GetSignature(i);
pSign->Check();
}
#endif
#endif
delete pCertificate;
return 0;
}

View File

@ -104,6 +104,7 @@ void CZipBuffer::open(BYTE* buffer, DWORD size)
if (file_info.uncompressed_size != 0)
m_arrFiles.push_back(CFile(get_filename_from_unzfile(uf), NULL, 0));
} while (UNZ_OK == unzGoToNextFile(uf));
unzClose(uf);
RELEASEOBJECT(buf);
}
void CZipBuffer::close()
@ -111,6 +112,8 @@ void CZipBuffer::close()
for (CFile& oFile : m_arrFiles)
RELEASEARRAYOBJECTS(oFile.m_pData);
m_arrFiles.clear();
RELEASEARRAYOBJECTS(m_zipFile);
}
std::vector<std::string> CZipBuffer::getPaths()
@ -171,7 +174,7 @@ void CZipBuffer::getFile(const std::string& sPath, BYTE*& data, DWORD& length)
buf->nSize = m_sizeZip;
unzFile uf = unzOpenHelp(buf);
data = new BYTE;
data = NULL;
length = 0;
get_file_in_archive(uf, sPath.c_str(), &data, length);
unzClose(uf);