Files
core/PdfFile/SrcReader/PdfAnnot.cpp
Svetlana Kulikova 507afb473f All fonts to PdfFont
2026-05-25 17:29:34 +03:00

4254 lines
107 KiB
C++

/*
* Copyright (C) Ascensio System SIA, 2009-2026
*
* 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, together with the
* additional terms provided in the LICENSE file.
*
* 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: https://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA by email at info@onlyoffice.com
* or by postal mail at 20A-6 Ernesta Birznieka-Upisha Street, Riga,
* LV-1050, Latvia, European Union.
*
* The interactive user interfaces in modified versions of the Program
* are required to display Appropriate Legal Notices in accordance with
* Section 5 of the GNU AGPL version 3.
*
* No trademark rights are granted under this License.
*
* All non-code elements of the Product, including illustrations,
* icon sets, and technical writing content, are licensed under the
* Creative Commons Attribution-ShareAlike 4.0 International License:
* https://creativecommons.org/licenses/by-sa/4.0/legalcode
*
* This license applies only to such non-code elements and does not
* modify or replace the licensing terms applicable to the Program's
* source code, which remains licensed under the GNU Affero General
* Public License v3.
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
#include "PdfAnnot.h"
#include "RendererOutputDev.h"
#include "Adaptors.h"
#include "PdfFont.h"
#include "../lib/xpdf/TextString.h"
#include "../lib/xpdf/Link.h"
#include "../lib/xpdf/Annot.h"
#include "../lib/xpdf/GfxFont.h"
#include "../lib/xpdf/Lexer.h"
#include "../lib/xpdf/Parser.h"
#include "../lib/goo/GList.h"
#include "../Resources/BaseFonts.h"
#include "../../DesktopEditor/common/Types.h"
#include "../../DesktopEditor/common/StringExt.h"
#include "../../DesktopEditor/fontengine/ApplicationFonts.h"
#include "../../DesktopEditor/graphics/pro/Fonts.h"
#include <map>
namespace PdfReader
{
double ArrGetNum(Object* pArr, int nI)
{
double dRes = 0.0;
Object oObj;
if (pArr->arrayGet(nI, &oObj)->isNum())
dRes = oObj.getNum();
oObj.free();
return dRes;
}
TextString* getFullFieldName(Object* oField)
{
TextString* sResName = NULL;
if (!oField || !oField->isDict())
return sResName;
Object oName;
if (oField->dictLookup("T", &oName)->isString())
sResName = new TextString(oName.getString());
else
{
oName.free();
return sResName;
}
oName.free();
Object oParent, oParent2;
oField->dictLookup("Parent", &oParent);
int nDepth = 0;
while (oParent.isDict() && nDepth < 50)
{
if (oParent.dictLookup("T", &oName)->isString())
{
if (sResName->getLength())
sResName->insert(0, (Unicode)'.');
sResName->insert(0, oName.getString());
}
oName.free();
oParent.dictLookup("Parent", &oParent2);
oParent.free();
oParent = oParent2;
++nDepth;
}
oParent.free();
return sResName;
}
CActionGoTo* getGoTo(PDFDoc* pdfDoc, LinkAction* oAct)
{
if (!oAct || oAct->getKind() != actionGoTo)
return NULL;
GString* str = ((LinkGoTo*)oAct)->getNamedDest();
LinkDest* pLinkDest = str ? pdfDoc->findDest(str) : ((LinkGoTo*)oAct)->getDest();
if (!pLinkDest)
return NULL;
CActionGoTo* ppRes = new CActionGoTo();
if (pLinkDest->isPageRef())
{
Ref pageRef = pLinkDest->getPageRef();
ppRes->unPage = pdfDoc->findPage(pageRef.num, pageRef.gen);
}
else
ppRes->unPage = pLinkDest->getPageNum();
if (ppRes->unPage > 0)
--ppRes->unPage;
ppRes->nKind = pLinkDest->getKind();
PDFRectangle* pCropBox = pdfDoc->getCatalog()->getPage(ppRes->unPage + 1)->getCropBox();
double dHeight = pCropBox->y2;
double dX = pCropBox->x1;
switch (ppRes->nKind)
{
case destXYZ:
case destFitH:
case destFitBH:
case destFitV:
case destFitBV:
{
ppRes->unKindFlag = 0;
// 0 - left
if (pLinkDest->getChangeLeft())
{
ppRes->unKindFlag |= (1 << 0);
ppRes->pRect[0] = pLinkDest->getLeft() - dX;
}
// 1 - top
if (pLinkDest->getChangeTop())
{
ppRes->unKindFlag |= (1 << 1);
ppRes->pRect[1] = dHeight - pLinkDest->getTop();
}
// 2 - zoom
if (pLinkDest->getChangeZoom() && pLinkDest->getZoom())
{
ppRes->unKindFlag |= (1 << 2);
ppRes->pRect[2] = pLinkDest->getZoom();
}
break;
}
case destFitR:
{
ppRes->pRect[0] = pLinkDest->getLeft() - dX;
ppRes->pRect[1] = dHeight - pLinkDest->getTop();
ppRes->pRect[2] = pLinkDest->getRight() - dX;
ppRes->pRect[3] = dHeight - pLinkDest->getBottom();
break;
}
case destFit:
case destFitB:
default:
break;
}
if (str)
RELEASEOBJECT(pLinkDest);
return ppRes;
}
CAction* getDest(PDFDoc* pdfDoc, Object* oDest)
{
LinkAction* oAct = LinkAction::parseDest(oDest);
if (!oAct)
return NULL;
CAction* pRes = getGoTo(pdfDoc, oAct);
RELEASEOBJECT(oAct);
return pRes;
}
CAction* getAction(PDFDoc* pdfDoc, Object* oAction)
{
Object oActType;
std::string sSName;
if (oAction->dictLookup("S", &oActType)->isName())
sSName = oActType.getName();
oActType.free();
LinkAction* oAct = LinkAction::parseAction(oAction);
if (!oAct)
return NULL;
CAction* pRes = NULL;
LinkActionKind kind = oAct->getKind();
switch (kind)
{
// Navigation within the file
case actionGoTo:
{
pRes = getGoTo(pdfDoc, oAct);
break;
}
// Navigation to external file
case actionGoToR:
{
break;
}
// Launch external application
case actionLaunch:
{
break;
}
// External link
case actionURI:
{
CActionURI* ppRes = new CActionURI();
TextString* s = new TextString(((LinkURI*)oAct)->getURI());
ppRes->sURI = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
pRes = ppRes;
break;
}
// Non-standard named actions
case actionNamed:
{
CActionNamed* ppRes = new CActionNamed();
TextString* s = new TextString(((LinkNamed*)oAct)->getName());
ppRes->sNamed = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
pRes = ppRes;
break;
}
// Movie playback
case actionMovie:
{
break;
}
// JavaScript
case actionJavaScript:
{
CActionJavaScript* ppRes = new CActionJavaScript();
TextString* s = new TextString(((LinkJavaScript*)oAct)->getJS());
ppRes->sJavaScript = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
pRes = ppRes;
break;
}
// Form submission
case actionSubmitForm:
{
break;
}
// Hide annotations
case actionHide:
{
CActionHide* ppRes = new CActionHide();
ppRes->bHideFlag = ((LinkHide*)oAct)->getHideFlag();
Object* oHideObj = ((LinkHide*)oAct)->getFields();
int nHide = 1, k = 0;
if (oHideObj->isArray())
nHide = oHideObj->arrayGetLength();
Object oHide;
oHideObj->copy(&oHide);
do
{
TextString* s = NULL;
if (oHideObj->isArray())
{
oHide.free();
oHideObj->arrayGet(k, &oHide);
}
if (oHide.isString())
s = new TextString(oHide.getString());
else if (oHide.isDict())
s = getFullFieldName(&oHide);
if (s)
{
std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
ppRes->arrAnnotName.push_back(sStr);
delete s;
}
k++;
} while (k < nHide);
oHide.free();
pRes = ppRes;
break;
}
// Unknown action
case actionUnknown:
default:
{
if (sSName == "ResetForm")
{
CActionResetForm* ppRes = new CActionResetForm();
Object oObj;
if (oAction->dictLookup("Flags", &oObj)->isInt())
ppRes->unFlags = oObj.getInt();
oObj.free();
if (oAction->dictLookup("Fields", &oObj)->isArray())
{
for (int j = 0; j < oObj.arrayGetLength(); ++j)
{
Object oField;
oObj.arrayGet(j, &oField);
TextString* s = NULL;
if (oField.isString())
s = new TextString(oField.getString());
else if (oField.isDict())
s = getFullFieldName(&oField);
if (s)
{
std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
ppRes->arrAnnotName.push_back(sStr);
delete s;
}
oField.free();
}
}
oObj.free();
pRes = ppRes;
}
break;
}
}
if (pRes)
pRes->pNext = NULL;
Object oNextAction;
if (pRes && oAction->dictLookup("Next", &oNextAction)->isDict())
pRes->pNext = getAction(pdfDoc, &oNextAction);
oNextAction.free();
RELEASEOBJECT(oAct);
return pRes;
};
std::string getValue(Object* oV, bool bArray = true)
{
std::string sRes;
if (oV->isName())
sRes = oV->getName();
else if (oV->isString() || oV->isDict() || oV->isArray())
{
TextString* s = NULL;
if (oV->isString())
s = new TextString(oV->getString());
else if (oV->isDict())
{
Object oContents;
if (oV->dictLookup("Contents", &oContents)->isString())
s = new TextString(oContents.getString());
oContents.free();
}
else if (bArray && oV->isArray())
{
Object oContents;
if (oV->arrayGet(0, &oContents)->isString())
s = new TextString(oContents.getString());
oContents.free();
}
if (s)
{
sRes = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
}
return sRes;
}
void DrawAppearance(PDFDoc* pdfDoc, int nPage, AcroFormField* pField, Gfx* gfx, const char* sAPName, const char* sASName)
{
XRef* xref = pdfDoc->getXRef();
Object oFieldRef, oField;
pField->getFieldRef(&oFieldRef);
oFieldRef.fetch(xref, &oField);
Object kidsObj, annotRef, annotObj;
if (oField.dictLookup("Kids", &kidsObj)->isArray())
{
for (int j = 0; j < kidsObj.arrayGetLength(); ++j)
{
kidsObj.arrayGetNF(j, &annotRef);
annotRef.fetch(xref, &annotObj);
pField->drawAnnot(nPage, gfx, gFalse, &annotRef, &annotObj, sAPName, sASName, gFalse);
annotObj.free();
annotRef.free();
}
}
else
pField->drawAnnot(nPage, gfx, gFalse, &oFieldRef, &oField, sAPName, sASName, gFalse);
kidsObj.free();
oFieldRef.free(); oField.free();
}
BYTE getLE(Object* oObj)
{
BYTE nLE = 5; // None
if (oObj->isName("Square"))
nLE = 0;
else if (oObj->isName("Circle"))
nLE = 1;
else if (oObj->isName("Diamond"))
nLE = 2;
else if (oObj->isName("OpenArrow"))
nLE = 3;
else if (oObj->isName("ClosedArrow"))
nLE = 4;
else if (oObj->isName("Butt"))
nLE = 6;
else if (oObj->isName("ROpenArrow"))
nLE = 7;
else if (oObj->isName("RClosedArrow"))
nLE = 8;
else if (oObj->isName("Slash"))
nLE = 9;
return nLE;
}
CAnnotFileAttachment::CEmbeddedFile* getEF(Object* oObj)
{
CAnnotFileAttachment::CEmbeddedFile* pRes = new CAnnotFileAttachment::CEmbeddedFile();
Object oObj2;
Dict* pImDict = oObj->streamGetDict();
if (pImDict->lookup("Length", &oObj2)->isInt())
pRes->nLength = oObj2.getInt();
oObj2.free();
if (pImDict->lookup("DL", &oObj2)->isInt())
pRes->nLength = oObj2.getInt();
oObj2.free();
Stream* pFile = oObj->getStream();
pFile->reset();
pRes->pFile = new BYTE[pRes->nLength];
BYTE* pBufferPtr = pRes->pFile;
for (int nI = 0; nI < pRes->nLength; ++nI)
*pBufferPtr++ = (BYTE)pFile->getChar();
return pRes;
}
GList* tokenize(GString *s)
{
GList *toks;
int i, j;
toks = new GList();
i = 0;
while (i < s->getLength()) {
while (i < s->getLength() && Lexer::isSpace(s->getChar(i))) {
++i;
}
if (i < s->getLength()) {
for (j = i + 1;
j < s->getLength() && !Lexer::isSpace(s->getChar(j));
++j) ;
toks->append(new GString(s, i, j - i));
i = j;
}
}
return toks;
}
CAnnot::CBorderType* getBorder(Object* oBorder, bool bBSorBorder)
{
// Borders and Dash Pattern - Border/BS
CAnnot::CBorderType* pBorderType = new CAnnot::CBorderType();
if (!oBorder)
return pBorderType;
if (bBSorBorder)
{
pBorderType->nType = annotBorderSolid;
Object oV;
if (oBorder->dictLookup("S", &oV)->isName())
{
if (oV.isName("S"))
pBorderType->nType = annotBorderSolid;
else if (oV.isName("D"))
pBorderType->nType = annotBorderDashed;
else if (oV.isName("B"))
pBorderType->nType = annotBorderBeveled;
else if (oV.isName("I"))
pBorderType->nType = annotBorderInset;
else if (oV.isName("U"))
pBorderType->nType = annotBorderUnderlined;
}
oV.free();
if (oBorder->dictLookup("W", &oV)->isNum())
pBorderType->dWidth = oV.getNum();
oV.free();
if (oBorder->dictLookup("D", &oV)->isArray())
{
for (int j = 0; j < oV.arrayGetLength(); ++j)
{
Object oObj2;
if (oV.arrayGet(j, &oObj2)->isNum())
pBorderType->arrDash.push_back(oObj2.getNum());
oObj2.free();
}
}
oV.free();
}
else
{
pBorderType->nType = annotBorderSolid;
pBorderType->dWidth = ArrGetNum(oBorder, 2);
Object oObj;
if (oBorder->arrayGetLength() > 3 && oBorder->arrayGet(3, &oObj)->isArray() && oObj.arrayGetLength() > 1)
{
pBorderType->nType = annotBorderDashed;
for (int j = 0; j < oObj.arrayGetLength(); ++j)
{
Object oObj2;
if (oObj.arrayGet(j, &oObj2)->isNum())
pBorderType->arrDash.push_back(oObj2.getNum());
oObj2.free();
}
}
oObj.free();
}
return pBorderType;
}
//------------------------------------------------------------------------
// Widget
//------------------------------------------------------------------------
CAnnotWidgetBtn::CAnnotWidgetBtn(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnotWidget(pdfDoc, pField, nStartRefID)
{
m_unIFFlag = 0;
Object oObj;
Object oFieldRef, oField;
pField->getFieldRef(&oFieldRef);
oFieldRef.fetch(pdfDoc->getXRef(), &oField);
oFieldRef.free();
// 9 - Field value - V
if (oField.dictLookup("V", &oObj))
{
m_sV = getValue(&oObj);
if (!m_sV.empty())
m_unFlags |= (1 << 9);
}
oObj.free();
oField.free();
if (pField->fieldLookup("AS", &oObj)->isName())
{
m_sV = oObj.getName();
m_unFlags |= (1 << 9);
}
oObj.free();
AcroFormFieldType oType = pField->getAcroFormFieldType();
Object oOpt;
// 10 - List of values
if (oType != acroFormFieldPushbutton && oField.dictLookup("Opt", &oOpt)->isArray())
{
m_unFlags |= (1 << 10);
int nOptLength = oOpt.arrayGetLength();
for (int j = 0; j < nOptLength; ++j)
{
Object oOptJ;
if (!oOpt.arrayGet(j, &oOptJ) || !(oOptJ.isString() || oOptJ.isArray()))
{
oOptJ.free();
continue;
}
std::string sOpt1, sOpt2;
if (oOptJ.isArray() && oOptJ.arrayGetLength() > 1)
{
Object oOptJ2;
if (oOptJ.arrayGet(0, &oOptJ2)->isString())
{
TextString* s = new TextString(oOptJ2.getString());
sOpt1 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oOptJ2.free();
if (oOptJ.arrayGet(1, &oOptJ2)->isString())
{
TextString* s = new TextString(oOptJ2.getString());
sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oOptJ2.free();
}
else if (oOptJ.isString())
{
TextString* s = new TextString(oOptJ.getString());
sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
m_arrOpt.push_back(std::make_pair(sOpt1, sOpt2));
oOptJ.free();
}
}
oOpt.free();
Object oMK;
m_nStyle = (oType == acroFormFieldRadioButton ? 3 : 0);
if (pField->fieldLookup("MK", &oMK)->isDict())
{
if (oType == acroFormFieldPushbutton)
{
// 10 - Caption - CA
m_sCA = DictLookupString(&oMK, "CA", 10);
// 11 - Rollover caption - RC
m_sRC = DictLookupString(&oMK, "RC", 11);
// 12 - Alternate caption - AC
m_sAC = DictLookupString(&oMK, "AC", 12);
}
else
{
if (oMK.dictLookup("CA", &oObj)->isString())
{
std::string sCA(oObj.getString()->getCString());
if (sCA == "l") // circle
m_nStyle = 3;
else if (sCA == "4") // checkmark
m_nStyle = 0;
else if (sCA == "8") // cross
m_nStyle = 1;
else if (sCA == "u") // diamond
m_nStyle = 2;
else if (sCA == "n") // square
m_nStyle = 5;
else if (sCA == "H") // star
m_nStyle = 4;
}
oObj.free();
}
// 13 - Title position - TP
if (oMK.dictLookup("TP", &oObj)->isInt())
{
m_nTP = oObj.getInt();
m_unFlags |= (1 << 13);
}
oObj.free();
Object oIF;
if (oMK.dictLookup("IF", &oIF)->isDict())
{
m_unIFFlag = 1;
// 1 - Scaling - SW
if (oIF.dictLookup("SW", &oObj)->isName())
{
m_unIFFlag |= (1 << 1);
std::string sName(oObj.getName());
m_nSW = 0; // Default: A
if (sName == "B")
m_nSW = 2;
else if (sName == "S")
m_nSW = 3;
else if (sName == "N")
m_nSW = 1;
}
oObj.free();
// 2 - Scaling type - S
if (oIF.dictLookup("S", &oObj)->isName())
{
m_unIFFlag |= (1 << 2);
std::string sName(oObj.getName());
m_nS = 0; // Default: P
if (sName == "A")
m_nS = 1;
}
oObj.free();
// 3 - Offset - A
if (oIF.dictLookup("A", &oObj)->isArray())
{
m_dA1 = 0.5, m_dA2 = 0.5;
Object oObj2;
m_unIFFlag |= (1 << 3);
m_dA1 = ArrGetNum(&oObj, 0);
m_dA2 = ArrGetNum(&oObj, 1);
}
oObj.free();
// 4 - Full fit - FB
if (oIF.dictLookup("FB", &oObj)->isBool() && oObj.getBool())
m_unIFFlag |= (1 << 4);
oObj.free();
}
oIF.free();
}
oMK.free();
pField->fieldLookup("Opt", &oOpt);
// 14 - On state name - AP - N - Yes
Object oNorm;
if (pField->fieldLookup("AP", &oObj)->isDict() && oObj.dictLookup("N", &oNorm)->isDict() && oOpt.isNull())
{
for (int j = 0, nNormLength = oNorm.dictGetLength(); j < nNormLength; ++j)
{
std::string sNormName(oNorm.dictGetKey(j));
if (sNormName != "Off")
{
m_unFlags |= (1 << 14);
m_sAP_N_Yes = sNormName;
break;
}
}
}
oNorm.free(); oObj.free(); oOpt.free();
}
CAnnotWidgetTx::CAnnotWidgetTx(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnotWidget(pdfDoc, pField, nStartRefID)
{
Object oObj;
Object oFieldRef, oField;
pField->getFieldRef(&oFieldRef);
oFieldRef.fetch(pdfDoc->getXRef(), &oField);
oFieldRef.free();
// 9 - Value - V
if (oField.dictLookup("V", &oObj))
{
m_sV = getValue(&oObj);
if (!m_sV.empty())
m_unFlags |= (1 << 9);
}
oObj.free();
oField.free();
// 10 - Maximum number of characters in Tx - MaxLen
if (oField.dictLookup("MaxLen", &oObj)->isInt())
{
m_unFlags |= (1 << 10);
m_unMaxLen = oObj.getInt();
}
oObj.free();
// 11 - Rich text RV - RichText
if (pField->getFlags() & (1 << 25))
m_sRV = FieldLookupString(pField, "RV", 11);
}
CAnnotWidgetCh::CAnnotWidgetCh(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnotWidget(pdfDoc, pField, nStartRefID)
{
Object oObj;
Object oFieldRef, oField;
pField->getFieldRef(&oFieldRef);
oFieldRef.fetch(pdfDoc->getXRef(), &oField);
oFieldRef.free();
// 9 - Value
if (oField.dictLookup("V", &oObj))
{
m_sV = getValue(&oObj, false);
if (!m_sV.empty())
m_unFlags |= (1 << 9);
}
oObj.free();
Object oOpt;
// 10 - List of values
if (oField.dictLookup("Opt", &oOpt)->isArray())
{
m_unFlags |= (1 << 10);
int nOptLength = oOpt.arrayGetLength();
for (int j = 0; j < nOptLength; ++j)
{
Object oOptJ;
if (!oOpt.arrayGet(j, &oOptJ) || !(oOptJ.isString() || oOptJ.isArray()))
{
oOptJ.free();
continue;
}
std::string sOpt1, sOpt2;
if (oOptJ.isArray() && oOptJ.arrayGetLength() > 1)
{
Object oOptJ2;
if (oOptJ.arrayGet(0, &oOptJ2)->isString())
{
TextString* s = new TextString(oOptJ2.getString());
sOpt1 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oOptJ2.free();
if (oOptJ.arrayGet(1, &oOptJ2)->isString())
{
TextString* s = new TextString(oOptJ2.getString());
sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oOptJ2.free();
}
else if (oOptJ.isString())
{
TextString* s = new TextString(oOptJ.getString());
sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
m_arrOpt.push_back(std::make_pair(sOpt1, sOpt2));
oOptJ.free();
}
}
oOpt.free();
// 11 - Top element index - TI
if (pField->fieldLookup("TI", &oObj)->isInt())
{
m_unFlags |= (1 << 11);
m_unTI = oObj.getInt();
}
oObj.free();
// 12 - Selected indices - I
if (oField.dictLookup("I", &oOpt)->isArray())
{
m_unFlags |= (1 << 12);
for (int j = 0; j < oOpt.arrayGetLength(); ++j)
{
if (oOpt.arrayGet(j, &oObj)->isInt())
m_arrI.push_back(oObj.getInt());
oObj.free();
}
}
oOpt.free();
// 13 - Values array
if (oField.dictLookup("V", &oOpt)->isArray())
{
m_unFlags |= (1 << 13);
int nVLength = oOpt.arrayGetLength();
for (int j = 0; j < nVLength; ++j)
{
if (oOpt.arrayGet(j, &oObj)->isString())
{
TextString* s = new TextString(oObj.getString());
m_arrV.push_back(NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()));
delete s;
}
oObj.free();
}
}
oOpt.free();
oField.free();
}
CAnnotWidgetSig::CAnnotWidgetSig(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnotWidget(pdfDoc, pField, nStartRefID)
{
Object oObj;
Object oFieldRef, oField;
pField->getFieldRef(&oFieldRef);
oFieldRef.fetch(pdfDoc->getXRef(), &oField);
oFieldRef.free();
// 9 - Value
if (oField.dictLookup("V", &oObj)->isDict())
m_unFlags |= (1 << 9);
oObj.free();
oField.free();
}
CAnnotWidget::CAnnotWidget(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID) : CAnnot(pdfDoc, pField, nStartRefID)
{
Object oObj, oField;
XRef* xref = pdfDoc->getXRef();
pField->getFieldRef(&oObj);
oObj.fetch(xref, &oField);
oObj.free();
m_bChangeFullName = false;
m_dFontSize = 0.0;
m_unFontStyle = 0;
// Text color - from DA
int nSpace;
GList *arrColors = pField->getColorSpace(&nSpace);
for (int j = 0; j < nSpace; ++j)
m_arrTC.push_back(*(double*)arrColors->get(j));
deleteGList(arrColors, double);
// Text alignment - Q
m_nQ = 0;
if (pField->fieldLookup("Q", &oObj)->isInt())
m_nQ = oObj.getInt();
oObj.free();
// Type - FT + flags
AcroFormFieldType oType = pField->getAcroFormFieldType();
m_nType = 26; // Unknown
switch (oType)
{
case acroFormFieldPushbutton: m_nType = 27; break;
case acroFormFieldRadioButton: m_nType = 28; break;
case acroFormFieldCheckbox: m_nType = 29; break;
case acroFormFieldFileSelect: m_nType = 30; break;
case acroFormFieldMultilineText: m_nType = 30; break;
case acroFormFieldText: m_nType = 30; break;
case acroFormFieldBarcode: m_nType = 30; break;
case acroFormFieldComboBox: m_nType = 31; break;
case acroFormFieldListBox: m_nType = 32; break;
case acroFormFieldSignature: m_nType = 33; break;
default: m_nType = 26; break;
}
// Flag - Ff
m_unFieldFlag = -1;
if (oField.dictLookup("Ff", &oObj)->isInt())
m_unFieldFlag = oObj.getInt();
oObj.free();
// 0 - Alternative field name, used in tooltips and error messages - TU
if (oField.dictLookup("TU", &oObj))
{
m_sTU = getValue(&oObj);
if (!m_sTU.empty())
m_unFlags |= (1 << 0);
}
oObj.free();
// 1 - Default style string - DS
m_sDS = FieldLookupString(pField, "DS", 1);
// 3 - Highlighting mode - H
if (pField->fieldLookup("H", &oObj)->isName())
{
m_unFlags |= (1 << 3);
std::string sName(oObj.getName());
m_nH = 1; // Default: I
if (sName == "N")
m_nH = 0;
else if (sName == "O")
m_nH = 3;
else if (sName == "P" || sName == "T")
m_nH = 2;
}
oObj.free();
Object oMK;
if (pField->fieldLookup("MK", &oMK)->isDict())
{
// 5 - Border color - BC. Even if border is not set by BS/Border, if BC is present a default border is provided (solid, 1pt thick)
if (oMK.dictLookup("BC", &oObj)->isArray())
{
m_unFlags |= (1 << 5);
int nBCLength = oObj.arrayGetLength();
for (int j = 0; j < nBCLength; ++j)
{
Object oBCj;
m_arrBC.push_back(oObj.arrayGet(j, &oBCj)->isNum() ? oBCj.getNum() : 0.0);
oBCj.free();
}
}
oObj.free();
// 6 - Annotation rotation relative to page - R
if (oMK.dictLookup("R", &oObj)->isInt())
{
m_unFlags |= (1 << 6);
m_unR = oObj.getInt();
}
oObj.free();
// 7 - Background color - BG
if (oMK.dictLookup("BG", &oObj)->isArray())
{
m_unFlags |= (1 << 7);
int nBGLength = oObj.arrayGetLength();
for (int j = 0; j < nBGLength; ++j)
{
Object oBGj;
m_arrBG.push_back(oObj.arrayGet(j, &oBGj)->isNum() ? oBGj.getNum() : 0.0);
oBGj.free();
}
}
oObj.free();
}
oMK.free();
// 8 - Default value
if (oField.dictLookup("DV", &oObj))
{
m_sDV = getValue(&oObj);
if (!m_sDV.empty())
m_unFlags |= (1 << 8);
}
oObj.free();
// 17 - Parent - Parent
m_unRefNumParent = 0;
if (oField.dictLookupNF("Parent", &oObj)->isRef())
{
m_unRefNumParent = oObj.getRefNum() + nStartRefID;
m_unFlags |= (1 << 17);
}
oObj.free();
// 18 - Partial field name - T
m_sT = DictLookupString(&oField, "T", 18);
m_sFullName = m_sT;
// 21 - MEOptions
if (oField.dictLookup("MEOptions", &oObj)->isInt())
{
m_unFlags |= (1 << 21);
m_unMEOptions = oObj.getInt();
}
oObj.free();
// Action - A
Object oAction;
if (oField.dictLookup("A", &oAction)->isDict())
{
std::string sAA = "A";
CAction* pA = getAction(pdfDoc, &oAction);
if (pA)
{
pA->sType = sAA;
m_arrAction.push_back(pA);
}
}
oAction.free();
// Actions - AA
Object oAA;
if (oField.dictLookup("AA", &oAA)->isDict())
{
for (int j = 0; j < oAA.dictGetLength(); ++j)
{
if (oAA.dictGetVal(j, &oAction)->isDict())
{
std::string sAA(oAA.dictGetKey(j));
CAction* pA = getAction(pdfDoc, &oAction);
if (pA)
{
pA->sType = sAA;
m_arrAction.push_back(pA);
}
}
oAction.free();
}
}
oAA.free();
oField.free();
}
CAnnotWidget::~CAnnotWidget()
{
ClearActions();
}
std::string CAnnotWidget::FieldLookupString(AcroFormField* pField, const char* sName, int nByte)
{
std::string sRes;
Object oObj;
if (pField->fieldLookup(sName, &oObj)->isString())
{
m_unFlags |= (1 << nByte);
TextString* s = new TextString(oObj.getString());
sRes = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
return sRes;
}
void CAnnotWidget::SetFont(PDFDoc* pdfDoc, AcroFormField* pField, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList)
{
// Font and font size - from DA
Ref fontID;
pField->getFont(&fontID, &m_dFontSize);
m_unFontStyle = 0;
Object oFontRef;
if (fontID.num < 0)
{
if (!GetFontFromAP(pdfDoc, pField, &oFontRef, m_sFontKey))
{
oFontRef.free();
return;
}
}
else
oFontRef.initRef(fontID.num, fontID.gen);
bool bBold = false, bItalic = false;
GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, m_sFontName, m_sActualFontName, bBold, bItalic);
oFontRef.free();
// 2 - Actual font
if (!m_sActualFontName.empty())
m_unFlags |= (1 << 2);
// 4 - Unique font identifier
if (!m_sFontKey.empty())
m_unFlags |= (1 << 4);
if (bBold)
m_unFontStyle |= (1 << 0);
if (bItalic)
m_unFontStyle |= (1 << 1);
}
void CAnnotWidget::SetButtonFont(PDFDoc* pdfDoc, AcroFormField* pField, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList)
{
// Incomplete font in pushbutton appearance
Object oFontRef;
if (!GetFontFromAP(pdfDoc, pField, &oFontRef, m_sFontKey))
{
oFontRef.free();
return;
}
bool bBold = false, bItalic = false;
GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, m_sButtonFontName, m_sButtonFontName, bBold, bItalic);
if (!m_sButtonFontName.empty())
m_unFlags |= (1 << 19);
oFontRef.free();
}
bool CAnnotWidget::ChangeFullName(const std::string& sPrefixForm)
{
m_bChangeFullName = true;
if (m_unFlags & (1 << 18))
{
m_sT += sPrefixForm;
m_sFullName += sPrefixForm;
return true;
}
return false;
}
void CAnnotWidget::ClearActions()
{
for (int i = 0; i < m_arrAction.size(); ++i)
RELEASEOBJECT(m_arrAction[i]);
m_arrAction.clear();
}
//------------------------------------------------------------------------
// Popup
//------------------------------------------------------------------------
CAnnotPopup::CAnnotPopup(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnot(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
m_unFlags = 0;
Object oAnnot, oObj;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// 0 - Display as open - Open
if (oAnnot.dictLookup("Open", &oObj)->isBool() && oObj.getBool())
m_unFlags |= (1 << 0);
oObj.free();
// 1 - Parent - Parent
if (oAnnot.dictLookupNF("Parent", &oObj)->isRef())
{
m_unFlags |= (1 << 1);
m_unRefNumParent = oObj.getRefNum() + nStartRefID;
}
oObj.free();
oAnnot.free();
}
//------------------------------------------------------------------------
// Link
//------------------------------------------------------------------------
CAnnotLink::CAnnotLink(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnot(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
m_unFlags = 0;
m_pAction = NULL;
m_pPA = NULL;
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// 0 - Action - A
if (oAnnot.dictLookup("A", &oObj)->isDict())
{
m_pAction = getAction(pdfDoc, &oObj);
if (m_pAction)
{
m_unFlags |= (1 << 0);
m_pAction->sType = "A";
}
}
oObj.free();
// 0 - Action from Dest - Dest
if (!m_pAction && !oAnnot.dictLookup("Dest", &oObj)->isNull())
{
m_pAction = getDest(pdfDoc, &oObj);
if (m_pAction)
{
m_unFlags |= (1 << 0);
m_pAction->sType = "A";
}
}
oObj.free();
// 1 - Action - PA
if (oAnnot.dictLookup("PA", &oObj)->isDict())
{
m_pPA = getAction(pdfDoc, &oObj);
if (m_pPA)
{
m_unFlags |= (1 << 1);
m_pPA->sType = "A";
}
}
oObj.free();
// 2 - Highlighting mode - H
if (oAnnot.dictLookup("H", &oObj)->isName())
{
m_unFlags |= (1 << 2);
std::string sName(oObj.getName());
m_nH = 1; // Default: I
if (sName == "N")
m_nH = 0;
else if (sName == "O")
m_nH = 3;
else if (sName == "P" || sName == "T")
m_nH = 2;
}
oObj.free();
// 3 - Coordinates - QuadPoints
if (oAnnot.dictLookup("QuadPoints", &oObj)->isArray())
{
m_unFlags |= (1 << 3);
for (int i = 0; i < oObj.arrayGetLength(); ++i)
{
if (oObj.arrayGet(i, &oObj2)->isNum())
m_arrQuadPoints.push_back(i % 2 == 0 ? oObj2.getNum() - m_dX : m_dHeight - oObj2.getNum());
oObj2.free();
}
}
oObj.free();
// 4 - Различия Rect и фактического размера - RD
if (oAnnot.dictLookup("RD", &oObj)->isArray() && oObj.arrayGetLength() == 4)
{
m_unFlags |= (1 << 4);
m_pRD[0] = ArrGetNum(&oObj, 0);
m_pRD[3] = ArrGetNum(&oObj, 1);
m_pRD[2] = ArrGetNum(&oObj, 2);
m_pRD[1] = ArrGetNum(&oObj, 3);
}
oObj.free();
oAnnot.free();
}
CAnnotLink::~CAnnotLink()
{
RELEASEOBJECT(m_pAction);
RELEASEOBJECT(m_pPA);
}
//------------------------------------------------------------------------
// Screen
//------------------------------------------------------------------------
CAnnotScreen::CAnnotScreen(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnot(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// 0 - Title - T
m_sT = DictLookupString(&oAnnot, "T", 0);
Object oMK;
if (oAnnot.dictLookup("MK", &oMK)->isDict())
{
// 1 - Цвет границ - BC. Даже если граница не задана BS/Border, то при наличии BC предоставляется граница по-умолчанию (сплошная, толщиной 1)
if (oMK.dictLookup("BC", &oObj)->isArray())
{
m_unFlags |= (1 << 1);
int nBCLength = oObj.arrayGetLength();
for (int j = 0; j < nBCLength; ++j)
{
Object oBCj;
m_arrBC.push_back(oObj.arrayGet(j, &oBCj)->isNum() ? oBCj.getNum() : 0.0);
oBCj.free();
}
}
oObj.free();
// 2 - Поворот аннотации относительно страницы - R
if (oMK.dictLookup("R", &oObj)->isInt())
{
m_unFlags |= (1 << 2);
m_unR = oObj.getInt();
}
oObj.free();
// 3 - Цвет фона - BG
if (oMK.dictLookup("BG", &oObj)->isArray())
{
m_unFlags |= (1 << 3);
int nBGLength = oObj.arrayGetLength();
for (int j = 0; j < nBGLength; ++j)
{
Object oBGj;
m_arrBG.push_back(oObj.arrayGet(j, &oBGj)->isNum() ? oBGj.getNum() : 0.0);
oBGj.free();
}
}
oObj.free();
}
oMK.free();
// 4 - Action - A
Object oAction;
if (oAnnot.dictLookup("A", &oAction)->isDict())
{
std::string sAA = "A";
CAction* pA = getAction(pdfDoc, &oAction);
if (pA)
{
pA->sType = sAA;
m_arrAction.push_back(pA);
m_unFlags |= (1 << 4);
}
}
oAction.free();
// 4 - Actions - AA
Object oAA;
if (oAnnot.dictLookup("AA", &oAA)->isDict())
{
for (int j = 0; j < oAA.dictGetLength(); ++j)
{
if (oAA.dictGetVal(j, &oAction)->isDict())
{
std::string sAA(oAA.dictGetKey(j));
CAction* pA = getAction(pdfDoc, &oAction);
if (pA)
{
pA->sType = sAA;
m_arrAction.push_back(pA);
m_unFlags |= (1 << 4);
}
}
oAction.free();
}
}
oAA.free();
oAnnot.free();
}
CAnnotScreen::~CAnnotScreen()
{
}
//------------------------------------------------------------------------
// Text
//------------------------------------------------------------------------
CAnnotText::CAnnotText(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// 15 - Display as open - Open
if (oAnnot.dictLookup("Open", &oObj)->isBool() && oObj.getBool())
m_unFlags |= (1 << 15);
oObj.free();
// 16 - Icon - Name
m_unFlags |= (1 << 16);
m_nName = 10; // Default: Note
if (oAnnot.dictLookup("Name", &oObj)->isName())
{
std::string sName(oObj.getName());
std::vector<std::string> arrName = {"Check", "Checkmark", "Circle", "Comment", "Cross", "CrossHairs", "Help", "Insert", "Key", "NewParagraph", "Note", "Paragraph", "RightArrow", "RightPointer", "Star", "UpArrow", "UpLeftArrow"};
std::vector<std::string>::iterator p = std::find(arrName.begin(), arrName.end(), sName);
if (p != arrName.end())
m_nName = p - arrName.begin();
}
oObj.free();
// 17 - State model - StateModel
if (oAnnot.dictLookup("StateModel", &oObj)->isString())
{
m_unFlags |= (1 << 17);
TextString* s = new TextString(oObj.getString());
std::string sStateModel = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
m_nStateModel = 1; // Review
if (sStateModel == "Marked")
m_nStateModel = 0;
}
oObj.free();
// 18 - State - State
if (oAnnot.dictLookup("State", &oObj)->isString())
{
m_unFlags |= (1 << 18);
TextString* s = new TextString(oObj.getString());
std::string sState = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
m_nState = 6; // None
if (sState == "Marked")
m_nState = 0;
else if (sState == "Unmarked")
m_nState = 1;
else if (sState == "Accepted")
m_nState = 2;
else if (sState == "Rejected")
m_nState = 3;
else if (sState == "Cancelled")
m_nState = 4;
else if (sState == "Completed")
m_nState = 5;
}
oObj.free();
// Text annotation with IRT is not displayed
if (m_unFlags & (1 << 5))
m_unAFlags &= ~(1 << 6);
oAnnot.free();
}
//------------------------------------------------------------------------
// Ink
//------------------------------------------------------------------------
CAnnotInk::CAnnotInk(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// Path - InkList
if (oAnnot.dictLookup("InkList", &oObj)->isArray())
{
for (int j = 0; j < oObj.arrayGetLength(); ++j)
{
if (oObj.arrayGet(j, &oObj2)->isArray())
{
std::vector<double> arrLine;
for (int k = 0; k < oObj2.arrayGetLength(); ++k)
{
Object oObj1;
if (oObj2.arrayGet(k, &oObj1)->isNum())
arrLine.push_back(k % 2 == 0 ? oObj1.getNum() - m_dX : m_dHeight - oObj1.getNum());
else
arrLine.push_back(0.0);
oObj1.free();
}
if (!arrLine.empty())
m_arrInkList.push_back(arrLine);
}
}
}
oObj.free();
oAnnot.free();
}
//------------------------------------------------------------------------
// Line
//------------------------------------------------------------------------
CAnnotLine::CAnnotLine(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// Line coordinates - L
if (oAnnot.dictLookup("L", &oObj)->isArray())
{
m_pL[0] = ArrGetNum(&oObj, 0) - m_dX;
m_pL[1] = m_dHeight - ArrGetNum(&oObj, 1);
m_pL[2] = ArrGetNum(&oObj, 2) - m_dX;
m_pL[3] = m_dHeight - ArrGetNum(&oObj, 3);
}
oObj.free();
// 15 - Line ending styles - LE
if (oAnnot.dictLookup("LE", &oObj)->isArray())
{
m_unFlags |= (1 << 15);
m_nLE[0] = 5; m_nLE[1] = 5; // None
for (int i = 0; i < oObj.arrayGetLength() && i < 2; ++i)
{
if (oObj.arrayGet(i, &oObj2)->isName())
m_nLE[i] = getLE(&oObj2);
oObj2.free();
}
}
oObj.free();
// 16 - Line endings color - IC
if (oAnnot.dictLookup("IC", &oObj)->isArray())
{
m_unFlags |= (1 << 16);
for (int j = 0; j < oObj.arrayGetLength(); ++j)
{
m_arrIC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0);
oObj2.free();
}
}
oObj.free();
// 17 - Leader lines length - LL
if (oAnnot.dictLookup("LL", &oObj)->isNum())
{
m_unFlags |= (1 << 17);
m_dLL = oObj.getNum();
}
oObj.free();
// 18 - Leader line extensions - LLE
if (oAnnot.dictLookup("LLE", &oObj)->isNum())
{
m_unFlags |= (1 << 18);
m_dLLE = oObj.getNum();
}
oObj.free();
// 19 - Caption location - Cap
if (oAnnot.dictLookup("Cap", &oObj)->isBool())
m_unFlags |= (1 << 19);
oObj.free();
// 20 - Annotation intent - IT
if (oAnnot.dictLookup("IT", &oObj)->isName())
{
m_unFlags |= (1 << 20);
m_nIT = 0; // LineDimension
if (oObj.isName("LineArrow"))
m_nIT = 1;
}
oObj.free();
// 21 - Leader line offset length - LLO
if (oAnnot.dictLookup("LLO", &oObj)->isNum())
{
m_unFlags |= (1 << 21);
m_dLLO = oObj.getNum();
}
oObj.free();
// 22 - Annotation caption position - CP
if (oAnnot.dictLookup("CP", &oObj)->isName())
{
m_unFlags |= (1 << 22);
m_nCP = 0; // Inline
if (oObj.isName("Top"))
m_nCP = 1;
}
oObj.free();
// 23 - Caption text offset - CO
m_pCO[0] = 0.0; m_pCO[1] = 0.0;
if (oAnnot.dictLookup("CO", &oObj)->isArray())
{
m_unFlags |= (1 << 23);
m_pCO[0] = ArrGetNum(&oObj, 0);
m_pCO[1] = ArrGetNum(&oObj, 1);
}
oObj.free();
oAnnot.free();
}
//------------------------------------------------------------------------
// TextMarkup: Highlight, Underline, Squiggly, StrikeOut
//------------------------------------------------------------------------
CAnnotTextMarkup::CAnnotTextMarkup(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// Coordinates - QuadPoints
if (oAnnot.dictLookup("QuadPoints", &oObj)->isArray())
{
for (int i = 0; i < oObj.arrayGetLength(); ++i)
{
if (oObj.arrayGet(i, &oObj2)->isNum())
m_arrQuadPoints.push_back(i % 2 == 0 ? oObj2.getNum() - m_dX : m_dHeight - oObj2.getNum());
oObj2.free();
}
}
oObj.free();
// Subtype - Subtype
std::string sType;
if (oAnnot.dictLookup("Subtype", &oObj)->isName())
sType = oObj.getName();
oObj.free();
if (sType == "Highlight")
m_nSubtype = 8;
else if (sType == "Underline")
m_nSubtype = 9;
else if (sType == "Squiggly")
m_nSubtype = 10;
else if (sType == "StrikeOut")
m_nSubtype = 11;
oAnnot.free();
}
//------------------------------------------------------------------------
// Square, Circle
//------------------------------------------------------------------------
CAnnotSquareCircle::CAnnotSquareCircle(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// Subtype - Subtype
std::string sType;
if (oAnnot.dictLookup("Subtype", &oObj)->isName())
sType = oObj.getName();
oObj.free();
if (sType == "Square")
m_nSubtype = 4;
else if (sType == "Circle")
m_nSubtype = 5;
// 15 - Differences between Rect and actual size - RD
if (oAnnot.dictLookup("RD", &oObj)->isArray())
{
m_unFlags |= (1 << 15);
m_pRD[0] = ArrGetNum(&oObj, 0);
m_pRD[3] = ArrGetNum(&oObj, 1);
m_pRD[2] = ArrGetNum(&oObj, 2);
m_pRD[1] = ArrGetNum(&oObj, 3);
}
oObj.free();
// 16 - Fill color - IC
if (oAnnot.dictLookup("IC", &oObj)->isArray())
{
m_unFlags |= (1 << 16);
for (int j = 0; j < oObj.arrayGetLength(); ++j)
{
m_arrIC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0);
oObj2.free();
}
}
oObj.free();
oAnnot.free();
}
//------------------------------------------------------------------------
// Polygon, PolyLine
//------------------------------------------------------------------------
CAnnotPolygonLine::CAnnotPolygonLine(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// Subtype - Subtype
std::string sType;
if (oAnnot.dictLookup("Subtype", &oObj)->isName())
sType = oObj.getName();
oObj.free();
if (sType == "Polygon")
m_nSubtype = 6;
else if (sType == "PolyLine")
m_nSubtype = 7;
// Vertex coordinates - Vertices
if (oAnnot.dictLookup("Vertices", &oObj)->isArray())
{
for (int j = 0; j < oObj.arrayGetLength(); ++j)
{
if (oObj.arrayGet(j, &oObj2)->isNum())
m_arrVertices.push_back(j % 2 == 0 ? oObj2.getNum() - m_dX : m_dHeight - oObj2.getNum());
else
m_arrVertices.push_back(0.0);
oObj2.free();
}
}
oObj.free();
// 15 - Line ending styles - LE
if (oAnnot.dictLookup("LE", &oObj)->isArray())
{
m_unFlags |= (1 << 15);
m_nLE[0] = 5; m_nLE[1] = 5; // None
for (int i = 0; i < oObj.arrayGetLength() && i < 2; ++i)
{
if (oObj.arrayGet(i, &oObj2)->isName())
m_nLE[i] = getLE(&oObj2);
oObj2.free();
}
}
oObj.free();
// 16 - Fill color - IC
if (oAnnot.dictLookup("IC", &oObj)->isArray())
{
m_unFlags |= (1 << 16);
for (int j = 0; j < oObj.arrayGetLength(); ++j)
{
m_arrIC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0);
oObj2.free();
}
}
oObj.free();
// 20 - Annotation intent - IT
if (oAnnot.dictLookup("IT", &oObj)->isName())
{
m_unFlags |= (1 << 20);
m_nIT = 0; // PolygonCloud
if (oObj.isName("PolyLineDimension"))
m_nIT = 1;
else if (oObj.isName("PolygonDimension"))
m_nIT = 2;
}
oObj.free();
oAnnot.free();
}
//------------------------------------------------------------------------
// FreeText
//------------------------------------------------------------------------
CAnnotFreeText::CAnnotFreeText(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// Text alignment - Q
m_nQ = 0;
if (oAnnot.dictLookup("Q", &oObj)->isInt())
m_nQ = oObj.getInt();
oObj.free();
m_nRotate = 0;
if (oAnnot.dictLookup("Rotate", &oObj)->isInt())
m_nRotate = oObj.getInt();
oObj.free();
// 15 - Differences between Rect and actual size - RD
if (oAnnot.dictLookup("RD", &oObj)->isArray())
{
m_unFlags |= (1 << 15);
m_pRD[0] = ArrGetNum(&oObj, 0);
m_pRD[3] = ArrGetNum(&oObj, 1);
m_pRD[2] = ArrGetNum(&oObj, 2);
m_pRD[1] = ArrGetNum(&oObj, 3);
}
oObj.free();
// 16 - Callout coordinates - CL
if (oAnnot.dictLookup("CL", &oObj)->isArray())
{
m_unFlags |= (1 << 16);
for (int j = 0; j < oObj.arrayGetLength(); ++j)
{
if (oObj.arrayGet(j, &oObj2)->isNum())
m_arrCL.push_back(j % 2 == 0 ? oObj2.getNum() - m_dX : m_dHeight - oObj2.getNum());
else
m_arrCL.push_back(0.0);
oObj2.free();
}
}
oObj.free();
// 17 - Default style string - DS
m_sDS = DictLookupString(&oAnnot, "DS", 17);
// 18 - Line ending styles - LE
if (oAnnot.dictLookup("LE", &oObj)->isName())
{
m_unFlags |= (1 << 18);
m_nLE = getLE(&oObj);
}
oObj.free();
// 20 - Annotation intent - IT
if (oAnnot.dictLookup("IT", &oObj)->isName())
{
m_unFlags |= (1 << 20);
m_nIT = 0; // FreeText
if (oObj.isName("FreeTextCallout"))
m_nIT = 1;
else if (oObj.isName("FreeTextTypeWriter"))
m_nIT = 2;
}
oObj.free();
// 21 - Border color - color from DA
if (oAnnot.dictLookup("DA", &oObj)->isString())
{
m_unFlags |= (1 << 21);
int nSpace;
GList *arrColors = new GList();
// parse the default appearance string
GList* daToks = tokenize(oObj.getString());
for (int i = daToks->getLength() - 1; i > 0; --i) {
// handle the g operator
if (!((GString *)daToks->get(i))->cmp("g")) {
arrColors->append(new double(atof(((GString *)daToks->get(i - 1))->getCString())));
break;
// handle the rg operator
} else if (i >= 3 && !((GString *)daToks->get(i))->cmp("rg")) {
arrColors->append(new double(atof(((GString *)daToks->get(i - 3))->getCString())));
arrColors->append(new double(atof(((GString *)daToks->get(i - 2))->getCString())));
arrColors->append(new double(atof(((GString *)daToks->get(i - 1))->getCString())));
break;
} else if (i >= 4 && !((GString *)daToks->get(i))->cmp("k")) {
arrColors->append(new double(atof(((GString *)daToks->get(i - 4))->getCString())));
arrColors->append(new double(atof(((GString *)daToks->get(i - 3))->getCString())));
arrColors->append(new double(atof(((GString *)daToks->get(i - 2))->getCString())));
arrColors->append(new double(atof(((GString *)daToks->get(i - 1))->getCString())));
break;
}
}
deleteGList(daToks, GString);
nSpace = arrColors->getLength();
for (int j = 0; j < nSpace; ++j)
m_arrCFromDA.push_back(*(double*)arrColors->get(j));
deleteGList(arrColors, double);
}
oObj.free();
if (oAnnot.dictLookup("RC", &oObj2)->isNull() && oAnnot.dictLookup("Contents", &oObj)->isString() && oObj.getString()->getLength())
{
m_arrRC = ReadRC(GetRCFromDS(m_sDS, &oObj, m_arrCFromDA));
if (m_arrRC.empty())
m_unFlags &= ~(1 << 3);
else
m_unFlags |= (1 << 3);
}
oObj.free(); oObj2.free();
oAnnot.free();
}
//------------------------------------------------------------------------
// Caret
//------------------------------------------------------------------------
CAnnotCaret::CAnnotCaret(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// 15 - Differences between Rect and actual size - RD
if (oAnnot.dictLookup("RD", &oObj)->isArray() && oObj.arrayGetLength() == 4)
{
m_unFlags |= (1 << 15);
m_pRD[0] = ArrGetNum(&oObj, 0);
m_pRD[3] = ArrGetNum(&oObj, 1);
m_pRD[2] = ArrGetNum(&oObj, 2);
m_pRD[1] = ArrGetNum(&oObj, 3);
}
oObj.free();
// 16 - Associated symbol - Sy
if (oAnnot.dictLookup("Sy", &oObj)->isName())
{
m_unFlags |= (1 << 16);
m_nSy = 0; // None
if (oObj.isName("P"))
m_nSy = 1;
if (oObj.isName("S"))
m_nSy = 2;
}
oObj.free();
oAnnot.free();
}
//------------------------------------------------------------------------
// FileAttachment
//------------------------------------------------------------------------
CAnnotFileAttachment::CAnnotFileAttachment(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
m_pEF = NULL;
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// 15 - Icon - Name
if (oAnnot.dictLookup("Name", &oObj)->isName())
{
m_unFlags |= (1 << 15);
m_sName = oObj.getName();
}
oObj.free();
Object oFS;
if (!oAnnot.dictLookup("FS", &oFS)->isDict())
{
oFS.free(); oAnnot.free();
return;
}
// 16 - File system - FS
if (oFS.dictLookup("FS", &oObj)->isName())
{
m_unFlags |= (1 << 16);
m_sFS = oObj.getName();
}
oObj.free();
// 17 - File specification - F
m_sF = DictLookupString(&oFS, "F", 17);
// 18 - File specification - UF
m_sUF = DictLookupString(&oFS, "UF", 18);
// 19 - File specification - DOS
m_sDOS = DictLookupString(&oFS, "DOS", 19);
// 20 - File specification - Mac
m_sMac = DictLookupString(&oFS, "Mac", 20);
// 21 - File specification - Unix
m_sUnix = DictLookupString(&oFS, "Unix", 21);
// 22 - File identifier - ID
if (oFS.dictLookup("ID", &oObj)->isArray() && oObj.arrayGetLength() == 2)
{
m_unFlags |= (1 << 22);
if (oObj.arrayGet(0, &oObj2)->isString())
{
TextString* s = new TextString(oObj2.getString());
m_sID.first = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj2.free();
if (oObj.arrayGet(1, &oObj2)->isString())
{
TextString* s = new TextString(oObj2.getString());
m_sID.second = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj2.free();
}
oObj.free();
// 23 - File volatility - V
if (oFS.dictLookup("V", &oObj)->isBool() && oObj.getBool())
m_unFlags |= (1 << 23);
oObj.free();
// 24 - Embedded file streams - EF
Object oEF;
if (oFS.dictLookup("EF", &oEF)->isDict())
{
m_unFlags |= (1 << 24);
m_pEF = new CEmbeddedFiles();
if (oEF.dictLookup("F", &oObj)->isStream())
m_pEF->m_pF = getEF(&oObj);
oObj.free();
if (oEF.dictLookup("UF", &oObj)->isStream())
m_pEF->m_pUF = getEF(&oObj);
oObj.free();
if (oEF.dictLookup("DOS", &oObj)->isStream())
m_pEF->m_pDOS = getEF(&oObj);
oObj.free();
if (oEF.dictLookup("Mac", &oObj)->isStream())
m_pEF->m_pMac = getEF(&oObj);
oObj.free();
if (oEF.dictLookup("Unix", &oObj)->isStream())
m_pEF->m_pUnix = getEF(&oObj);
oObj.free();
}
oEF.free();
// 25 - Embedded file streams - RF
if (oFS.dictLookup("RF", &oObj)->isDict())
m_unFlags |= (1 << 25);
oObj.free();
// 26 - File description - Desc
m_sDesc = DictLookupString(&oFS, "Desc", 26);
// 27 - Collection - Cl
if (oFS.dictLookup("Cl", &oObj)->isDict())
m_unFlags |= (1 << 27);
oObj.free();
oFS.free(); oAnnot.free();
}
CAnnotFileAttachment::~CAnnotFileAttachment()
{
RELEASEOBJECT(m_pEF);
}
//------------------------------------------------------------------------
// Stamp
//------------------------------------------------------------------------
CAnnotStamp::CAnnotStamp(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// Icon - Name
if (oAnnot.dictLookup("Name", &oObj)->isName())
m_sName = oObj.getName();
oObj.free();
m_dRotate = 0;
if (oAnnot.dictLookup("Rotate", &oObj)->isNum())
m_dRotate = oObj.getNum();
oObj.free();
double m[6] = { 1, 0, 0, 1, 0, 0 }, bbox[4] = { 0, 0, 0, 0 };
Object oAP, oObj2;
if (oAnnot.dictLookup("AP", &oAP)->isDict() && oAP.dictLookup("N", &oObj2)->isStream())
{
Object oObj1;
if (oObj2.streamGetDict()->lookup("BBox", &oObj)->isArray() && oObj.arrayGetLength() == 4)
{
for (int i = 0; i < 4; ++i)
{
oObj.arrayGet(i, &oObj1);
bbox[i] = oObj1.isNum() ? oObj1.getNum() : 0;
oObj1.free();
}
}
oObj.free();
if (oObj2.streamGetDict()->lookup("Matrix", &oObj)->isArray() && oObj.arrayGetLength() == 6)
{
for (int i = 0; i < 6; ++i)
{
oObj.arrayGet(i, &oObj1);
m[i] = oObj1.getNum();
oObj1.free();
}
}
}
else
{
m_dX1 = 0;
m_dY1 = 0;
m_dX2 = 0;
m_dY2 = 0;
m_dX3 = 0;
m_dY3 = 0;
m_dX4 = 0;
m_dY4 = 0;
return;
}
oAP.free(); oObj2.free(); oObj.free();
double formXMin, formYMin, formXMax, formYMax, x, y, sx, sy;
x = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
y = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
formXMin = formXMax = x;
formYMin = formYMax = y;
x = bbox[0] * m[0] + bbox[3] * m[2] + m[4];
y = bbox[0] * m[1] + bbox[3] * m[3] + m[5];
if (x < formXMin)
formXMin = x;
else if (x > formXMax)
formXMax = x;
if (y < formYMin)
formYMin = y;
else if (y > formYMax)
formYMax = y;
x = bbox[2] * m[0] + bbox[1] * m[2] + m[4];
y = bbox[2] * m[1] + bbox[1] * m[3] + m[5];
if (x < formXMin)
formXMin = x;
else if (x > formXMax)
formXMax = x;
if (y < formYMin)
formYMin = y;
else if (y > formYMax)
formYMax = y;
x = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
y = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
if (x < formXMin)
formXMin = x;
else if (x > formXMax)
formXMax = x;
if (y < formYMin)
formYMin = y;
else if (y > formYMax)
formYMax = y;
if (formXMin == formXMax)
sx = 1;
else
sx = (m_pRect[2] - m_pRect[0]) / (formXMax - formXMin);
if (formYMin == formYMax)
sy = 1;
else
sy = (m_pRect[3] - m_pRect[1]) / (formYMax - formYMin);
double tx = -formXMin * sx + m_pRect[0];
double ty = -formYMin * sy - m_pRect[3] + m_dHeight;
m[0] *= sx;
m[1] *= sy;
m[2] *= sx;
m[3] *= sy;
m[4] = m[4] * sx + tx;
m[5] = m[5] * sy + ty;
m_dX1 = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
m_dY1 = m_dHeight - (bbox[0] * m[1] + bbox[1] * m[3] + m[5]);
m_dX2 = bbox[0] * m[0] + bbox[3] * m[2] + m[4];
m_dY2 = m_dHeight - (bbox[0] * m[1] + bbox[3] * m[3] + m[5]);
m_dX3 = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
m_dY3 = m_dHeight - (bbox[2] * m[1] + bbox[3] * m[3] + m[5]);
m_dX4 = bbox[2] * m[0] + bbox[1] * m[2] + m[4];
m_dY4 = m_dHeight - (bbox[2] * m[1] + bbox[1] * m[3] + m[5]);
oAnnot.free();
}
//------------------------------------------------------------------------
// Redact
//------------------------------------------------------------------------
CAnnotRedact::CAnnotRedact(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnotMarkup(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// 15 - Coordinates - QuadPoints
if (oAnnot.dictLookup("QuadPoints", &oObj)->isArray())
{
m_unFlags |= (1 << 15);
for (int i = 0; i < oObj.arrayGetLength(); ++i)
{
if (oObj.arrayGet(i, &oObj2)->isNum())
m_arrQuadPoints.push_back(i % 2 == 0 ? oObj2.getNum() - m_dX : m_dHeight - oObj2.getNum());
oObj2.free();
}
}
oObj.free();
// 16 - Fill color - IC
if (oAnnot.dictLookup("IC", &oObj)->isArray())
{
m_unFlags |= (1 << 16);
for (int j = 0; j < oObj.arrayGetLength(); ++j)
{
m_arrIC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0);
oObj2.free();
}
}
oObj.free();
// RO in appearance streams
// 17 - Overlay text - OverlayText
m_sOverlayText = DictLookupString(&oAnnot, "OverlayText", 17);
// 18 - Repeat text - Repeat
if (oAnnot.dictLookup("Repeat", &oObj)->isBool() && oObj.getBool())
m_unFlags |= (1 << 18);
// 19 - Text alignment - Q
m_nQ = 0;
if (oAnnot.dictLookup("Q", &oObj)->isInt())
{
m_unFlags |= (1 << 19);
m_nQ = oObj.getInt();
}
oObj.free();
// Replacement of C: 3 - Color - C
if (oAnnot.dictLookup("OC", &oObj)->isArray())
{
m_unAFlags |= (1 << 3);
int nBCLength = oObj.arrayGetLength();
m_arrC.clear();
for (int j = 0; j < nBCLength; ++j)
{
m_arrC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0);
oObj2.free();
}
}
oObj.free();
oAnnot.free();
}
void CAnnotRedact::SetFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oAnnotRef)
{
Object oAnnot, oObj;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// 20 - Font, size, color of replacement text - DA
if (oAnnot.dictLookup("DA", &oObj)->isString())
{
m_unFlags |= (1 << 20);
// parse the default appearance string
GList* daToks = tokenize(oObj.getString());
for (int i = daToks->getLength() - 1; i > 0; --i)
{
// handle the g operator
if (!((GString *)daToks->get(i))->cmp("G") && m_arrCFromDA.empty())
{
m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 1))->getCString()));
}
// handle the rg operator
else if (i >= 3 && !((GString *)daToks->get(i))->cmp("RG") && m_arrCFromDA.empty())
{
m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 3))->getCString()));
m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 2))->getCString()));
m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 1))->getCString()));
}
// handle the k operator
else if (i >= 4 && !((GString *)daToks->get(i))->cmp("K") && m_arrCFromDA.empty())
{
m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 4))->getCString()));
m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 3))->getCString()));
m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 2))->getCString()));
m_arrCFromDA.push_back(atof(((GString *)daToks->get(i - 1))->getCString()));
}
else if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf"))
{
m_dFontSize = atof(((GString *)daToks->get(i - 1))->getCString());
m_unFontStyle = 0;
}
}
deleteGList(daToks, GString);
}
oObj.free();
Object oAP, oN;
if (!oAnnot.dictLookup("RO", &oN)->isStream())
{
oN.free();
if (!oAnnot.dictLookup("AP", &oAP)->isDict() || !oAP.dictLookup("D", &oN)->isStream())
{
oAP.free(); oN.free(); oAnnot.free();
return;
}
}
oAP.free();
Object oFonts;
if (!FindFonts(&oN, 0, &oFonts))
{
oN.free(); oFonts.free(); oAnnot.free();
return;
}
oN.free();
for (int i = 0, nFonts = oFonts.dictGetLength(); i < nFonts; ++i)
{
Object oFontRef;
if (!oFonts.dictGetValNF(i, &oFontRef)->isRef())
{
oFontRef.free();
continue;
}
std::string sFontName, sActualFontName;
bool bBold = false, bItalic = false;
std::wstring sFontPath = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, m_sFontName, m_sActualFontName, bBold, bItalic);
oFontRef.free();
m_unFontStyle = 0;
if (bBold)
m_unFontStyle |= (1 << 0);
if (bItalic)
m_unFontStyle |= (1 << 1);
}
oFonts.free(); oAnnot.free();
}
//------------------------------------------------------------------------
// Annots
//------------------------------------------------------------------------
CAnnots::CAnnots(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, int nStartPage, int nStartRefID)
{
Object oObj1, oObj2;
XRef* xref = pdfDoc->getXRef();
AcroForm* pAcroForms = pdfDoc->getCatalog()->getForm();
// Calculation order - CO
Object* oAcroForm = pAcroForms->getAcroFormObj();
if (oAcroForm->dictLookup("CO", &oObj1)->isArray())
{
for (int j = 0; j < oObj1.arrayGetLength(); ++j)
{
if (oObj1.arrayGetNF(j, &oObj2)->isRef())
m_arrCO.push_back(oObj2.getRefNum() + nStartRefID);
oObj2.free();
}
}
oObj1.free();
// Fields
for (int i = 0, nNum = pAcroForms->getNumFields(); i < nNum; ++i)
{
AcroFormField* pField = pAcroForms->getField(i);
Object oFieldRef, oField;
if (!pField || !pField->getFieldRef(&oFieldRef)->isRef() || !oFieldRef.fetch(xref, &oField)->isDict())
{
oField.free(); oFieldRef.free();
continue;
}
if (pField->getPageNum() < 1)
{
oField.free(); oFieldRef.free();
std::vector<int>::iterator it = std::find(m_arrCO.begin(), m_arrCO.end(), oFieldRef.getRefNum() + nStartRefID);
if (it != m_arrCO.end())
m_arrCO.erase(it);
continue;
}
// Parents
Object oParentRefObj;
if (oField.dictLookupNF("Parent", &oParentRefObj)->isRef())
getParents(pdfDoc, &oParentRefObj, nStartRefID);
oParentRefObj.free();
oField.free(); oFieldRef.free();
CAnnotWidget* pAnnot = NULL;
AcroFormFieldType oType = pField->getAcroFormFieldType();
switch (oType)
{
case acroFormFieldPushbutton:
case acroFormFieldRadioButton:
case acroFormFieldCheckbox:
{
pAnnot = new CAnnotWidgetBtn(pdfDoc, pField, nStartRefID);
break;
}
case acroFormFieldFileSelect:
case acroFormFieldMultilineText:
case acroFormFieldText:
case acroFormFieldBarcode:
{
pAnnot = new CAnnotWidgetTx(pdfDoc, pField, nStartRefID);
break;
}
case acroFormFieldComboBox:
case acroFormFieldListBox:
{
pAnnot = new CAnnotWidgetCh(pdfDoc, pField, nStartRefID);
break;
}
case acroFormFieldSignature:
{
pAnnot = new CAnnotWidgetSig(pdfDoc, pField, nStartRefID);
break;
}
default:
break;
}
if (pAnnot)
{
pAnnot->SetFont(pdfDoc, pField, pFontManager, pFontList);
if (pField->getAcroFormFieldType() == acroFormFieldPushbutton)
pAnnot->SetButtonFont(pdfDoc, pField, pFontManager, pFontList);
pAnnot->SetPage(nStartPage + pField->getPageNum());
unsigned int unRefNumParent = pAnnot->GetRefNumParent();
if (unRefNumParent)
{
std::vector<CAnnotParent*>::iterator it = std::find_if(m_arrParents.begin(), m_arrParents.end(), [unRefNumParent](CAnnotParent* pP) { return pP->unRefNum == unRefNumParent; });
if (it != m_arrParents.end() && !((*it)->sFullName.empty()))
{
const std::string& sFullNameChild = pAnnot->GetFullName();
if (sFullNameChild.empty())
pAnnot->SetFullName((*it)->sFullName);
else
pAnnot->SetFullName((*it)->sFullName + "." + sFullNameChild);
}
}
m_arrAnnots.push_back(pAnnot);
}
}
}
CAnnots::~CAnnots()
{
for (int i = 0; i < m_arrParents.size(); ++i)
RELEASEOBJECT(m_arrParents[i]);
for (int i = 0; i < m_arrAnnots.size(); ++i)
RELEASEOBJECT(m_arrAnnots[i]);
}
void CAnnots::getParents(PDFDoc* pdfDoc, Object* oFieldRef, int nStartRefID)
{
if (!oFieldRef || !pdfDoc || !oFieldRef->isRef() ||
std::find_if(m_arrParents.begin(), m_arrParents.end(), [oFieldRef, nStartRefID] (CAnnotParent* pAP) { return oFieldRef->getRefNum() + nStartRefID == pAP->unRefNum; }) != m_arrParents.end())
return;
Object oField;
CAnnotParent* pAnnotParent = new CAnnotParent();
if (!pAnnotParent || !oFieldRef->fetch(pdfDoc->getXRef(), &oField)->isDict())
{
oField.free();
RELEASEOBJECT(pAnnotParent);
return;
}
pAnnotParent->unRefNum = oFieldRef->getRefNum() + nStartRefID;
Object oObj;
if (oField.dictLookup("T", &oObj)->isString())
{
TextString* s = new TextString(oObj.getString());
std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
pAnnotParent->unFlags |= (1 << 0);
pAnnotParent->sT = sStr;
pAnnotParent->sFullName = sStr;
delete s;
}
oObj.free();
if (oField.dictLookup("V", &oObj))
{
pAnnotParent->sV = getValue(&oObj, false);
if (!pAnnotParent->sV.empty())
pAnnotParent->unFlags |= (1 << 1);
if (oObj.isArray())
{
pAnnotParent->unFlags |= (1 << 5);
int nVLength = oObj.arrayGetLength();
for (int j = 0; j < nVLength; ++j)
{
Object oObj2;
if (oObj.arrayGet(j, &oObj2)->isString())
{
TextString* s = new TextString(oObj2.getString());
pAnnotParent->arrV.push_back(NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()));
delete s;
}
oObj2.free();
}
}
}
oObj.free();
if (oField.dictLookup("DV", &oObj))
{
pAnnotParent->sDV = getValue(&oObj);
if (!pAnnotParent->sDV.empty())
pAnnotParent->unFlags |= (1 << 2);
}
oObj.free();
Object oI;
if (oField.dictLookup("I", &oI)->isArray())
{
int nILength = oI.arrayGetLength();
for (int j = 0; j < nILength; ++j)
{
if (oI.arrayGet(j, &oObj)->isInt())
pAnnotParent->arrI.push_back(oObj.getInt());
oObj.free();
}
if (!pAnnotParent->arrI.empty())
pAnnotParent->unFlags |= (1 << 3);
}
oI.free();
Object oOpt;
// 6 - Opt
if (oField.dictLookup("Opt", &oOpt)->isArray())
{
int nOptLength = oOpt.arrayGetLength();
for (int j = 0; j < nOptLength; ++j)
{
Object oOptJ;
if (!oOpt.arrayGet(j, &oOptJ) || !(oOptJ.isString() || oOptJ.isArray()))
{
oOptJ.free();
continue;
}
std::string sOpt1, sOpt2;
if (oOptJ.isArray() && oOptJ.arrayGetLength() > 1)
{
Object oOptJ2;
if (oOptJ.arrayGet(0, &oOptJ2)->isString())
{
TextString* s = new TextString(oOptJ2.getString());
sOpt1 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oOptJ2.free();
if (oOptJ.arrayGet(1, &oOptJ2)->isString())
{
TextString* s = new TextString(oOptJ2.getString());
sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oOptJ2.free();
}
else if (oOptJ.isString())
{
TextString* s = new TextString(oOptJ.getString());
sOpt2 = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
pAnnotParent->arrOpt.push_back(std::make_pair(sOpt1, sOpt2));
oOptJ.free();
}
if (!pAnnotParent->arrOpt.empty())
pAnnotParent->unFlags |= (1 << 6);
}
oOpt.free();
// 7 - Flag - Ff
if (oField.dictLookup("Ff", &oObj)->isInt())
{
pAnnotParent->unFieldFlag = oObj.getInt();
pAnnotParent->unFlags |= (1 << 7);
}
oObj.free();
// 8 - Actions - A/AA
Object oAction;
if (oField.dictLookup("A", &oAction)->isDict())
{
std::string sAA = "A";
CAction* pA = getAction(pdfDoc, &oAction);
if (pA)
{
pA->sType = sAA;
pAnnotParent->arrAction.push_back(pA);
pAnnotParent->unFlags |= (1 << 8);
}
}
oAction.free();
Object oAA;
if (oField.dictLookup("AA", &oAA)->isDict())
{
for (int j = 0; j < oAA.dictGetLength(); ++j)
{
if (oAA.dictGetVal(j, &oAction)->isDict())
{
std::string sAA(oAA.dictGetKey(j));
CAction* pA = getAction(pdfDoc, &oAction);
if (pA)
{
pA->sType = sAA;
pAnnotParent->arrAction.push_back(pA);
pAnnotParent->unFlags |= (1 << 8);
}
}
oAction.free();
}
}
oAA.free();
// 9 - MaxLen
if (oField.dictLookup("MaxLen", &oObj)->isInt())
{
pAnnotParent->unMaxLen = oObj.getInt();
pAnnotParent->unFlags |= (1 << 9);
}
oObj.free();
// 10 - TU
if (oField.dictLookup("TU", &oObj)->isString())
{
TextString* s = new TextString(oObj.getString());
std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
pAnnotParent->unFlags |= (1 << 10);
pAnnotParent->sTU = sStr;
delete s;
}
oObj.free();
// 11 - MEOptions
if (oField.dictLookup("MEOptions", &oObj)->isInt())
{
pAnnotParent->unFlags |= (1 << 11);
pAnnotParent->unMEOptions = oObj.getInt();
}
oObj.free();
m_arrParents.push_back(pAnnotParent);
Object oParentRefObj;
if (oField.dictLookupNF("Parent", &oParentRefObj)->isRef())
{
pAnnotParent->unFlags |= (1 << 4);
pAnnotParent->unRefNumParent = oParentRefObj.getRefNum() + nStartRefID;
getParents(pdfDoc, &oParentRefObj, nStartRefID);
unsigned int unRefNumParent = pAnnotParent->unRefNumParent;
std::vector<CAnnotParent*>::iterator it = std::find_if(m_arrParents.begin(), m_arrParents.end(), [unRefNumParent](CAnnotParent* pP) { return pP->unRefNum == unRefNumParent; });
if (it != m_arrParents.end() && !((*it)->sFullName.empty()))
{
if (pAnnotParent->sFullName.empty())
pAnnotParent->sFullName = (*it)->sFullName;
else
pAnnotParent->sFullName = (*it)->sFullName + "." + pAnnotParent->sFullName;
}
}
oParentRefObj.free();
oField.free();
}
bool CAnnots::ChangeFullNameAnnot(int nAnnot, const std::string& sPrefixForm)
{
if (nAnnot < 0 || nAnnot > m_arrAnnots.size())
return false;
CAnnotWidget* pWidget = m_arrAnnots[nAnnot];
if (pWidget->m_bChangeFullName)
return true;
unsigned int unRefNumParent = pWidget->GetRefNumParent();
if (unRefNumParent)
{
std::vector<CAnnotParent*>::iterator it = std::find_if(m_arrParents.begin(), m_arrParents.end(), [unRefNumParent](CAnnotParent* pP) { return pP->unRefNum == unRefNumParent; });
if (it != m_arrParents.end() && ChangeFullNameParent(std::distance(m_arrParents.begin(), it), sPrefixForm))
{
const std::string& sFullNameChild = pWidget->GetFullName();
if (sFullNameChild.empty())
pWidget->SetFullName((*it)->sFullName);
else
pWidget->SetFullName((*it)->sFullName + "." + sFullNameChild);
pWidget->m_bChangeFullName = true;
return true;
}
}
return pWidget->ChangeFullName(sPrefixForm);
}
bool CAnnots::ChangeFullNameParent(int nParent, const std::string& sPrefixForm)
{
if (nParent < 0 || nParent > m_arrParents.size())
return false;
CAnnotParent* pParent = m_arrParents[nParent];
if (pParent->bChangeFullName)
return true;
if (pParent->unFlags & (1 << 4))
{
unsigned int unRefNumParent = pParent->unRefNumParent;
std::vector<CAnnotParent*>::iterator it = std::find_if(m_arrParents.begin(), m_arrParents.end(), [unRefNumParent](CAnnotParent* pP) { return pP->unRefNum == unRefNumParent; });
if (it != m_arrParents.end() && ChangeFullNameParent(std::distance(m_arrParents.begin(), it), sPrefixForm))
{
if (pParent->sT.empty())
pParent->sFullName = (*it)->sFullName;
else
pParent->sFullName = (*it)->sFullName + "." + sPrefixForm;
pParent->bChangeFullName = true;
return true;
}
}
else if (pParent->unFlags & (1 << 0))
{
pParent->sT += sPrefixForm;
pParent->sFullName += sPrefixForm;
pParent->bChangeFullName = true;
return true;
}
return false;
}
void CAnnots::CAnnotParent::ClearActions()
{
unFlags &= ~(1 << 8);
for (int i = 0; i < arrAction.size(); ++i)
RELEASEOBJECT(arrAction[i]);
arrAction.clear();
}
//------------------------------------------------------------------------
// Markup
//------------------------------------------------------------------------
CAnnotMarkup::CAnnotMarkup(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID) : CAnnot(pdfDoc, oAnnotRef, nPageIndex, nStartRefID)
{
m_unFlags = 0;
Object oAnnot, oObj;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// 0 - Popup annotation - Popup
if (oAnnot.dictLookupNF("Popup", &oObj)->isRef())
{
m_unFlags |= (1 << 0);
m_unRefNumPopup = oObj.getRefNum() + nStartRefID;
}
// 1 - User text label - T
m_sT = DictLookupString(&oAnnot, "T", 1);
// 2 - Opacity value - CA
if (oAnnot.dictLookup("CA", &oObj)->isNum())
{
m_unFlags |= (1 << 2);
m_dCA = oObj.getNum();
}
oObj.free();
// 3 - Rich text - RC
std::string sRC = DictLookupString(&oAnnot, "RC", 3);
// std::cout << sRC << std::endl;
// if (oAnnot.dictLookup("RC", &oObj)->isStream())
// TODO streamGetBlock
m_arrRC = ReadRC(sRC);
if (m_arrRC.empty())
m_unFlags &= ~(1 << 3);
else
m_unFlags |= (1 << 3);
// 4 - Creation date - CreationDate
m_sCreationDate = DictLookupString(&oAnnot, "CreationDate", 4);
// 5 - Reference to reply annotation - IRT
if (oAnnot.dictLookupNF("IRT", &oObj)->isRef())
{
m_unFlags |= (1 << 5);
m_unRefNumIRT = oObj.getRefNum() + nStartRefID;
}
oObj.free();
// 6 - Reply annotation type - RT
if (oAnnot.dictLookup("RT", &oObj)->isName())
{
m_unFlags |= (1 << 6);
m_nRT = 1; // Group
if (oObj.isName("R"))
m_nRT = 0;
}
oObj.free();
// 7 - Brief description - Subj
m_sSubj = DictLookupString(&oAnnot, "Subj", 7);
oAnnot.free();
}
CAnnotMarkup::~CAnnotMarkup()
{
for (int i = 0; i < m_arrRC.size(); ++i)
RELEASEOBJECT(m_arrRC[i]);
}
void CAnnotMarkup::SetFont(PDFDoc* pdfDoc, Object* oAnnotRef, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList)
{
GetFreeTextFont(pdfDoc, pFontManager, pFontList, oAnnotRef, m_arrRC);
}
//------------------------------------------------------------------------
// Annot
//------------------------------------------------------------------------
CAnnot::CAnnot(PDFDoc* pdfDoc, AcroFormField* pField, int nStartRefID)
{
m_pBorder = NULL;
m_unAnnotFlag = 0;
m_unAFlags = 0;
m_unFlags = 0;
Object oObj;
pField->getFieldRef(&oObj);
m_unRefNum = oObj.getRefNum() + nStartRefID;
oObj.free();
// Annotation flag - F
if (pField->fieldLookup("F", &oObj)->isInt())
m_unAnnotFlag = oObj.getInt();
oObj.free();
// Page number - P
m_unPage = pField->getPageNum();
// Coordinates - Rect
pField->getBBox(&m_pRect[0], &m_pRect[1], &m_pRect[2], &m_pRect[3]);
PDFRectangle* pCropBox = pdfDoc->getCatalog()->getPage(m_unPage)->getCropBox();
m_dHeight = pCropBox->y2;
m_dX = pCropBox->x1;
double dTemp = m_pRect[1];
m_pRect[0] = m_pRect[0] - m_dX;
m_pRect[1] = m_dHeight - m_pRect[3];
m_pRect[2] = m_pRect[2] - m_dX;
m_pRect[3] = m_dHeight - dTemp;
if (m_pRect[0] > m_pRect[2])
std::swap(m_pRect[0], m_pRect[2]);
if (m_pRect[1] > m_pRect[3])
std::swap(m_pRect[1], m_pRect[3]);
// 0 - Unique name - NM
if (pField->fieldLookup("NM", &oObj)->isString())
{
m_unAFlags |= (1 << 0);
TextString* s = new TextString(oObj.getString());
m_sNM = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
// 1 - Alternative text - Contents
if (pField->fieldLookup("Contents", &oObj)->isString())
{
m_unAFlags |= (1 << 1);
TextString* s = new TextString(oObj.getString());
m_sContents = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
// 2 - Border effects - BE
if (pField->fieldLookup("BE", &oObj)->isDict())
{
Object oBorderBE;
m_unAFlags |= (1 << 2);
m_pBE.first = 0;
if (oObj.dictLookup("S", &oBorderBE)->isName("C"))
m_pBE.first = 1;
oBorderBE.free();
m_pBE.second = 0;
if (oObj.dictLookup("I", &oBorderBE)->isNum())
m_pBE.second = oBorderBE.getNum();
oBorderBE.free();
}
oObj.free();
// 3 - Special color for annotation - C
if (pField->fieldLookup("C", &oObj)->isArray())
{
m_unAFlags |= (1 << 3);
int nCLength = oObj.arrayGetLength();
for (int j = 0; j < nCLength; ++j)
{
Object oCj;
m_arrC.push_back(oObj.arrayGet(j, &oCj)->isNum() ? oCj.getNum() : 0.0);
oCj.free();
}
}
oObj.free();
// 4 - Borders and Dash Pattern - Border/BS
m_pBorder = NULL;
if (pField->fieldLookup("BS", &oObj)->isDict())
m_pBorder = getBorder(&oObj, true);
else
{
oObj.free();
if (pField->fieldLookup("Border", &oObj)->isArray() && oObj.arrayGetLength() > 2)
m_pBorder = getBorder(&oObj, false);
}
oObj.free();
if (m_pBorder && m_pBorder->nType != 5)
m_unAFlags |= (1 << 4);
// 5 - Last modification date - M
if (pField->fieldLookup("M", &oObj)->isString())
{
m_unAFlags |= (1 << 5);
TextString* s = new TextString(oObj.getString());
m_sM = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
// 6 - Presence/Absence of appearance
if (std::abs(m_pRect[2] - m_pRect[0]) * std::abs(m_pRect[3] - m_pRect[1]) < 1073741824.0 / 3.0 && pField->fieldLookup("AP", &oObj)->isDict() && oObj.dictGetLength() &&
(oObj.free(), true) && (nStartRefID == 0 || pField->fieldLookup("OONoAP", &oObj)->isNull()))
m_unAFlags |= (1 << 6);
oObj.free();
// 7 - User ID
if (pField->fieldLookup("OUserID", &oObj)->isString())
{
m_unAFlags |= (1 << 7);
TextString* s = new TextString(oObj.getString());
m_sOUserID = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
// 9 - OO form metadata - OMetadata
if (pField->fieldLookup("OMetadata", &oObj)->isString())
{
m_unAFlags |= (1 << 9);
TextString* s = new TextString(oObj.getString());
m_sOMetadata = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
}
CAnnot::CAnnot(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID)
{
m_pBorder = NULL;
m_unAnnotFlag = 0;
m_unAFlags = 0;
m_unFlags = 0;
Object oAnnot, oObj, oObj2;
XRef* pXref = pdfDoc->getXRef();
oAnnotRef->fetch(pXref, &oAnnot);
// Annotation object number
m_unRefNum = oAnnotRef->getRefNum() + nStartRefID;
// Annotation flag - F
if (oAnnot.dictLookup("F", &oObj)->isInt())
m_unAnnotFlag = oObj.getInt();
oObj.free();
// Page number - P
m_unPage = nPageIndex;
PDFRectangle* pCropBox = pdfDoc->getCatalog()->getPage(m_unPage)->getCropBox();
m_dHeight = pCropBox->y2;
m_dX = pCropBox->x1;
// Coordinates - Rect
m_pRect[0] = 0.0, m_pRect[1] = 0.0, m_pRect[2] = 0.0, m_pRect[3] = 0.0;
if (oAnnot.dictLookup("Rect", &oObj)->isArray() && oObj.arrayGetLength() == 4)
{
m_pRect[0] = ArrGetNum(&oObj, 0) - m_dX;
m_pRect[1] = m_dHeight - ArrGetNum(&oObj, 3);
m_pRect[2] = ArrGetNum(&oObj, 2) - m_dX;
m_pRect[3] = m_dHeight - ArrGetNum(&oObj, 1);
if (m_pRect[0] > m_pRect[2])
std::swap(m_pRect[0], m_pRect[2]);
if (m_pRect[1] > m_pRect[3])
std::swap(m_pRect[1], m_pRect[3]);
}
oObj.free();
// 0 - Unique name - NM
if (oAnnot.dictLookup("NM", &oObj)->isString())
{
m_unAFlags |= (1 << 0);
TextString* s = new TextString(oObj.getString());
m_sNM = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
// 1 - Alternative text - Contents
if (oAnnot.dictLookup("Contents", &oObj)->isString())
{
m_unAFlags |= (1 << 1);
TextString* s = new TextString(oObj.getString());
m_sContents = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
// 2 - Border effects - BE
if (oAnnot.dictLookup("BE", &oObj)->isDict())
{
Object oBorderBE;
m_unAFlags |= (1 << 2);
m_pBE.first = 0;
if (oObj.dictLookup("S", &oBorderBE)->isName("C"))
m_pBE.first = 1;
oBorderBE.free();
m_pBE.second = 0;
if (oObj.dictLookup("I", &oBorderBE)->isNum())
m_pBE.second = oBorderBE.getNum();
oBorderBE.free();
}
oObj.free();
// 3 - Color - C
if (oAnnot.dictLookup("C", &oObj)->isArray())
{
m_unAFlags |= (1 << 3);
int nBCLength = oObj.arrayGetLength();
for (int j = 0; j < nBCLength; ++j)
{
m_arrC.push_back(oObj.arrayGet(j, &oObj2)->isNum() ? oObj2.getNum() : 0.0);
oObj2.free();
}
}
oObj.free();
// 4 - Borders and Dash Pattern - Border/BS
m_pBorder = NULL;
if (oAnnot.dictLookup("BS", &oObj)->isDict())
m_pBorder = getBorder(&oObj, true);
else
{
oObj.free();
if (oAnnot.dictLookup("Border", &oObj)->isArray() && oObj.arrayGetLength() > 2)
m_pBorder = getBorder(&oObj, false);
}
oObj.free();
if (m_pBorder && m_pBorder->nType != 5)
m_unAFlags |= (1 << 4);
// 5 - Last modification date - M
if (oAnnot.dictLookup("M", &oObj)->isString())
{
m_unAFlags |= (1 << 5);
TextString* s = new TextString(oObj.getString());
m_sM = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
// 6 - Presence/Absence of appearance
if (std::abs(m_pRect[2] - m_pRect[0]) * std::abs(m_pRect[3] - m_pRect[1]) < 1073741824.0 / 3.0 && oAnnot.dictLookup("AP", &oObj)->isDict() && oObj.dictGetLength() && nStartRefID == 0)
m_unAFlags |= (1 << 6);
oObj.free();
// 7 - User ID
if (oAnnot.dictLookup("OUserID", &oObj)->isString())
{
m_unAFlags |= (1 << 7);
TextString* s = new TextString(oObj.getString());
m_sOUserID = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
// 9 - OO form metadata - OMetadata
if (oAnnot.dictLookup("OMetadata", &oObj)->isString())
{
m_unAFlags |= (1 << 9);
TextString* s = new TextString(oObj.getString());
m_sOMetadata = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
oAnnot.free();
}
CAnnot::~CAnnot()
{
RELEASEOBJECT(m_pBorder);
}
std::string CAnnot::DictLookupString(Object* pObj, const char* sName, int nByte)
{
std::string sRes;
Object oObj;
if (pObj->dictLookup(sName, &oObj)->isString())
{
m_unFlags |= (1 << nByte);
TextString* s = new TextString(oObj.getString());
sRes = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength());
delete s;
}
oObj.free();
return sRes;
}
//------------------------------------------------------------------------
// AP
//------------------------------------------------------------------------
CAnnotAP::CAnnotAP(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex, const char* sView, const char* sButtonView, AcroFormField* pField, int nStartRefID)
{
m_gfx = NULL;
m_pFrame = NULL;
m_pRendererOut = NULL;
m_pRenderer = NULL;
m_dRWScale = 1;
m_dRHScale = 1;
m_bIsStamp = false;
Object oAP;
if (pField->fieldLookup("AP", &oAP)->isDict() && oAP.dictGetLength())
{
// Annotation number for matching with AP
Object oRef;
pField->getFieldRef(&oRef);
m_unRefNum = oRef.getRefNum() + nStartRefID;
oRef.free();
// Coordinates - BBox
pField->getBBox(&m_dx1, &m_dy1, &m_dx2, &m_dy2);
if (std::abs(m_dx2 - m_dx1) * std::abs(m_dy2 - m_dy1) < 1073741824.0 / 3.0)
{
Init(pdfDoc, pFontManager, pFontList, nRasterW, nRasterH, nBackgroundColor, nPageIndex);
Draw(pdfDoc, &oAP, nRasterH, nBackgroundColor, nPageIndex, pField, sView, sButtonView);
}
}
oAP.free();
Clear();
}
CAnnotAP::CAnnotAP(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex, const char* sView, Object* oAnnotRef, int nStartRefID)
{
m_gfx = NULL;
m_pFrame = NULL;
m_pRendererOut = NULL;
m_pRenderer = NULL;
m_dRWScale = 1;
m_dRHScale = 1;
Object oAnnot, oAP, oSubtype;
XRef* xref = pdfDoc->getXRef();
oAnnotRef->fetch(xref, &oAnnot);
m_bIsStamp = oAnnot.dictLookup("Subtype", &oSubtype)->isName("Stamp") == gTrue;
if (oAnnot.dictLookup("AP", &oAP)->isDict())
{
m_unRefNum = oAnnotRef->getRefNum() + nStartRefID;
Init(&oAnnot);
if (std::abs(m_dx2 - m_dx1) * std::abs(m_dy2 - m_dy1) < 1073741824.0 / 3.0)
{
Init(pdfDoc, pFontManager, pFontList, nRasterW, nRasterH, nBackgroundColor, nPageIndex);
Draw(pdfDoc, &oAP, nRasterH, nBackgroundColor, oAnnotRef, sView);
}
}
oAP.free(); oAnnot.free(); oSubtype.free();
Clear();
}
CAnnotAP::~CAnnotAP()
{
Clear();
for (int i = 0; i < m_arrAP.size(); ++i)
{
RELEASEOBJECT(m_arrAP[i]);
}
}
void CAnnotAP::Clear()
{
RELEASEOBJECT(m_gfx);
RELEASEOBJECT(m_pFrame);
RELEASEOBJECT(m_pRendererOut);
RELEASEOBJECT(m_pRenderer);
}
void CAnnotAP::Init(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, int nRasterW, int nRasterH, int nBackgroundColor, int nPageIndex)
{
Page* pPage = pdfDoc->getCatalog()->getPage(nPageIndex);
PDFRectangle* pCropBox = pPage->getCropBox();
m_dCropX = pCropBox->x1;
m_dCropY = pCropBox->y1;
double dWidth = round(pdfDoc->getPageCropWidth(nPageIndex));
double dHeight = round(pdfDoc->getPageCropHeight(nPageIndex));
double dRasterW = (double)nRasterW * m_dRWScale;
double dRasterH = (double)nRasterH * m_dRHScale;
m_dWScale = dRasterW / dWidth;
m_dHScale = dRasterH / dHeight;
m_nWidth = (int)round((m_dx2 - m_dx1) * m_dWScale);
m_nHeight = (int)round((m_dy2 - m_dy1) * m_dHScale);
m_dWTale = m_nWidth - (m_dx2 - m_dx1) * m_dWScale;
m_dHTale = m_nHeight - (m_dy2 - m_dy1) * m_dHScale;
m_nWidth += 2;
m_nHeight += 2;
// Drawing on transparent canvas with specified background color
BYTE* pBgraData = new BYTE[m_nWidth * m_nHeight * 4];
unsigned int nColor = (unsigned int)nBackgroundColor;
unsigned int nSize = (unsigned int)(m_nWidth * m_nHeight);
unsigned int* pTemp = (unsigned int*)pBgraData;
for (unsigned int i = 0; i < nSize; ++i)
*pTemp++ = nColor;
m_pFrame = new CBgraFrame();
m_pFrame->put_Data(pBgraData);
m_pFrame->put_Width(m_nWidth);
m_pFrame->put_Height(m_nHeight);
m_pFrame->put_Stride(4 * m_nWidth);
m_pRenderer = NSGraphics::Create();
m_pRenderer->SetFontManager(pFontManager);
m_pRenderer->CreateFromBgraFrame(m_pFrame);
m_pRenderer->SetSwapRGB(true);
m_pRenderer->put_Width ((m_dx2 - m_dx1 + (2 + m_dWTale) * dWidth / dRasterW) * 25.4 / 72.0);
m_pRenderer->put_Height((m_dy2 - m_dy1 + (2 + m_dHTale) * dHeight / dRasterH) * 25.4 / 72.0);
if (nBackgroundColor != 0xFFFFFF)
m_pRenderer->CommandLong(c_nDarkMode, 1);
m_pRenderer->CommandLong(c_nPenWidth0As1px, 1);
m_pRendererOut = new RendererOutputDev(m_pRenderer, pFontManager, pFontList);
m_pRendererOut->NewPDF(pdfDoc->getXRef());
// Create Gfx
GBool crop = gTrue;
PDFRectangle box;
// Rotation not required
pPage->makeBox(72.0, 72.0, 0, gFalse, m_pRendererOut->upsideDown(), -1, -1, -1, -1, &box, &crop);
PDFRectangle* cropBox = pPage->getCropBox();
m_gfx = new Gfx(pdfDoc, m_pRendererOut, nPageIndex, pPage->getAttrs()->getResourceDict(), 72.0, 72.0, &box, crop ? cropBox : (PDFRectangle *)NULL, 0, NULL, NULL);
// Appearance coordinates
m_dRx1 = ((m_bIsStamp ? m_dx1S: m_dx1) - m_dCropX) * m_dWScale - 1;
m_dRy1 = (pdfDoc->getPageCropHeight(nPageIndex) - (m_bIsStamp ? m_dy2S : m_dy2) + m_dCropY) * m_dHScale - 1;
}
void CAnnotAP::Init(Object* oAnnot)
{
Object oObj, oObj2;
if (oAnnot->dictLookup("Rect", &oObj)->isArray() && oObj.arrayGetLength() == 4)
{
m_dx1 = ArrGetNum(&oObj, 0);
m_dy1 = ArrGetNum(&oObj, 1);
m_dx2 = ArrGetNum(&oObj, 2);
m_dy2 = ArrGetNum(&oObj, 3);
if (m_bIsStamp)
{
m_dx1S = m_dx1;
m_dy2S = m_dy2;
double m[6] = { 1, 0, 0, 1, 0, 0 }, bbox[4] = { m_dx1, m_dy1, m_dx2, m_dy2 };
oObj.free();
Object oAP;
if (oAnnot->dictLookup("AP", &oAP)->isDict() && oAP.dictLookup("N", &oObj2)->isStream())
{
Object oObj1;
if (oObj2.streamGetDict()->lookup("BBox", &oObj)->isArray() && oObj.arrayGetLength() == 4)
{
for (int i = 0; i < 4; ++i)
{
oObj.arrayGet(i, &oObj1);
bbox[i] = oObj1.isNum() ? oObj1.getNum() : 0;
oObj1.free();
}
}
oObj.free();
if (oObj2.streamGetDict()->lookup("Matrix", &oObj)->isArray() && oObj.arrayGetLength() == 6)
{
for (int i = 0; i < 6; ++i)
{
oObj.arrayGet(i, &oObj1);
m[i] = oObj1.getNum();
oObj1.free();
}
}
}
oAP.free(); oObj2.free();
double formXMin, formYMin, formXMax, formYMax, x, y, sx, sy;
x = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
y = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
formXMin = formXMax = x;
formYMin = formYMax = y;
x = bbox[0] * m[0] + bbox[3] * m[2] + m[4];
y = bbox[0] * m[1] + bbox[3] * m[3] + m[5];
if (x < formXMin)
formXMin = x;
else if (x > formXMax)
formXMax = x;
if (y < formYMin)
formYMin = y;
else if (y > formYMax)
formYMax = y;
x = bbox[2] * m[0] + bbox[1] * m[2] + m[4];
y = bbox[2] * m[1] + bbox[1] * m[3] + m[5];
if (x < formXMin)
formXMin = x;
else if (x > formXMax)
formXMax = x;
if (y < formYMin)
formYMin = y;
else if (y > formYMax)
formYMax = y;
x = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
y = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
if (x < formXMin)
formXMin = x;
else if (x > formXMax)
formXMax = x;
if (y < formYMin)
formYMin = y;
else if (y > formYMax)
formYMax = y;
if (formXMin == formXMax)
sx = 1;
else
sx = (m_dx2 - m_dx1) / (formXMax - formXMin);
if (formYMin == formYMax)
sy = 1;
else
sy = (m_dy2 - m_dy1) / (formYMax - formYMin);
m_dx1 = bbox[0];
m_dy1 = bbox[1];
m_dx2 = bbox[2];
m_dy2 = bbox[3];
m_dRWScale = sx;
m_dRHScale = sy;
}
double dTemp;
if (m_dx1 > m_dx2)
{
dTemp = m_dx1; m_dx1 = m_dx2; m_dx2 = dTemp;
}
if (m_dy1 > m_dy2)
{
dTemp = m_dy1; m_dy1 = m_dy2; m_dy2 = dTemp;
}
}
oObj.free();
}
void CAnnotAP::Draw(PDFDoc* pdfDoc, Object* oAP, int nRasterH, int nBackgroundColor, int nPageIndex, AcroFormField* pField, const char* sView, const char* sButtonView)
{
// Drawing annotation appearances
AcroFormFieldType oType = pField->getAcroFormFieldType();
((GlobalParamsAdaptor*)globalParams)->setDrawFormField(true);
double dOffsetX = -(m_dx1 - m_dCropX) * m_dWScale + 1 + m_dWTale / 2;
double dOffsetY = (m_dy2 - m_dCropY) * m_dHScale - nRasterH + 1 + m_dHTale / 2;
std::vector<const char*> arrAPName { "N", "D", "R" };
for (unsigned int j = 0; j < arrAPName.size(); ++j)
{
if (sView && strcmp(sView, arrAPName[j]) != 0)
continue;
Object oObj;
if (oAP->dictLookup(arrAPName[j], &oObj)->isDict())
{
for (int k = 0; k < oObj.dictGetLength(); ++k)
{
if (sButtonView)
{
if (strcmp(sButtonView, "Off") == 0 && strcmp(oObj.dictGetKey(k), "Off") != 0)
continue;
if (strcmp(sButtonView, "Yes") == 0 && strcmp(oObj.dictGetKey(k), "Off") == 0)
continue;
}
CAnnotAPView* pView = new CAnnotAPView();
pView->sAPName = arrAPName[j];
pView->sASName = oObj.dictGetKey(k);
if ((oType == acroFormFieldRadioButton || oType == acroFormFieldCheckbox) && pView->sASName != "Off")
pView->sASName = "Yes";
m_pRenderer->SetCoordTransformOffset(dOffsetX, dOffsetY);
DrawAppearance(pdfDoc, nPageIndex, pField, m_gfx, arrAPName[j], pView->sASName.c_str());
WriteAppearance(nBackgroundColor, pView);
pView->nBlendMode = GetBlendMode();
m_arrAP.push_back(pView);
}
}
else if (!oObj.isNull())
{
CAnnotAPView* pView = new CAnnotAPView();
pView->sAPName = arrAPName[j];
m_pRenderer->SetCoordTransformOffset(dOffsetX, dOffsetY);
DrawAppearance(pdfDoc, nPageIndex, pField, m_gfx, arrAPName[j], NULL);
WriteAppearance(nBackgroundColor, pView);
pView->nBlendMode = GetBlendMode();
m_arrAP.push_back(pView);
}
oObj.free();
}
((GlobalParamsAdaptor*)globalParams)->setDrawFormField(false);
}
void CAnnotAP::Draw(PDFDoc* pdfDoc, Object* oAP, int nRasterH, int nBackgroundColor, Object* oAnnotRef, const char* sView)
{
((GlobalParamsAdaptor*)globalParams)->setDrawFormField(true);
// Drawing annotation appearances
Object oAnnot;
XRef* xref = pdfDoc->getXRef();
oAnnotRef->fetch(xref, &oAnnot);
double dOffsetX = -(m_dx1 - m_dCropX) * m_dWScale + 1 + m_dWTale / 2;
double dOffsetY = (m_dy2 - m_dCropY) * m_dHScale - (double)nRasterH * m_dRHScale + 1 + m_dHTale / 2;
std::vector<const char*> arrAPName { "N", "D", "R" };
for (unsigned int j = 0; j < arrAPName.size(); ++j)
{
if (sView && strcmp(sView, arrAPName[j]) != 0)
continue;
Object oObj;
if (oAP->dictLookup(arrAPName[j], &oObj)->isStream())
{
CAnnotAPView* pView = new CAnnotAPView();
pView->sAPName = arrAPName[j];
m_pRenderer->SetCoordTransformOffset(dOffsetX, dOffsetY);
Ref ref = oAnnotRef->getRef();
Annot* annot = new Annot(pdfDoc, oAnnot.getDict(), &ref, arrAPName[j]);
if (annot)
{
annot->generateAnnotAppearance();
if (m_bIsStamp)
{
double dCA = 1;
Object oCA;
if (oAnnot.dictLookup("CA", &oCA)->isNum())
dCA = oCA.getNum();
oCA.free();
m_gfx->setIgnoreStampOpacity(dCA);
}
annot->draw(m_gfx, gFalse);
if (m_bIsStamp)
m_gfx->setIgnoreStampOpacity(1);
}
RELEASEOBJECT(annot);
WriteAppearance(nBackgroundColor, pView);
pView->nBlendMode = GetBlendMode();
m_arrAP.push_back(pView);
}
oObj.free();
}
oAnnot.free();
((GlobalParamsAdaptor*)globalParams)->setDrawFormField(false);
}
void CAnnotAP::WriteAppearance(unsigned int nColor, CAnnotAPView* pView)
{
BYTE* pSubMatrix = new BYTE[m_nWidth * m_nHeight * 4];
int p = 0;
unsigned int* pTemp = (unsigned int*)m_pFrame->get_Data();
unsigned int* pSubTemp = (unsigned int*)pSubMatrix;
for (int y = 0; y < m_nHeight; ++y)
{
for (int x = 0; x < m_nWidth; ++x)
{
pSubTemp[p++] = pTemp[y * m_nWidth + x];
pTemp[y * m_nWidth + x] = nColor;
}
}
pView->pAP = pSubMatrix;
}
BYTE CAnnotAP::GetBlendMode()
{
return 0;
}
//------------------------------------------------------------------------
// ToWASM
//------------------------------------------------------------------------
void CAnnotAP::ToWASM(NSWasm::CData& oRes)
{
if (m_arrAP.empty())
return;
oRes.AddInt(m_unRefNum);
oRes.AddDouble(m_dRx1);
oRes.AddDouble(m_dRy1);
oRes.AddInt(m_nWidth);
oRes.AddInt(m_nHeight);
oRes.AddInt((unsigned int)m_arrAP.size());
for (int i = 0; i < m_arrAP.size(); ++i)
{
oRes.WriteString(m_arrAP[i]->sAPName);
oRes.WriteString(m_arrAP[i]->sASName);
unsigned long long npSubMatrix = (unsigned long long)m_arrAP[i]->pAP;
unsigned int npSubMatrix1 = npSubMatrix & 0xFFFFFFFF;
oRes.AddInt(npSubMatrix1);
oRes.AddInt(npSubMatrix >> 32);
oRes.WriteBYTE(m_arrAP[i]->nBlendMode);
}
}
void CAnnots::ToWASM(NSWasm::CData& oRes)
{
// Calculation order - CO
oRes.AddInt(m_arrCO.size());
for (int i = 0; i < m_arrCO.size(); ++i)
oRes.AddInt(m_arrCO[i]);
// Parent Fields
oRes.AddInt(m_arrParents.size());
for (int i = 0; i < m_arrParents.size(); ++i)
m_arrParents[i]->ToWASM(oRes);
oRes.AddInt(m_arrAnnots.size());
for (int i = 0; i < m_arrAnnots.size(); ++i)
m_arrAnnots[i]->ToWASM(oRes);
}
void CAnnots::CAnnotParent::ToWASM(NSWasm::CData& oRes)
{
oRes.AddInt(unRefNum);
oRes.AddInt(unFlags);
if (unFlags & (1 << 0))
oRes.WriteString(sT);
if (unFlags & (1 << 1))
oRes.WriteString(sV);
if (unFlags & (1 << 2))
oRes.WriteString(sDV);
if (unFlags & (1 << 3))
{
oRes.AddInt((unsigned int)arrI.size());
for (int i = 0; i < arrI.size(); ++i)
oRes.AddInt(arrI[i]);
}
if (unFlags & (1 << 4))
oRes.AddInt(unRefNumParent);
if (unFlags & (1 << 5))
{
oRes.AddInt((unsigned int)arrV.size());
for (int i = 0; i < arrV.size(); ++i)
oRes.WriteString(arrV[i]);
}
if (unFlags & (1 << 6))
{
oRes.AddInt(arrOpt.size());
for (int i = 0; i < arrOpt.size(); ++i)
{
oRes.WriteString(arrOpt[i].first);
oRes.WriteString(arrOpt[i].second);
}
}
if (unFlags & (1 << 7))
oRes.AddInt(unFieldFlag);
if (unFlags & (1 << 8))
{
oRes.AddInt(arrAction.size());
for (int i = 0; i < arrAction.size(); ++i)
{
oRes.WriteString(arrAction[i]->sType);
arrAction[i]->ToWASM(oRes);
}
}
if (unFlags & (1 << 9))
oRes.AddInt(unMaxLen);
if (unFlags & (1 << 10))
oRes.WriteString(sTU);
if (unFlags & (1 << 11))
oRes.AddInt(unMEOptions);
}
void CAnnot::ToWASM(NSWasm::CData& oRes)
{
oRes.AddInt(m_unRefNum);
oRes.AddInt(m_unAnnotFlag);
oRes.AddInt(m_unPage - 1);
for (int i = 0; i < 4; ++i)
oRes.WriteDouble(m_pRect[i]);
oRes.AddInt(m_unAFlags);
if (m_unAFlags & (1 << 0))
oRes.WriteString(m_sNM);
if (m_unAFlags & (1 << 1))
oRes.WriteString(m_sContents);
if (m_unAFlags & (1 << 2))
{
oRes.WriteBYTE(m_pBE.first);
oRes.AddDouble(m_pBE.second);
}
if (m_unAFlags & (1 << 3))
{
oRes.AddInt((unsigned int)m_arrC.size());
for (int i = 0; i < m_arrC.size(); ++i)
oRes.WriteDouble(m_arrC[i]);
}
if (m_pBorder && (m_unAFlags & (1 << 4)))
m_pBorder->ToWASM(oRes);
if (m_unAFlags & (1 << 5))
oRes.WriteString(m_sM);
if (m_unAFlags & (1 << 7))
oRes.WriteString(m_sOUserID);
if (m_unAFlags & (1 << 9))
oRes.WriteString(m_sOMetadata);
}
void CAnnot::CBorderType::ToWASM(NSWasm::CData& oRes)
{
BYTE nBP = nType;
if (nBP == 1)
nBP = 2;
else if (nBP == 2)
nBP = 1;
oRes.WriteBYTE(nBP);
oRes.AddDouble(dWidth);
if (nType == annotBorderDashed)
{
oRes.AddInt(arrDash.size());
for (int i = 0; i < arrDash.size(); ++i)
oRes.AddDouble(arrDash[i]);
}
}
void CAnnotWidget::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(m_nType);
CAnnot::ToWASM(oRes);
oRes.WriteString(m_sFontName);
oRes.AddDouble(m_dFontSize);
oRes.AddInt(m_unFontStyle);
oRes.AddInt(m_arrTC.size());
for (int i = 0; i < m_arrTC.size(); ++i)
oRes.WriteDouble(m_arrTC[i]);
oRes.WriteBYTE(m_nQ);
oRes.AddInt(m_unFieldFlag);
oRes.AddInt(m_unFlags);
if (m_unFlags & (1 << 0))
oRes.WriteString(m_sTU);
if (m_unFlags & (1 << 1))
oRes.WriteString(m_sDS);
if (m_unFlags & (1 << 2))
oRes.WriteString(m_sActualFontName);
if (m_unFlags & (1 << 3))
oRes.WriteBYTE(m_nH);
if (m_unFlags & (1 << 4))
oRes.WriteString(m_sFontKey);
if (m_unFlags & (1 << 5))
{
oRes.AddInt(m_arrBC.size());
for (int i = 0; i < m_arrBC.size(); ++i)
oRes.WriteDouble(m_arrBC[i]);
}
if (m_unFlags & (1 << 6))
oRes.AddInt(m_unR);
if (m_unFlags & (1 << 7))
{
oRes.AddInt(m_arrBG.size());
for (int i = 0; i < m_arrBG.size(); ++i)
oRes.WriteDouble(m_arrBG[i]);
}
if (m_unFlags & (1 << 8))
oRes.WriteString(m_sDV);
if (m_unFlags & (1 << 17))
oRes.AddInt(m_unRefNumParent);
if (m_unFlags & (1 << 18))
oRes.WriteString(m_sT);
if (m_unFlags & (1 << 19))
oRes.WriteString(m_sButtonFontName);
if (m_unFlags & (1 << 21))
oRes.AddInt(m_unMEOptions);
oRes.AddInt(m_arrAction.size());
for (int i = 0; i < m_arrAction.size(); ++i)
{
oRes.WriteString(m_arrAction[i]->sType);
m_arrAction[i]->ToWASM(oRes);
}
}
void CActionGoTo::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(1);
oRes.AddInt(unPage);
oRes.WriteBYTE(nKind);
switch (nKind)
{
case destXYZ:
case destFitH:
case destFitBH:
case destFitV:
case destFitBV:
{
oRes.AddInt(unKindFlag);
if (unKindFlag & (1 << 0))
oRes.AddDouble(pRect[0]);
if (unKindFlag & (1 << 1))
oRes.AddDouble(pRect[1]);
if (unKindFlag & (1 << 2))
oRes.AddDouble(pRect[2]);
break;
}
case destFitR:
{
oRes.AddDouble(pRect[0]);
oRes.AddDouble(pRect[1]);
oRes.AddDouble(pRect[2]);
oRes.AddDouble(pRect[3]);
break;
}
case destFit:
case destFitB:
default:
break;
}
CAction::ToWASM(oRes);
}
void CActionURI::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(6);
oRes.WriteString(sURI);
CAction::ToWASM(oRes);
}
void CActionNamed::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(10);
oRes.WriteString(sNamed);
CAction::ToWASM(oRes);
}
void CActionJavaScript::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(14);
oRes.WriteString(sJavaScript);
CAction::ToWASM(oRes);
}
void CActionHide::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(9);
oRes.WriteBYTE(bHideFlag ? 1 : 0);
oRes.AddInt(arrAnnotName.size());
for (int i = 0; i < arrAnnotName.size(); ++i)
oRes.WriteString(arrAnnotName[i]);
CAction::ToWASM(oRes);
}
void CActionResetForm::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(12);
oRes.AddInt(unFlags);
oRes.AddInt(arrAnnotName.size());
for (int i = 0; i < arrAnnotName.size(); ++i)
oRes.WriteString(arrAnnotName[i]);
CAction::ToWASM(oRes);
}
void CAction::ToWASM(NSWasm::CData& oRes)
{
if (pNext)
{
oRes.WriteBYTE(1);
pNext->ToWASM(oRes);
}
else
oRes.WriteBYTE(0);
}
void CAnnotWidgetBtn::ToWASM(NSWasm::CData& oRes)
{
CAnnotWidget::ToWASM(oRes);
if (m_unFlags & (1 << 9))
oRes.WriteString(m_sV);
if (m_nType == 27)
{
oRes.AddInt(m_unIFFlag);
if (m_unFlags & (1 << 10))
oRes.WriteString(m_sCA);
if (m_unFlags & (1 << 11))
oRes.WriteString(m_sRC);
if (m_unFlags & (1 << 12))
oRes.WriteString(m_sAC);
if (m_unFlags & (1 << 13))
oRes.WriteBYTE(m_nTP);
if (m_unIFFlag & (1 << 0))
{
if (m_unIFFlag & (1 << 1))
oRes.WriteBYTE(m_nSW);
if (m_unIFFlag & (1 << 2))
oRes.WriteBYTE(m_nS);
if (m_unIFFlag & (1 << 3))
{
oRes.AddDouble(m_dA1);
oRes.AddDouble(m_dA2);
}
}
}
else
{
oRes.WriteBYTE(m_nStyle);
if (m_unFlags & (1 << 10))
{
oRes.AddInt(m_arrOpt.size());
for (int i = 0; i < m_arrOpt.size(); ++i)
{
oRes.WriteString(m_arrOpt[i].first);
oRes.WriteString(m_arrOpt[i].second);
}
}
if (m_unFlags & (1 << 14))
oRes.WriteString(m_sAP_N_Yes);
}
}
void CAnnotWidgetTx::ToWASM(NSWasm::CData& oRes)
{
CAnnotWidget::ToWASM(oRes);
if (m_unFlags & (1 << 9))
oRes.WriteString(m_sV);
if (m_unFlags & (1 << 10))
oRes.AddInt(m_unMaxLen);
if (m_unFlags & (1 << 11))
oRes.WriteString(m_sRV);
}
void CAnnotWidgetCh::ToWASM(NSWasm::CData& oRes)
{
CAnnotWidget::ToWASM(oRes);
if (m_unFlags & (1 << 9))
oRes.WriteString(m_sV);
if (m_unFlags & (1 << 10))
{
oRes.AddInt(m_arrOpt.size());
for (int i = 0; i < m_arrOpt.size(); ++i)
{
oRes.WriteString(m_arrOpt[i].first);
oRes.WriteString(m_arrOpt[i].second);
}
}
if (m_unFlags & (1 << 11))
oRes.AddInt(m_unTI);
if (m_unFlags & (1 << 12))
{
oRes.AddInt(m_arrI.size());
for (int i = 0; i < m_arrI.size(); ++i)
oRes.AddInt(m_arrI[i]);
}
if (m_unFlags & (1 << 13))
{
oRes.AddInt(m_arrV.size());
for (int i = 0; i < m_arrV.size(); ++i)
oRes.WriteString(m_arrV[i]);
}
}
void CAnnotWidgetSig::ToWASM(NSWasm::CData& oRes)
{
CAnnotWidget::ToWASM(oRes);
}
void CAnnotMarkup::ToWASM(NSWasm::CData& oRes)
{
CAnnot::ToWASM(oRes);
oRes.AddInt(m_unFlags);
if (m_unFlags & (1 << 0))
oRes.AddInt(m_unRefNumPopup);
if (m_unFlags & (1 << 1))
oRes.WriteString(m_sT);
if (m_unFlags & (1 << 2))
oRes.AddDouble(m_dCA);
if (m_unFlags & (1 << 3))
{
oRes.AddInt(m_arrRC.size());
for (int i = 0; i < m_arrRC.size(); ++i)
{
oRes.WriteBYTE(m_arrRC[i]->nAlign);
oRes.AddInt(m_arrRC[i]->unFontFlags);
if (m_arrRC[i]->unFontFlags & (1 << 5))
oRes.AddDouble(m_arrRC[i]->dVAlign);
if (m_arrRC[i]->unFontFlags & (1 << 6))
oRes.WriteString(m_arrRC[i]->sActualFont);
oRes.AddDouble(m_arrRC[i]->dFontSise);
oRes.WriteDouble(m_arrRC[i]->dColor[0]);
oRes.WriteDouble(m_arrRC[i]->dColor[1]);
oRes.WriteDouble(m_arrRC[i]->dColor[2]);
oRes.WriteString(m_arrRC[i]->sFontFamily);
oRes.WriteString(m_arrRC[i]->sText);
}
}
if (m_unFlags & (1 << 4))
oRes.WriteString(m_sCreationDate);
if (m_unFlags & (1 << 5))
oRes.AddInt(m_unRefNumIRT);
if (m_unFlags & (1 << 6))
oRes.WriteBYTE(m_nRT);
if (m_unFlags & (1 << 7))
oRes.WriteString(m_sSubj);
}
void CAnnotText::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(0); // Text
CAnnotMarkup::ToWASM(oRes);
if (m_unFlags & (1 << 16))
oRes.WriteBYTE(m_nName);
if (m_unFlags & (1 << 17))
oRes.WriteBYTE(m_nStateModel);
if (m_unFlags & (1 << 18))
oRes.WriteBYTE(m_nState);
}
void CAnnotLink::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(1); // Link
CAnnot::ToWASM(oRes);
oRes.AddInt(m_unFlags);
if (m_unFlags & (1 << 0))
m_pAction->ToWASM(oRes);
if (m_unFlags & (1 << 1))
m_pPA->ToWASM(oRes);
if (m_unFlags & (1 << 2))
oRes.WriteBYTE(m_nH);
if (m_unFlags & (1 << 3))
{
oRes.AddInt((unsigned int)m_arrQuadPoints.size());
for (int i = 0; i < m_arrQuadPoints.size(); ++i)
oRes.AddDouble(m_arrQuadPoints[i]);
}
if (m_unFlags & (1 << 4))
{
for (int i = 0; i < 4; ++i)
oRes.AddDouble(m_pRD[i]);
}
}
void CAnnotScreen::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(20); // Screen
CAnnot::ToWASM(oRes);
oRes.AddInt(m_unFlags);
if (m_unFlags & (1 << 0))
oRes.WriteString(m_sT);
if (m_unFlags & (1 << 1))
{
oRes.AddInt(m_arrBC.size());
for (int i = 0; i < m_arrBC.size(); ++i)
oRes.WriteDouble(m_arrBC[i]);
}
if (m_unFlags & (1 << 2))
oRes.AddInt(m_unR);
if (m_unFlags & (1 << 3))
{
oRes.AddInt(m_arrBG.size());
for (int i = 0; i < m_arrBG.size(); ++i)
oRes.WriteDouble(m_arrBG[i]);
}
if (m_unFlags & (1 << 4))
{
oRes.AddInt(m_arrAction.size());
for (int i = 0; i < m_arrAction.size(); ++i)
{
oRes.WriteString(m_arrAction[i]->sType);
m_arrAction[i]->ToWASM(oRes);
}
}
}
void CAnnotPopup::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(15); // Popup
CAnnot::ToWASM(oRes);
oRes.AddInt(m_unFlags);
if (m_unFlags & (1 << 1))
oRes.AddInt(m_unRefNumParent);
}
void CAnnotInk::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(14); // Ink
CAnnotMarkup::ToWASM(oRes);
oRes.AddInt(m_arrInkList.size());
for (int i = 0; i < m_arrInkList.size(); ++i)
{
oRes.AddInt(m_arrInkList[i].size());
for (int j = 0; j < m_arrInkList[i].size(); ++j)
oRes.AddDouble(m_arrInkList[i][j]);
}
}
void CAnnotLine::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(3); // Line
CAnnotMarkup::ToWASM(oRes);
for (int i = 0; i < 4; ++i)
oRes.AddDouble(m_pL[i]);
if (m_unFlags & (1 << 15))
{
oRes.WriteBYTE(m_nLE[0]);
oRes.WriteBYTE(m_nLE[1]);
}
if (m_unFlags & (1 << 16))
{
oRes.AddInt((unsigned int)m_arrIC.size());
for (int i = 0; i < m_arrIC.size(); ++i)
oRes.WriteDouble(m_arrIC[i]);
}
if (m_unFlags & (1 << 17))
oRes.AddDouble(m_dLL);
if (m_unFlags & (1 << 18))
oRes.AddDouble(m_dLLE);
if (m_unFlags & (1 << 20))
oRes.WriteBYTE(m_nIT);
if (m_unFlags & (1 << 21))
oRes.AddDouble(m_dLLO);
if (m_unFlags & (1 << 22))
oRes.WriteBYTE(m_nCP);
if (m_unFlags & (1 << 23))
{
oRes.AddDouble(m_pCO[0]);
oRes.AddDouble(m_pCO[1]);
}
}
void CAnnotTextMarkup::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(m_nSubtype); // Highlight, Underline, Squiggly, StrikeOut
CAnnotMarkup::ToWASM(oRes);
oRes.AddInt((unsigned int)m_arrQuadPoints.size());
for (int i = 0; i < m_arrQuadPoints.size(); ++i)
oRes.AddDouble(m_arrQuadPoints[i]);
}
void CAnnotSquareCircle::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(m_nSubtype); // Square, Circle
CAnnotMarkup::ToWASM(oRes);
if (m_unFlags & (1 << 15))
{
for (int i = 0; i < 4; ++i)
oRes.AddDouble(m_pRD[i]);
}
if (m_unFlags & (1 << 16))
{
oRes.AddInt((unsigned int)m_arrIC.size());
for (int i = 0; i < m_arrIC.size(); ++i)
oRes.WriteDouble(m_arrIC[i]);
}
}
void CAnnotPolygonLine::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(m_nSubtype); // Polygon, PolyLine
CAnnotMarkup::ToWASM(oRes);
oRes.AddInt((unsigned int)m_arrVertices.size());
for (int i = 0; i < m_arrVertices.size(); ++i)
oRes.AddDouble(m_arrVertices[i]);
if (m_unFlags & (1 << 15))
{
oRes.WriteBYTE(m_nLE[0]);
oRes.WriteBYTE(m_nLE[1]);
}
if (m_unFlags & (1 << 16))
{
oRes.AddInt((unsigned int)m_arrIC.size());
for (int i = 0; i < m_arrIC.size(); ++i)
oRes.WriteDouble(m_arrIC[i]);
}
if (m_unFlags & (1 << 20))
oRes.WriteBYTE(m_nIT);
}
void CAnnotFreeText::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(2); // FreeText
CAnnotMarkup::ToWASM(oRes);
oRes.WriteBYTE(m_nQ);
oRes.AddInt(m_nRotate);
if (m_unFlags & (1 << 15))
{
for (int i = 0; i < 4; ++i)
oRes.AddDouble(m_pRD[i]);
}
if (m_unFlags & (1 << 16))
{
oRes.AddInt((unsigned int)m_arrCL.size());
for (int i = 0; i < m_arrCL.size(); ++i)
oRes.AddDouble(m_arrCL[i]);
}
if (m_unFlags & (1 << 17))
oRes.WriteString(m_sDS);
if (m_unFlags & (1 << 18))
oRes.WriteBYTE(m_nLE);
if (m_unFlags & (1 << 20))
oRes.WriteBYTE(m_nIT);
if (m_unFlags & (1 << 21))
{
oRes.AddInt((unsigned int)m_arrCFromDA.size());
for (int i = 0; i < m_arrCFromDA.size(); ++i)
oRes.WriteDouble(m_arrCFromDA[i]);
}
}
void CAnnotCaret::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(13); // Caret
CAnnotMarkup::ToWASM(oRes);
if (m_unFlags & (1 << 15))
{
for (int i = 0; i < 4; ++i)
oRes.AddDouble(m_pRD[i]);
}
if (m_unFlags & (1 << 16))
oRes.WriteBYTE(m_nSy);
}
void CAnnotFileAttachment::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(16); // FileAttachment
CAnnotMarkup::ToWASM(oRes);
if (m_unFlags & (1 << 15))
oRes.WriteString(m_sName);
if (m_unFlags & (1 << 16))
oRes.WriteString(m_sFS);
if (m_unFlags & (1 << 17))
oRes.WriteString(m_sF);
if (m_unFlags & (1 << 18))
oRes.WriteString(m_sUF);
if (m_unFlags & (1 << 19))
oRes.WriteString(m_sDOS);
if (m_unFlags & (1 << 20))
oRes.WriteString(m_sMac);
if (m_unFlags & (1 << 21))
oRes.WriteString(m_sUnix);
if (m_unFlags & (1 << 22))
{
oRes.WriteString(m_sID.first);
oRes.WriteString(m_sID.second);
}
if (m_unFlags & (1 << 24))
{
int nFlag = 0;
int nPos = oRes.GetSize();
oRes.AddInt(nFlag);
auto fWriteEF = [&oRes](CAnnotFileAttachment::CEmbeddedFile* pEF)
{
oRes.AddInt(pEF->nLength);
unsigned long long npSubMatrix = (unsigned long long)pEF->pFile;
unsigned int npSubMatrix1 = npSubMatrix & 0xFFFFFFFF;
oRes.AddInt(npSubMatrix1);
oRes.AddInt(npSubMatrix >> 32);
pEF->bFree = false;
};
// Memory release must be called from js side
if (m_pEF->m_pF)
{
nFlag |= (1 << 0);
fWriteEF(m_pEF->m_pF);
}
if (m_pEF->m_pUF)
{
nFlag |= (1 << 1);
fWriteEF(m_pEF->m_pUF);
}
if (m_pEF->m_pDOS)
{
nFlag |= (1 << 2);
fWriteEF(m_pEF->m_pDOS);
}
if (m_pEF->m_pMac)
{
nFlag |= (1 << 3);
fWriteEF(m_pEF->m_pMac);
}
if (m_pEF->m_pUnix)
{
nFlag |= (1 << 4);
fWriteEF(m_pEF->m_pUnix);
}
oRes.AddInt(nFlag, nPos);
}
if (m_unFlags & (1 << 25))
{
}
if (m_unFlags & (1 << 26))
oRes.WriteString(m_sDesc);
if (m_unFlags & (1 << 27))
{
}
}
void CAnnotStamp::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(12); // Stamp
CAnnotMarkup::ToWASM(oRes);
oRes.WriteString(m_sName);
oRes.WriteDouble(m_dRotate);
oRes.WriteDouble(m_dX1);
oRes.WriteDouble(m_dY1);
oRes.WriteDouble(m_dX2);
oRes.WriteDouble(m_dY2);
oRes.WriteDouble(m_dX3);
oRes.WriteDouble(m_dY3);
oRes.WriteDouble(m_dX4);
oRes.WriteDouble(m_dY4);
}
void CAnnotRedact::ToWASM(NSWasm::CData& oRes)
{
oRes.WriteBYTE(25); // Redact
CAnnotMarkup::ToWASM(oRes);
if (m_unFlags & (1 << 15))
{
oRes.AddInt((unsigned int)m_arrQuadPoints.size());
for (int i = 0; i < m_arrQuadPoints.size(); ++i)
oRes.AddDouble(m_arrQuadPoints[i]);
}
if (m_unFlags & (1 << 16))
{
oRes.AddInt((unsigned int)m_arrIC.size());
for (int i = 0; i < m_arrIC.size(); ++i)
oRes.WriteDouble(m_arrIC[i]);
}
if (m_unFlags & (1 << 17))
oRes.WriteString(m_sOverlayText);
if (m_unFlags & (1 << 19))
oRes.WriteBYTE(m_nQ);
if (m_unFlags & (1 << 20))
{
oRes.AddInt((unsigned int)m_arrCFromDA.size());
for (int i = 0; i < m_arrCFromDA.size(); ++i)
oRes.WriteDouble(m_arrCFromDA[i]);
oRes.AddDouble(m_dFontSize);
oRes.WriteString(m_sFontName);
oRes.WriteString(m_sActualFontName);
oRes.AddInt(m_unFontStyle);
}
}
}