Files
core/PdfFile/PdfEditor.cpp
2024-05-20 17:52:22 +03:00

1359 lines
35 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "PdfEditor.h"
#include "../DesktopEditor/common/Path.h"
#include "lib/xpdf/PDFDoc.h"
#include "lib/xpdf/AcroForm.h"
#include "lib/xpdf/TextString.h"
#include "lib/xpdf/Lexer.h"
#include "lib/xpdf/Parser.h"
#include "SrcWriter/Catalog.h"
#include "SrcWriter/EncryptDictionary.h"
#include "SrcWriter/Info.h"
#include "SrcWriter/ResourcesDictionary.h"
#include "SrcWriter/Streams.h"
#define AddToObject(oVal)\
{\
if (pObj->GetType() == PdfWriter::object_type_DICT)\
((PdfWriter::CDictObject*)pObj)->Add(sKey, oVal);\
else if (pObj->GetType() == PdfWriter::object_type_ARRAY)\
((PdfWriter::CArrayObject*)pObj)->Add(oVal);\
}
void DictToCDictObject(Object* obj, PdfWriter::CObjectBase* pObj, bool bBinary, const std::string& sKey, bool bUnicode = false)
{
Object oTemp;
switch (obj->getType())
{
case objBool:
{
bool b = obj->getBool();
AddToObject(b)
break;
}
case objInt:
{
AddToObject(obj->getInt())
break;
}
case objReal:
{
AddToObject(obj->getReal())
break;
}
case objString:
{
if (bBinary)
{
GString* str = obj->getString();
int nLength = str->getLength();
BYTE* arrId = new BYTE[nLength];
for (int nIndex = 0; nIndex < nLength; ++nIndex)
arrId[nIndex] = str->getChar(nIndex);
AddToObject(new PdfWriter::CBinaryObject(arrId, nLength));
RELEASEARRAYOBJECTS(arrId);
}
else
{
TextString* s = new TextString(obj->getString());
std::string sValue = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
AddToObject(new PdfWriter::CStringObject(sValue.c_str(), bUnicode))
delete s;
}
break;
}
case objName:
{
AddToObject(obj->getName())
break;
}
case objNull:
{
AddToObject(new PdfWriter::CNullObject())
break;
}
case objArray:
{
PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject();
AddToObject(pArray)
for (int nIndex = 0; nIndex < obj->arrayGetLength(); ++nIndex)
{
obj->arrayGetNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pArray, bBinary, "");
oTemp.free();
}
break;
}
case objDict:
{
PdfWriter::CDictObject* pDict = new PdfWriter::CDictObject();
AddToObject(pDict);
for (int nIndex = 0; nIndex < obj->dictGetLength(); ++nIndex)
{
char* chKey = obj->dictGetKey(nIndex);
obj->dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pDict, bBinary, chKey);
oTemp.free();
}
break;
}
case objRef:
{
PdfWriter::CObjectBase* pBase = new PdfWriter::CObjectBase();
pBase->SetRef(obj->getRefNum(), obj->getRefGen());
AddToObject(new PdfWriter::CProxyObject(pBase, true))
break;
}
case objNone:
{
AddToObject("None")
break;
}
case objStream:
case objCmd:
case objError:
case objEOF:
break;
}
}
PdfWriter::CDictObject* GetWidgetParent(PDFDoc* pdfDoc, PdfWriter::CDocument* pDoc, Object* pParentRef)
{
PdfWriter::CDictObject* pParent = pDoc->GetParent(pParentRef->getRefNum());
if (pParent)
return pParent;
if (!pParentRef || !pParentRef->isRef() || !pdfDoc)
return pParent;
XRef* xref = pdfDoc->getXRef();
Object oParent;
if (!pParentRef->fetch(xref, &oParent)->isDict())
{
oParent.free();
return pParent;
}
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, pParentRef->getRefNum());
pParent = new PdfWriter::CDictObject();
pXref->Add(pParent, pParentRef->getRefGen());
if (!pDoc->EditParent(pXref, pParent, pParentRef->getRefNum()))
{
RELEASEOBJECT(pXref);
oParent.free();
return NULL;
}
for (int i = 0; i < oParent.dictGetLength(); ++i)
{
char* chKey = oParent.dictGetKey(i);
if (strcmp("Parent", chKey) == 0)
{
Object oParentRef;
oParent.dictGetValNF(i, &oParentRef);
PdfWriter::CDictObject* pParent2 = GetWidgetParent(pdfDoc, pDoc, &oParentRef);
if (pParent2)
{
pParent->Add("Parent", pParent2);
oParentRef.free();
continue;
}
oParentRef.free();
}
Object oTemp;
oParent.dictGetValNF(i, &oTemp);
DictToCDictObject(&oTemp, pParent, false, chKey);
oTemp.free();
}
oParent.free();
return pParent;
}
HRESULT _ChangePassword(const std::wstring& wsPath, const std::wstring& wsPassword, CPdfReader* _pReader, CPdfWriter* _pWriter)
{
if (!_pReader || !_pWriter)
return S_FALSE;
PDFDoc* pPDFDocument = _pReader->GetPDFDocument();
if (!pPDFDocument)
return S_FALSE;
XRef* xref = pPDFDocument->getXRef();
if (!xref)
return S_FALSE;
Object* trailerDict = xref->getTrailerDict();
if (!trailerDict)
return S_FALSE;
PdfWriter::CDocument* pDoc = _pWriter->GetDocument();
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, 0);
PdfWriter::CXref* m_pXref = new PdfWriter::CXref(pDoc, xref->getNumObjects()); // Для новых объектов
if (!xref || !pDoc || !pXref || !m_pXref)
{
RELEASEOBJECT(pXref);
RELEASEOBJECT(m_pXref);
return S_FALSE;
}
pXref->SetPrev(m_pXref);
for (int i = 0; i < xref->getSize(); ++i)
{
XRefEntry* pEntry = xref->getEntry(i);
if (pEntry->type == xrefEntryFree)
continue;
if (i != pXref->GetSizeXRef())
{
PdfWriter::CXref* pXref2 = new PdfWriter::CXref(pDoc, i);
pXref2->SetPrev(pXref);
pXref = pXref2;
}
Object oTemp;
xref->fetch(i, pEntry->gen, &oTemp);
PdfWriter::CObjectBase* pObj = NULL;
switch (oTemp.getType())
{
case objBool:
{
pObj = new PdfWriter::CBoolObject(oTemp.getBool());
break;
}
case objInt:
{
pObj = new PdfWriter::CNumberObject(oTemp.getInt());
break;
}
case objReal:
{
pObj = new PdfWriter::CRealObject(oTemp.getReal());
break;
}
case objString:
{
TextString* s = new TextString(oTemp.getString());
std::string sValue = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
pObj = new PdfWriter::CStringObject(sValue.c_str());
delete s;
break;
}
case objName:
{
pObj = new PdfWriter::CNameObject(oTemp.getName());
break;
}
case objNull:
{
pObj = new PdfWriter::CNullObject();
break;
}
case objArray:
{
pObj = new PdfWriter::CArrayObject();
for (int nIndex = 0; nIndex < oTemp.arrayGetLength(); ++nIndex)
{
Object oT;
oTemp.arrayGetNF(nIndex, &oT);
DictToCDictObject(&oT, pObj, false, "");
oT.free();
}
break;
}
case objDict:
{
pObj = new PdfWriter::CDictObject();
for (int nIndex = 0; nIndex < oTemp.dictGetLength(); ++nIndex)
{
Object oT;
char* chKey = oTemp.dictGetKey(nIndex);
oTemp.dictGetValNF(nIndex, &oT);
DictToCDictObject(&oT, pObj, false, chKey);
oT.free();
}
break;
}
case objRef:
{
PdfWriter::CObjectBase* pBase = new PdfWriter::CObjectBase();
pBase->SetRef(oTemp.getRefNum(), oTemp.getRefGen());
pObj = new PdfWriter::CProxyObject(pBase, true);
break;
}
case objStream:
{
Dict* pDict = oTemp.streamGetDict();
Object oObjStm;
if (pDict->lookup("Type", &oObjStm)->isName("ObjStm"))
{
oObjStm.free();
break;
}
oObjStm.free();
PdfWriter::CDictObject* pDObj = new PdfWriter::CDictObject();
pObj = pDObj;
int nLength = 0;
for (int nIndex = 0; nIndex < pDict->getLength(); ++nIndex)
{
Object oT;
char* chKey = pDict->getKey(nIndex);
if (strcmp("Length", chKey) == 0)
{
Object oLength;
nLength = pDict->getVal(nIndex, &oLength)->isInt() ? oLength.getInt() : 0;
oLength.free();
continue;
}
pDict->getValNF(nIndex, &oT);
DictToCDictObject(&oT, pObj, false, chKey);
oT.free();
}
PdfWriter::CStream* pStream = new PdfWriter::CMemoryStream();
pDObj->SetStream(m_pXref, pStream, false);
Stream* pImage = oTemp.getStream()->getUndecodedStream();
pImage->reset();
for (int nI = 0; nI < nLength; ++nI)
pStream->WriteChar(pImage->getChar());
break;
}
case objNone:
case objCmd:
case objError:
case objEOF:
default:
break;
}
oTemp.free();
if (pObj)
pXref->Add(pObj);
}
PdfWriter::CDictObject* pTrailer = pXref->GetTrailer();
for (int nIndex = 0; nIndex < trailerDict->dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = trailerDict->dictGetKey(nIndex);
if (strcmp("Root", chKey) == 0 || strcmp("Info", chKey) == 0)
{
trailerDict->dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pTrailer, true, chKey);
}
oTemp.free();
}
bool bRes = pDoc->SaveNewWithPassword(pXref, m_pXref, wsPath, wsPassword, wsPassword, pTrailer);
RELEASEOBJECT(pXref);
return bRes ? S_OK : S_FALSE;
}
CPdfEditor::CPdfEditor(const std::wstring& _wsSrcFile, const std::wstring& _wsPassword, CPdfReader* _pReader, const std::wstring& _wsDstFile, CPdfWriter* _pWriter)
{
wsSrcFile = _wsSrcFile;
wsPassword = _wsPassword;
pReader = _pReader;
pWriter = _pWriter;
bEditPage = false;
nError = 0;
PDFDoc* pPDFDocument = pReader->GetPDFDocument();
if (!pPDFDocument)
{
nError = 1;
return;
}
// Если результат редактирования будет сохранен в тот же файл, что открыт для чтения, то файл необходимо сделать редактируемым
std::string sPathUtf8New = U_TO_UTF8(_wsDstFile);
std::string sPathUtf8Old = U_TO_UTF8(wsSrcFile);
if (sPathUtf8Old == sPathUtf8New || NSSystemPath::NormalizePath(sPathUtf8Old) == NSSystemPath::NormalizePath(sPathUtf8New))
{
GString* owner_pswd = NSStrings::CreateString(wsPassword);
GString* user_pswd = NSStrings::CreateString(wsPassword);
GBool bRes = pPDFDocument->makeWritable(true, owner_pswd, user_pswd);
delete owner_pswd;
delete user_pswd;
if (!bRes)
{
nError = 2; // Не удалось проверить файл для записи
return;
}
}
else
{
if (!NSFile::CFileBinary::Copy(wsSrcFile, _wsDstFile))
{
nError = 2;
return;
}
NSFile::CFileBinary oFile;
if (!oFile.OpenFile(_wsDstFile, true))
{
nError = 2;
return;
}
oFile.CloseFile();
}
XRef* xref = pPDFDocument->getXRef();
PdfWriter::CDocument* pDoc = pWriter->GetDocument();
if (!xref || !pDoc)
{
nError = 1;
return;
}
// Получение каталога и дерева страниц из reader
Object catDict, catRefObj, pagesRefObj;
if (!xref->getCatalog(&catDict) || !catDict.isDict() || !catDict.dictLookupNF("Pages", &pagesRefObj))
{
pagesRefObj.free();
catDict.free();
nError = 3; // Не удалось получить каталог и дерево страниц
return;
}
Object* trailer = xref->getTrailerDict();
if (!trailer || !trailer->isDict() || !trailer->dictLookupNF("Root", &catRefObj) || !catRefObj.isRef())
{
pagesRefObj.free();
catDict.free();
catRefObj.free();
nError = 3; // Не удалось получить каталог и дерево страниц
return;
}
Ref catRef = catRefObj.getRef();
catRefObj.free();
// Создание каталога для writer
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, catRef.num);
if (!pXref)
{
pagesRefObj.free();
catDict.free();
nError = 1;
return;
}
PdfWriter::CCatalog* pCatalog = new PdfWriter::CCatalog();
if (!pCatalog)
{
pagesRefObj.free();
catDict.free();
RELEASEOBJECT(pXref);
nError = 1;
return;
}
pXref->Add(pCatalog, catRef.gen);
PdfWriter::CResourcesDict* pDR = NULL;
PdfWriter::CXref* pDRXref = NULL;
for (int nIndex = 0; nIndex < catDict.dictGetLength(); ++nIndex)
{
Object oAcroForm;
char* chKey = catDict.dictGetKey(nIndex);
if (strcmp("AcroForm", chKey) == 0)
{
catDict.dictGetVal(nIndex, &oAcroForm);
PdfWriter::CDictObject* pAcroForm = new PdfWriter::CDictObject();
for (int nIndex = 0; nIndex < oAcroForm.dictGetLength(); ++nIndex)
{
Object oTemp2;
char* chKey = oAcroForm.dictGetKey(nIndex);
if (strcmp("DR", chKey) == 0)
{
oAcroForm.dictGetVal(nIndex, &oTemp2);
if (!oTemp2.isDict())
{
oTemp2.free();
continue;
}
Object oDR;
oAcroForm.dictGetValNF(nIndex, &oDR);
int nDRxrefNum = oDR.isRef() ? oDR.getRefNum() : xref->getNumObjects();
int nDRxrefGen = oDR.isRef() ? oDR.getRefGen() : 0;
oDR.free();
pDRXref = new PdfWriter::CXref(pDoc, nDRxrefNum);
pDR = new PdfWriter::CResourcesDict(NULL, true, false);
pDRXref->Add(pDR, nDRxrefGen);
pAcroForm->Add(chKey, pDR);
for (int nIndex2 = 0; nIndex2 < oTemp2.dictGetLength(); ++nIndex2)
{
Object oTemp;
char* chKey = oTemp2.dictGetKey(nIndex2);
oTemp2.dictGetVal(nIndex2, &oTemp);
DictToCDictObject(&oTemp, pDR, false, chKey);
oTemp.free();
}
oTemp2.free();
pDR->Fix();
continue;
}
else
oAcroForm.dictGetValNF(nIndex, &oTemp2);
DictToCDictObject(&oTemp2, pAcroForm, false, chKey);
oTemp2.free();
}
if (!pAcroForm->Get("Fields"))
pAcroForm->Add("Fields", new PdfWriter::CArrayObject());
oAcroForm.free();
pCatalog->Add(chKey, pAcroForm);
continue;
}
else
catDict.dictGetValNF(nIndex, &oAcroForm);
DictToCDictObject(&oAcroForm, pCatalog, false, chKey);
oAcroForm.free();
}
catDict.free();
// Проверка уникальности имён текущих цифровых подписей pdf
unsigned int nFormField = 0;
AcroForm* form = pPDFDocument->getCatalog()->getForm();
if (form)
{
nFormField = form->getNumFields() + 1;
std::wstring sSig = L"Sig" + std::to_wstring(nFormField);
int i = 0, nFormFields = form->getNumFields();
while (i < nFormFields)
{
int nLength;
Unicode* uName = form->getField(i)->getName(&nLength);
std::wstring sName = NSStringExt::CConverter::GetUnicodeFromUTF32(uName, nLength);
RELEASEMEM(uName);
if (sName == sSig)
{
i = 0;
nFormField++;
sSig = L"Sig" + std::to_wstring(nFormField);
}
else
i++;
}
nFormField--;
}
// Получение шифрования из reader и применения для writer
int nCryptAlgorithm = -1;
PdfWriter::CEncryptDict* pEncryptDict = NULL;
if (xref->isEncrypted())
{
CryptAlgorithm encAlgorithm;
GBool ownerPasswordOk;
int permFlags, keyLength, encVersion;
xref->getEncryption(&permFlags, &ownerPasswordOk, &keyLength, &encVersion, &encAlgorithm);
nCryptAlgorithm = encAlgorithm;
Object* pTrailerDict = xref->getTrailerDict();
if (pTrailerDict)
{
pEncryptDict = new PdfWriter::CEncryptDict();
// Нужно получить словарь Encrypt БЕЗ дешифровки, поэтому времено отключаем encrypted в xref
xref->offEncrypted();
Object encrypt, ID, ID1;
if (pTrailerDict->dictLookup("Encrypt", &encrypt) && encrypt.isDict())
{
for (int nIndex = 0; nIndex < encrypt.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = encrypt.dictGetKey(nIndex);
encrypt.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pEncryptDict, true, chKey);
oTemp.free();
}
}
if (!pEncryptDict->Get("Length"))
pEncryptDict->Add("Length", 40);
encrypt.free();
if (pTrailerDict->dictLookup("ID", &ID) && ID.isArray() && ID.arrayGet(0, &ID1) && ID1.isString())
DictToCDictObject(&ID1, pEncryptDict, true, "ID");
ID.free(); ID1.free();
xref->onEncrypted();
pEncryptDict->SetRef(0, 0);
pEncryptDict->Fix();
pEncryptDict->SetPasswords(wsPassword, wsPassword);
if (!pEncryptDict->UpdateKey(nCryptAlgorithm))
{
pagesRefObj.free();
RELEASEOBJECT(pXref);
RELEASEOBJECT(pDRXref);
nError = 4; // Ошибка шифрования файла
return;
}
}
}
// Применение редактирования для writer
bool bRes = pDoc->EditPdf(_wsDstFile, xref->getLastXRefPos(), xref->getNumObjects() + 1, pXref, pCatalog, pEncryptDict, nFormField);
if (bRes)
{
// Воспроизведение дерева страниц во writer
GetPageTree(xref, &pagesRefObj);
if (pDR && pDRXref)
bRes = pDoc->EditResources(pDRXref, pDR);
}
pagesRefObj.free();
if (!bRes)
nError = 5; // Ошибка применения редактирования
}
void CPdfEditor::Close()
{
PDFDoc* pPDFDocument = pReader->GetPDFDocument();
PdfWriter::CDocument* pDoc = pWriter->GetDocument();
if (!pPDFDocument || !pDoc)
return;
XRef* xref = pPDFDocument->getXRef();
if (!xref)
return;
// Добавляем первый элемент в таблицу xref
// он должен иметь вид 0000000000 65535 f
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, 0, 65535);
if (!pXref)
return;
PdfWriter::CDictObject* pTrailer = NULL;
Object* trailerDict = xref->getTrailerDict();
if (trailerDict)
{
pTrailer = pXref->GetTrailer();
for (int nIndex = 0; nIndex < trailerDict->dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = trailerDict->dictGetKey(nIndex);
trailerDict->dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pTrailer, true, chKey);
oTemp.free();
}
}
Object info;
pPDFDocument->getDocInfo(&info);
PdfWriter::CXref* pInfoXref = NULL;
PdfWriter::CInfoDict* pInfoDict = NULL;
if (info.isDict())
{
// Обновление Info
PdfWriter::CObjectBase* pInfo = pTrailer->Get("Info");
pInfoXref = new PdfWriter::CXref(pDoc, pInfo ? pInfo->GetObjId() : 0);
if (!pInfoXref)
{
RELEASEOBJECT(pXref);
return;
}
pInfoDict = new PdfWriter::CInfoDict();
if (!pInfoDict)
{
RELEASEOBJECT(pXref);
RELEASEOBJECT(pInfoXref);
return;
}
pInfoXref->Add(pInfoDict, pInfo ? pInfo->GetGenNo() : 0);
for (int nIndex = 0; nIndex < info.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = info.dictGetKey(nIndex);
info.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pInfoDict, true, chKey);
oTemp.free();
}
pInfoDict->SetTime(PdfWriter::InfoModaDate);
}
info.free();
if (!pWriter->EditClose() || !pDoc->AddToFile(pXref, pTrailer, pInfoXref, pInfoDict))
{
RELEASEOBJECT(pXref);
return;
}
std::wstring wsPath = pDoc->GetEditPdfPath();
std::string sPathUtf8New = U_TO_UTF8(wsPath);
std::string sPathUtf8Old = U_TO_UTF8(wsSrcFile);
if (sPathUtf8Old == sPathUtf8New || NSSystemPath::NormalizePath(sPathUtf8Old) == NSSystemPath::NormalizePath(sPathUtf8New))
{
GString* owner_pswd = NSStrings::CreateString(wsPassword);
GString* user_pswd = NSStrings::CreateString(wsPassword);
pPDFDocument->makeWritable(false, owner_pswd, user_pswd);
delete owner_pswd;
delete user_pswd;
NSFile::CFileBinary oFile;
if (oFile.OpenFile(wsSrcFile))
{
pReader->ChangeLength(oFile.GetFileSize());
oFile.CloseFile();
}
}
pReader = NULL;
pWriter = NULL;
bEditPage = false;
}
int CPdfEditor::GetError()
{
return nError;
}
void CPdfEditor::GetPageTree(XRef* xref, Object* pPagesRefObj)
{
PdfWriter::CDocument* pDoc = pWriter->GetDocument();
if (!pPagesRefObj || !xref || !pDoc)
return;
Object typeDict, pagesObj;
if (!pPagesRefObj->isRef() || !pPagesRefObj->fetch(xref, &pagesObj)->isDict())
{
pagesObj.free();
return;
}
if (pagesObj.dictLookup("Type", &typeDict)->isName() && !typeDict.isName("Pages"))
{
pagesObj.free();
typeDict.free();
return;
}
typeDict.free();
Ref topPagesRef = pPagesRefObj->getRef();
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, topPagesRef.num);
if (!pXref)
{
pagesObj.free();
return;
}
PdfWriter::CPageTree* pPageT = new PdfWriter::CPageTree();
if (!pPageT)
{
pagesObj.free();
RELEASEOBJECT(pXref);
return;
}
pXref->Add(pPageT, topPagesRef.gen);
for (int nIndex = 0; nIndex < pagesObj.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = pagesObj.dictGetKey(nIndex);
pagesObj.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pPageT, false, chKey);
oTemp.free();
}
pDoc->CreatePageTree(pXref, pPageT);
pPageT->Fix();
Object kidsArrObj;
if (!pagesObj.dictLookup("Kids", &kidsArrObj)->isArray())
{
pagesObj.free();
kidsArrObj.free();
return;
}
pagesObj.free();
for (int i = 0, count = kidsArrObj.arrayGetLength(); i < count; ++i)
{
Object kidRefObj;
if (kidsArrObj.arrayGetNF(i, &kidRefObj))
GetPageTree(xref, &kidRefObj);
kidRefObj.free();
}
kidsArrObj.free();
}
bool CPdfEditor::EditPage(int nPageIndex)
{
PDFDoc* pPDFDocument = pReader->GetPDFDocument();
PdfWriter::CDocument* pDoc = pWriter->GetDocument();
if (!pPDFDocument || !pDoc)
return false;
PdfWriter::CPage* pEditPage = pDoc->GetEditPage(nPageIndex);
if (pEditPage)
{
pDoc->SetCurPage(pEditPage);
pWriter->EditPage(pEditPage);
return true;
}
XRef* xref = pPDFDocument->getXRef();
Catalog* pCatalog = pPDFDocument->getCatalog();
if (!xref || !pCatalog)
return false;
std::pair<int, int> pPageRef = pDoc->GetPageRef(nPageIndex);
if (pPageRef.first == 0)
return false;
// Получение объекта страницы
Object pageRefObj, pageObj;
pageRefObj.initRef(pPageRef.first, pPageRef.second);
if (!pageRefObj.fetch(xref, &pageObj) || !pageObj.isDict())
{
pageObj.free();
pageRefObj.free();
return false;
}
pageRefObj.free();
// Воспроизведение словаря страницы из reader для writer
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, pPageRef.first);
if (!pXref)
{
pageObj.free();
return false;
}
PdfWriter::CPage* pPage = new PdfWriter::CPage(pDoc);
if (!pPage)
{
pageObj.free();
RELEASEOBJECT(pXref);
return false;
}
pXref->Add(pPage, pPageRef.second);
for (int nIndex = 0; nIndex < pageObj.dictGetLength(); ++nIndex)
{
Object oTemp;
char* chKey = pageObj.dictGetKey(nIndex);
if (strcmp("Resources", chKey) == 0)
pageObj.dictGetVal(nIndex, &oTemp);
else if (strcmp("Annots", chKey) == 0)
{
// ВРЕМЕНО удаление Link аннотаций при редактировании
if (pageObj.dictGetVal(nIndex, &oTemp)->isArray())
{
PdfWriter::CArrayObject* pArray = new PdfWriter::CArrayObject();
pPage->Add("Annots", pArray);
for (int nIndex = 0; nIndex < oTemp.arrayGetLength(); ++nIndex)
{
Object oAnnot, oSubtype;
if (oTemp.arrayGet(nIndex, &oAnnot)->isDict("Annot") && oAnnot.dictLookup("Subtype", &oSubtype)->isName("Link"))
{
oAnnot.free(); oSubtype.free();
continue;
}
oAnnot.free(); oSubtype.free();
oTemp.arrayGetNF(nIndex, &oAnnot);
DictToCDictObject(&oAnnot, pArray, false, "");
oAnnot.free();
}
oTemp.free();
continue;
}
else
{
oTemp.free();
pageObj.dictGetValNF(nIndex, &oTemp);
}
}
else if (strcmp("Contents", chKey) == 0)
{
if (pageObj.dictGetVal(nIndex, &oTemp)->isArray())
{
DictToCDictObject(&oTemp, pPage, true, chKey);
oTemp.free();
continue;
}
else
{
oTemp.free();
pageObj.dictGetValNF(nIndex, &oTemp);
}
}
else
pageObj.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pPage, true, chKey);
oTemp.free();
}
pPage->Fix();
pageObj.free();
// Применение редактирования страницы для writer
if (pWriter->EditPage(pPage) && pDoc->EditPage(pXref, pPage, nPageIndex))
{
bEditPage = true;
return true;
}
RELEASEOBJECT(pXref);
return false;
}
bool CPdfEditor::DeletePage(int nPageIndex)
{
return pWriter->GetDocument()->DeletePage(nPageIndex);
}
bool CPdfEditor::AddPage(int nPageIndex)
{
// Применение добавления страницы для writer
if (!pWriter->AddPage(nPageIndex))
return false;
// По умолчанию выставляются размеры первой страницы, в дальнейшем размеры можно изменить
double dPageDpiX, dPageDpiY;
double dWidth, dHeight;
pReader->GetPageInfo(0, &dWidth, &dHeight, &dPageDpiX, &dPageDpiY);
dWidth *= 25.4 / dPageDpiX;
dHeight *= 25.4 / dPageDpiY;
pWriter->put_Width(dWidth);
pWriter->put_Height(dHeight);
return true;
}
bool CPdfEditor::EditAnnot(int nPageIndex, int nID)
{
PDFDoc* pPDFDocument = pReader->GetPDFDocument();
PdfWriter::CDocument* pDoc = pWriter->GetDocument();
if (!pPDFDocument || !pDoc)
return false;
PdfWriter::CPage* pEditPage = pDoc->GetEditPage(nPageIndex);
if (!pEditPage)
{
pEditPage = pDoc->GetCurPage();
EditPage(nPageIndex);
pDoc->SetCurPage(pEditPage);
pWriter->EditPage(pEditPage);
}
XRef* xref = pPDFDocument->getXRef();
std::pair<int, int> pPageRef = pDoc->GetPageRef(nPageIndex);
if (!xref || pPageRef.first == 0)
return false;
// Получение объекта аннотации
Object pageRefObj, pageObj, oAnnots;
pageRefObj.initRef(pPageRef.first, pPageRef.second);
if (!pageRefObj.fetch(xref, &pageObj)->isDict() || !pageObj.dictLookup("Annots", &oAnnots)->isArray())
{
pageRefObj.free(); pageObj.free(); oAnnots.free();
return false;
}
pageRefObj.free(); pageObj.free();
Object oAnnotRef, oAnnot, oType;
for (int i = 0; i < oAnnots.arrayGetLength(); ++i)
{
if (oAnnots.arrayGetNF(i, &oAnnotRef)->isRef() && oAnnotRef.getRefNum() == nID)
break;
oAnnotRef.free();
}
oAnnots.free();
if (!oAnnotRef.isRef() || !oAnnotRef.fetch(xref, &oAnnot)->isDict() || !oAnnot.dictLookup("Subtype", &oType)->isName())
{
oAnnotRef.free(); oAnnot.free(); oType.free();
return false;
}
// Воспроизведение словаря аннотации из reader для writer
PdfWriter::CXref* pXref = new PdfWriter::CXref(pDoc, oAnnotRef.getRefNum());
if (!pXref)
{
oAnnotRef.free(); oAnnot.free(); oType.free();
return false;
}
bool bIsWidget = false;
PdfWriter::CAnnotation* pAnnot = NULL;
if (oType.isName("Text"))
pAnnot = new PdfWriter::CTextAnnotation(pXref);
else if (oType.isName("Ink"))
pAnnot = new PdfWriter::CInkAnnotation(pXref);
else if (oType.isName("Line"))
pAnnot = new PdfWriter::CLineAnnotation(pXref);
else if (oType.isName("Highlight") || oType.isName("Underline") || oType.isName("Squiggly") || oType.isName("StrikeOut"))
pAnnot = new PdfWriter::CTextMarkupAnnotation(pXref);
else if (oType.isName("Square") || oType.isName("Circle"))
pAnnot = new PdfWriter::CSquareCircleAnnotation(pXref);
else if (oType.isName("Polygon") || oType.isName("PolyLine"))
pAnnot = new PdfWriter::CPolygonLineAnnotation(pXref);
else if (oType.isName("FreeText"))
{
std::map<std::wstring, std::wstring> mapFont = pReader->AnnotFonts(&oAnnotRef);
m_mFonts.insert(mapFont.begin(), mapFont.end());
pAnnot = new PdfWriter::CFreeTextAnnotation(pXref);
}
else if (oType.isName("Caret"))
pAnnot = new PdfWriter::CCaretAnnotation(pXref);
else if (oType.isName("Popup"))
pAnnot = new PdfWriter::CPopupAnnotation(pXref);
else if (oType.isName("Widget"))
{
bIsWidget = true;
char* sName = NULL;
Object oFT;
if (oAnnot.dictLookup("FT", &oFT)->isName())
sName = oFT.getName();
if (!sName)
{
Object oParent, oParent2;
oAnnot.dictLookup("Parent", &oParent);
while (oParent.isDict())
{
if (oParent.dictLookup("FT", &oFT)->isName())
{
sName = oFT.getName();
break;
}
oFT.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
}
oParent.free();
}
if (sName)
{
if (strcmp("Btn", sName) == 0)
{
bool bPushButton = false;
oFT.free();
int nFf = 0;
if (oAnnot.dictLookup("Ff", &oFT)->isInt())
nFf = oFT.getInt();
if (!nFf)
{
Object oParent, oParent2;
oAnnot.dictLookup("Parent", &oParent);
while (oParent.isDict())
{
if (oParent.dictLookup("Ff", &oFT)->isInt())
{
nFf = oFT.getInt();
break;
}
oFT.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
}
oParent.free();
}
bPushButton = (bool)((nFf >> 16) & 1);
if (bPushButton)
pAnnot = new PdfWriter::CPushButtonWidget(pXref);
else
pAnnot = new PdfWriter::CCheckBoxWidget(pXref);
}
else if (strcmp("Tx", sName) == 0)
pAnnot = new PdfWriter::CTextWidget(pXref);
else if (strcmp("Ch", sName) == 0)
pAnnot = new PdfWriter::CChoiceWidget(pXref);
else if (strcmp("Sig", sName) == 0)
pAnnot = new PdfWriter::CSignatureWidget(pXref);
else
pAnnot = new PdfWriter::CWidgetAnnotation(pXref, PdfWriter::EAnnotType::AnnotWidget);
}
oFT.free();
}
oType.free();
if (!pAnnot)
{
oAnnotRef.free(); oAnnot.free();
RELEASEOBJECT(pXref);
return false;
}
pXref->Add(pAnnot, oAnnotRef.getRefGen());
for (int nIndex = 0; nIndex < oAnnot.dictGetLength(); ++nIndex)
{
char* chKey = oAnnot.dictGetKey(nIndex);
if (strcmp("Popup", chKey) == 0)
{
Object oPopupRef;
if (oAnnot.dictGetValNF(nIndex, &oPopupRef)->isRef() && EditAnnot(nPageIndex, oPopupRef.getRefNum()))
{
PdfWriter::CAnnotation* pPopup = pDoc->GetAnnot(oPopupRef.getRefNum());
if (pPopup)
{
pAnnot->Add("Popup", pPopup);
pPopup->Add("Parent", pAnnot);
}
}
continue;
}
if (strcmp("Parent", chKey) == 0 && bIsWidget)
{
Object oParentRef;
oAnnot.dictGetValNF(nIndex, &oParentRef);
PdfWriter::CDictObject* pParent = GetWidgetParent(pPDFDocument, pDoc, &oParentRef);
if (!pParent)
{
oParentRef.free();
continue;
}
((PdfWriter::CWidgetAnnotation*)pAnnot)->SetParent(pParent);
PdfWriter::CArrayObject* pKids = dynamic_cast<PdfWriter::CArrayObject*>(pParent->Get("Kids"));
if (!pKids)
{
oParentRef.free();
continue;
}
for (int i = 0; i < pKids->GetCount(); ++i)
{
PdfWriter::CObjectBase* pKid = pKids->Get(i);
if (pKid->GetObjId() == oAnnotRef.getRefNum())
{
pKids->Insert(pKid, pAnnot, true);
break;
}
}
oParentRef.free();
}
Object oTemp;
oAnnot.dictGetValNF(nIndex, &oTemp);
DictToCDictObject(&oTemp, pAnnot, false, chKey);
oTemp.free();
}
oAnnotRef.free(); oAnnot.free();
if (pDoc->EditAnnot(pXref, pAnnot, nID))
return true;
RELEASEOBJECT(pXref);
return false;
}
bool CPdfEditor::DeleteAnnot(int nID)
{
PDFDoc* pPDFDocument = pReader->GetPDFDocument();
PdfWriter::CDocument* pDoc = pWriter->GetDocument();
if (!pPDFDocument || !pDoc)
return false;
XRef* xref = pPDFDocument->getXRef();
std::pair<int, int> pPageRef;
pPageRef.first = pDoc->GetCurPage()->GetObjId();
pPageRef.second = pDoc->GetCurPage()->GetGenNo();
if (!xref || pPageRef.first == 0)
return false;
// Получение объекта аннотации
Object pageRefObj, pageObj, oAnnots;
pageRefObj.initRef(pPageRef.first, pPageRef.second);
if (!pageRefObj.fetch(xref, &pageObj)->isDict() || !pageObj.dictLookup("Annots", &oAnnots)->isArray())
{
pageRefObj.free(); pageObj.free(); oAnnots.free();
return false;
}
pageRefObj.free(); pageObj.free();
bool bRes = false;
for (int i = 0; i < oAnnots.arrayGetLength(); ++i)
{
Object oAnnotRef, oAnnot;
if (oAnnots.arrayGetNF(i, &oAnnotRef)->isRef() && oAnnotRef.getRefNum() == nID)
{
bRes = pDoc->DeleteAnnot(oAnnotRef.getRefNum(), oAnnotRef.getRefGen());
if (oAnnotRef.fetch(xref, &oAnnot)->isDict())
{
Object oPopupRef;
if (oAnnot.dictLookupNF("Popup", &oPopupRef)->isRef())
pDoc->DeleteAnnot(oPopupRef.getRefNum(), oPopupRef.getRefGen());
oPopupRef.free();
}
}
else if (oAnnots.arrayGet(i, &oAnnot)->isDict())
{
Object oIRTRef;
if (oAnnot.dictLookupNF("IRT", &oIRTRef)->isRef() && oIRTRef.getRefNum() == nID)
DeleteAnnot(oAnnotRef.getRefNum());
oIRTRef.free();
}
oAnnotRef.free(); oAnnot.free();
}
oAnnots.free();
return bRes;
}
bool CPdfEditor::EditWidgets(IAdvancedCommand* pCommand)
{
CWidgetsInfo* pFieldInfo = (CWidgetsInfo*)pCommand;
PDFDoc* pPDFDocument = pReader->GetPDFDocument();
PdfWriter::CDocument* pDoc = pWriter->GetDocument();
std::vector<CWidgetsInfo::CParent*> arrParents = pFieldInfo->GetParents();
for (CWidgetsInfo::CParent* pParent : arrParents)
{
PdfWriter::CDictObject* pDParent = pDoc->GetParent(pParent->nID);
if (pDParent)
continue;
Object oParentRef;
// TODO узнать gen родителя
oParentRef.initRef(pParent->nID, 0);
GetWidgetParent(pPDFDocument, pDoc, &oParentRef);
// TODO перевыставить детей
oParentRef.free();
}
return true;
}
int CPdfEditor::GetPagesCount()
{
return pWriter->GetDocument()->GetPagesCount();
}
void CPdfEditor::GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, double* pdDpiX, double* pdDpiY)
{
PdfWriter::CPage* pPage = pWriter->GetDocument()->GetPage(nPageIndex);
if (!pPage)
return;
int nRotate = pPage->GetRotate();
if (nRotate % 180 == 0)
{
*pdWidth = pPage->GetWidth();
*pdHeight = pPage->GetHeight();
}
else
{
*pdWidth = pPage->GetHeight();
*pdHeight = pPage->GetWidth();
}
*pdDpiX = 72.0;
*pdDpiY = 72.0;
}
int CPdfEditor::GetRotate(int nPageIndex)
{
PdfWriter::CPage* pPage = pWriter->GetDocument()->GetPage(nPageIndex);
if (!pPage)
return 0;
return pPage->GetRotate();
}
bool CPdfEditor::IsEditPage()
{
return bEditPage;
}
void CPdfEditor::AddShapeXML(const std::string& sXML)
{
return pWriter->GetDocument()->AddShapeXML(sXML);
}
void CPdfEditor::EndMarkedContent()
{
pWriter->GetDocument()->EndShapeXML();
}
bool CPdfEditor::IsBase14(const std::wstring& wsFontName, bool& bBold, bool& bItalic, std::wstring& wsFontPath)
{
std::map<std::wstring, std::wstring>::iterator it = m_mFonts.find(wsFontName);
if (it == m_mFonts.end())
return false;
wsFontPath = it->second;
if (wsFontName == L"Helvetica")
return true;
if (wsFontName == L"Helvetica-Bold")
{
bBold = true;
return true;
}
if (wsFontName == L"Helvetica-Oblique")
{
bItalic = true;
return true;
}
if (wsFontName == L"Helvetice-BoldOblique")
{
bBold = true;
bItalic = true;
return true;
}
if (wsFontName == L"Courier")
return true;
if (wsFontName == L"Courier-Bold")
{
bBold = true;
return true;
}
if (wsFontName == L"Courier-Oblique")
{
bItalic = true;
return true;
}
if (wsFontName == L"Courier-BoldOblique")
{
bBold = true;
bItalic = true;
return true;
}
if (wsFontName == L"Times")
return true;
if (wsFontName == L"Times-Bold")
{
bBold = true;
return true;
}
if (wsFontName == L"Times-Oblique")
{
bItalic = true;
return true;
}
if (wsFontName == L"Times-BoldOblique")
{
bBold = true;
bItalic = true;
return true;
}
if (wsFontName == L"Symbol")
return true;
if (wsFontName == L"ZapfDingbats")
return true;
return false;
}