From 35f0861e82a09fa3566ea4b36635ab8b3bf0a4e2 Mon Sep 17 00:00:00 2001 From: Kulikova Svetlana Date: Fri, 14 Apr 2023 17:08:10 +0300 Subject: [PATCH] ResetForm and Next Action --- .../pro/js/wasm/js/drawingfile_base.js | 84 +++++++---- .../graphics/pro/js/wasm/src/drawingfile.cpp | 138 +++++++++++------- PdfFile/PdfReader.cpp | 111 +++++++++----- PdfFile/lib/xpdf/AcroForm.cc | 7 + PdfFile/lib/xpdf/AcroForm.h | 2 + 5 files changed, 229 insertions(+), 113 deletions(-) diff --git a/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js b/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js index 1c0f3e1ea5..9e8c169b86 100644 --- a/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js +++ b/DesktopEditor/graphics/pro/js/wasm/js/drawingfile_base.js @@ -59,6 +59,12 @@ this.pos = start; this.limit = start + size; } + CBinaryReader.prototype.readByte = function() + { + var val = this.data[this.pos]; + this.pos += 1; + return val; + }; CBinaryReader.prototype.readInt = function() { var val = this.data[this.pos] | this.data[this.pos + 1] << 8 | this.data[this.pos + 2] << 16 | this.data[this.pos + 3] << 24; @@ -368,6 +374,54 @@ Module["_free"](ext); return res; }; + + function readAction(reader, rec) + { + var SType = reader.readString(); + rec["S"] = SType; + if (SType == "JavaScript") + { + rec["JS"] = reader.readString(); + } + else if (SType == "GoTo") + { + rec["GoTo"]["link"] = reader.readString(); + rec["GoTo"]["dest"] = reader.readDouble(); + } + else if (SType == "Named") + { + rec["N"] = reader.readString(); + } + else if (SType == "URI") + { + rec["URI"] = reader.readString(); + } + else if (SType == "Hide") + { + rec["Hide"]["H"] = reader.readInt(); + let m = reader.readInt(); + rec["Hide"]["T"] = []; + // В массиве используются номера аннотации из сопоставления с AP - rec["AP"]["i"] + for (let j = 0; j < m; ++j) + rec["Hide"]["T"].push(reader.readInt()); + } + else if (SType == "ResetForm") + { + rec["ResetForm"]["Flags"] = reader.readInt(); + let m = reader.readInt(); + rec["ResetForm"]["Fields"] = []; + // В массиве используются номера аннотации из сопоставления с AP - rec["AP"]["i"] + for (let j = 0; j < m; ++j) + rec["ResetForm"]["Fields"].push(reader.readInt()); + } + let NextAction = reader.readByte(); + if (NextAction) + { + rec["Next"] = {}; + readAction(reader, rec["Next"]); + } + } + CFile.prototype["getInteractiveFormsInfo"] = function() { var res = []; @@ -579,33 +633,7 @@ { var AAType = reader.readString(); rec["AA"][AAType] = {}; - var SType = reader.readString(); - rec["AA"][AAType]["S"] = SType; - if (SType == "JavaScript") - { - rec["AA"][AAType]["JS"] = reader.readString(); - } - else if (SType == "GoTo") - { - rec["AA"][AAType]["GoTo"]["link"] = reader.readString(); - rec["AA"][AAType]["GoTo"]["dest"] = reader.readDouble(); - } - else if (SType == "Named") - { - rec["AA"][AAType]["N"] = reader.readString(); - } - else if (SType == "URI") - { - rec["AA"][AAType]["URI"] = reader.readString(); - } - else if (SType == "Hide") - { - rec["AA"][AAType]["Hide"]["H"] = reader.readInt(); - let m = reader.readInt(); - rec["AA"][AAType]["Hide"]["T"] = []; - for (let j = 0; j < m; ++j) - rec["AA"][AAType]["Hide"]["T"].push(reader.readString()); - } + readAction(reader, rec["AA"][AAType]); } res.push(rec); @@ -728,7 +756,7 @@ while (reader.isValid()) { - // Иконка pushbutton аннотации + // Внешний вид pushbutton аннотации var MK = {}; // Номер для сопоставление с AP MK["i"] = reader.readInt(); diff --git a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp index 16363770a3..4bd0e7c218 100644 --- a/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp +++ b/DesktopEditor/graphics/pro/js/wasm/src/drawingfile.cpp @@ -203,11 +203,95 @@ WASM_EXPORT void SetCMapData(CGraphicsFileDrawing* pGraphics, BYTE* data, int si #ifdef TEST_CPP_BINARY +unsigned char READ_BYTE(BYTE* x) +{ + return x ? x[0] : 1; +} unsigned int READ_INT(BYTE* x) { return x ? (x[0] | x[1] << 8 | x[2] << 16 | x[3] << 24) : 4; } +void ReadAction(BYTE* pWidgets, int& i) +{ + unsigned int nPathLength = READ_INT(pWidgets + i); + i += 4; + std::string sType((char*)(pWidgets + i), nPathLength); + std::cout << "Type " << sType << ", "; + i += nPathLength; + + if (sType == "JavaScript") + { + nPathLength = READ_INT(pWidgets + i); + i += 4; + std::cout << "JS " << std::string((char*)(pWidgets + i), nPathLength) << ", "; + i += nPathLength; + } + else if (sType == "GoTo") + { + nPathLength = READ_INT(pWidgets + i); + i += 4; + std::cout << "GoTo " << std::string((char*)(pWidgets + i), nPathLength) << " "; + i += nPathLength; + nPathLength = READ_INT(pWidgets + i); + i += 4; + std::cout << "Y " << (double)nPathLength / 100.0 << ", "; + } + else if (sType == "Named") + { + nPathLength = READ_INT(pWidgets + i); + i += 4; + std::cout << "Named " << std::string((char*)(pWidgets + i), nPathLength) << ", "; + i += nPathLength; + } + else if (sType == "URI") + { + nPathLength = READ_INT(pWidgets + i); + i += 4; + std::cout << "URL " << std::string((char*)(pWidgets + i), nPathLength) << ", "; + i += nPathLength; + } + else if (sType == "Hide") + { + nPathLength = READ_INT(pWidgets + i); + i += 4; + std::cout << "Hide flag " << nPathLength << ", "; + + int nHideLength = READ_INT(pWidgets + i); + i += 4; + std::cout << "THide: "; + + for (int j = 0; j < nHideLength; ++j) + { + nPathLength = READ_INT(pWidgets + i); + i += 4; + std::cout << nPathLength << ", "; + } + } + else if (sType == "ResetForm") + { + nPathLength = READ_INT(pWidgets + i); + i += 4; + std::cout << "ResetForm flag " << nPathLength << ", "; + + int nResetLength = READ_INT(pWidgets + i); + i += 4; + std::cout << "annots: "; + + for (int j = 0; j < nResetLength; ++j) + { + nPathLength = READ_INT(pWidgets + i); + i += 4; + std::cout << nPathLength << ", "; + } + } + + nPathLength = READ_BYTE(pWidgets + i); + i += 1; + if (nPathLength) + ReadAction(pWidgets, i); +} + #include "../../../../../fontengine/ApplicationFontsWorker.h" #include "../../../../../common/Directory.h" @@ -694,63 +778,13 @@ int main(int argc, char* argv[]) i += 4; for (int j = 0; j < nActLength; ++j) { + std::cout << std::endl; nPathLength = READ_INT(pWidgets + i); i += 4; std::cout << std::to_string(j) << " Action " << std::string((char*)(pWidgets + i), nPathLength) << ", "; i += nPathLength; - nPathLength = READ_INT(pWidgets + i); - i += 4; - std::string sType((char*)(pWidgets + i), nPathLength); - std::cout << "Type " << sType << ", "; - i += nPathLength; - - if (sType == "JavaScript") - { - nPathLength = READ_INT(pWidgets + i); - i += 4; - std::cout << "JS " << std::string((char*)(pWidgets + i), nPathLength) << ", "; - i += nPathLength; - } - else if (sType == "GoTo") - { - nPathLength = READ_INT(pWidgets + i); - i += 4; - std::cout << "GoTo " << std::string((char*)(pWidgets + i), nPathLength) << " "; - i += nPathLength; - nPathLength = READ_INT(pWidgets + i); - i += 4; - std::cout << "Y " << (double)nPathLength / 100.0 << ", "; - } - else if (sType == "Named") - { - nPathLength = READ_INT(pWidgets + i); - i += 4; - std::cout << "Named " << std::string((char*)(pWidgets + i), nPathLength) << ", "; - i += nPathLength; - } - else if (sType == "URI") - { - nPathLength = READ_INT(pWidgets + i); - i += 4; - std::cout << "URL " << std::string((char*)(pWidgets + i), nPathLength) << ", "; - i += nPathLength; - } - else if (sType == "Hide") - { - nPathLength = READ_INT(pWidgets + i); - i += 4; - std::cout << "Hide flag " << nPathLength << ", "; - int nHideLength = READ_INT(pWidgets + i); - i += 4; - for (int j = 0; j < nHideLength; ++j) - { - nPathLength = READ_INT(pWidgets + i); - i += 4; - std::cout << std::to_string(j) << " THide " << std::string((char*)(pWidgets + i), nPathLength) << ", "; - i += nPathLength; - } - } + ReadAction(pWidgets, i); } std::cout << std::endl; } diff --git a/PdfFile/PdfReader.cpp b/PdfFile/PdfReader.cpp index 1a657ca162..1fb0e62066 100644 --- a/PdfFile/PdfReader.cpp +++ b/PdfFile/PdfReader.cpp @@ -721,8 +721,17 @@ BYTE* CPdfReader::GetLinks(int nPageIndex) void getAction(PDFDoc* pdfDoc, NSWasm::CData& oRes, Object* oAction, int nAnnot) { AcroForm* pAcroForms = pdfDoc->getCatalog()->getForm(); - if (!pAcroForms) - return; + + Object oActType; + std::string sSName; + if (oAction->dictLookup("S", &oActType)->isName()) + { + sSName = oActType.getName(); + oRes.WriteString((BYTE*)sSName.c_str(), (unsigned int)sSName.length()); + } + else + oRes.WriteString(NULL, 0); + oActType.free(); LinkAction* oAct = LinkAction::parseAction(oAction); if (!oAct) @@ -823,27 +832,19 @@ void getAction(PDFDoc* pdfDoc, NSWasm::CData& oRes, Object* oAction, int nAnnot) } if (oHide.isString()) { - TextString* s = new TextString(oHide.getString()); - std::string sStr = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); - oRes.WriteString((BYTE*)sStr.c_str(), (unsigned int)sStr.length()); - delete s; + GString* sField = oHide.getString(); + int nFind = pAcroForms->findFieldIdx(sField); + if (nFind >= 0) + { + oRes.AddInt(nFind); + } } else if (oHide.isRef()) { - for (int m = 0, nNum = pAcroForms->getNumFields(); m < nNum; ++m) + int nFind = pAcroForms->findFieldIdx(&oHide); + if (nFind >= 0) { - AcroFormField* pSField = pAcroForms->getField(nAnnot); - Object oSFieldRef; - if (pSField->getFieldRef(&oSFieldRef)->isRef() && oSFieldRef.getRefGen() == oHide.getRefGen() && oSFieldRef.getRefNum() == oHide.getRefNum()) - { - // TODO нельзя однозначно идентифицировать аннотацию по Т-имени, лучше использовать i из сопоставления с AP - int nLengthName; - Unicode* uName = pSField->getName(&nLengthName); - std::string sTName = NSStringExt::CConverter::GetUtf8FromUTF32(uName, nLengthName); - oRes.WriteString((BYTE*)sTName.c_str(), (unsigned int)sTName.length()); - gfree(uName); - break; - } + oRes.AddInt(nFind); } } k++; @@ -855,10 +856,64 @@ void getAction(PDFDoc* pdfDoc, NSWasm::CData& oRes, Object* oAction, int nAnnot) case actionUnknown: default: { + if (sSName == "ResetForm") + { + Object oObj; + if (oAction->dictLookup("Flags", &oObj)->isInt()) + oRes.AddInt(oObj.getInt()); + else + oRes.AddInt(0); + oObj.free(); + + if (oAction->dictLookup("Fields", &oObj)->isArray()) + { + int nFieldsPos = oRes.GetSize(); + int nFields = 0; + oRes.AddInt(nFields); + for (int j = 0; j < oObj.arrayGetLength(); ++j) + { + Object oField; + oObj.arrayGetNF(j, &oField); + if (oField.isString()) + { + GString* sField = oField.getString(); + int nFind = pAcroForms->findFieldIdx(sField); + if (nFind >= 0) + { + nFields++; + oRes.AddInt(nFind); + } + } + else if (oField.isRef()) + { + int nFind = pAcroForms->findFieldIdx(&oField); + if (nFind >= 0) + { + nFields++; + oRes.AddInt(nFind); + } + } + oField.free(); + } + oRes.AddInt(nFields, nFieldsPos); + } + else + oRes.AddInt(0); + oObj.free(); + } break; } } + Object oNextAction; + if (oAction->dictLookup("Next", &oNextAction)->isDict()) + { + oRes.WriteBYTE(1); + getAction(pdfDoc, oRes, &oNextAction, nAnnot); + } + else + oRes.WriteBYTE(0); + RELEASEOBJECT(oAct); }; BYTE* CPdfReader::GetWidgets() @@ -1698,21 +1753,16 @@ oObj.free();\ oRes.AddInt(nActionLength); // Action - A - Object oAction, oActType; - if (pField->fieldLookup("A", &oAction)->isDict() && oAction.dictLookup("S", &oActType)->isName()) + Object oAction; + if (pField->fieldLookup("A", &oAction)->isDict()) { nActionLength++; std::string sAA = "A"; oRes.WriteString((BYTE*)sAA.c_str(), (unsigned int)sAA.length()); - - std::string sSName(oActType.getName()); - oRes.WriteString((BYTE*)sSName.c_str(), (unsigned int)sSName.length()); - oActType.free(); - getAction(m_pPDFDocument, oRes, &oAction, i); } - oAction.free(); oActType.free(); + oAction.free(); // Actions - AA Object oAA; @@ -1725,18 +1775,13 @@ oObj.free();\ std::string sAA(oAA.dictGetKey(j)); oRes.WriteString((BYTE*)sAA.c_str(), (unsigned int)sAA.length()); - if (!oAA.dictGetVal(j, &oAction)->isDict() || !oAction.dictLookup("S", &oActType)->isName()) + if (!oAA.dictGetVal(j, &oAction)->isDict()) { oRes.WriteString(NULL, 0); oAction.free(); - oActType.free(); continue; } - std::string sSName(oActType.getName()); - oRes.WriteString((BYTE*)sSName.c_str(), (unsigned int)sSName.length()); - oActType.free(); - getAction(m_pPDFDocument, oRes, &oAction, i); oAction.free(); } diff --git a/PdfFile/lib/xpdf/AcroForm.cc b/PdfFile/lib/xpdf/AcroForm.cc index c5f5abb0aa..30ee2ab376 100644 --- a/PdfFile/lib/xpdf/AcroForm.cc +++ b/PdfFile/lib/xpdf/AcroForm.cc @@ -608,6 +608,13 @@ int AcroForm::findFieldIdx(int pg, double x, double y) { return -1; } +int AcroForm::findFieldIdx(Object* oRefObj) { + return -1; +} +int AcroForm::findFieldIdx(GString* fullName) { + return -1; +} + //------------------------------------------------------------------------ // AcroFormField //------------------------------------------------------------------------ diff --git a/PdfFile/lib/xpdf/AcroForm.h b/PdfFile/lib/xpdf/AcroForm.h index 22c8704750..5eb05a9404 100644 --- a/PdfFile/lib/xpdf/AcroForm.h +++ b/PdfFile/lib/xpdf/AcroForm.h @@ -41,6 +41,8 @@ public: AcroFormField *getField(int idx); AcroFormField *findField(int pg, double x, double y); int findFieldIdx(int pg, double x, double y); + int findFieldIdx(Object* oRefObj); + int findFieldIdx(GString* fullName); private: