/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include "Adaptors.h" #include "../lib/xpdf/NameToCharCode.h" #include "../lib/xpdf/TextString.h" #include "../../DesktopEditor/graphics/pro/js/wasm/src/serialize.h" void GlobalParamsAdaptor::SetCMapFolder(const std::wstring &wsFolder) { m_wsCMapFolder = wsFolder; GString* sFolder = NSStrings::CreateString(wsFolder); if (!sFolder) return; unicodeMaps->add(new GString("ISO-8859-6"), sFolder->copy()->append("/ISO-8859-6.unicodeMap")); unicodeMaps->add(new GString("ISO-2022-CN"), sFolder->copy()->append("/ISO-2022-CN.unicodeMap")); unicodeMaps->add(new GString("EUC-CN"), sFolder->copy()->append("/EUC-CN.unicodeMap")); unicodeMaps->add(new GString("GBK"), sFolder->copy()->append("/GBK.unicodeMap")); unicodeMaps->add(new GString("KOI8-R"), sFolder->copy()->append("/KOI8-R.unicodeMap")); unicodeMaps->add(new GString("ISO-8859-7"), sFolder->copy()->append("/ISO-8859-7.unicodeMap")); unicodeMaps->add(new GString("ISO-8859-8"), sFolder->copy()->append("/ISO-8859-8.unicodeMap")); unicodeMaps->add(new GString("Windows-1255"), sFolder->copy()->append("/Windows-1255.unicodeMap")); unicodeMaps->add(new GString("ISO-2022-JP"), sFolder->copy()->append("/ISO-2022-JP.unicodeMap")); unicodeMaps->add(new GString("EUC-JP"), sFolder->copy()->append("/EUC-JP.unicodeMap")); unicodeMaps->add(new GString("Shift-JIS"), sFolder->copy()->append("/Shift-JIS.unicodeMap")); unicodeMaps->add(new GString("ISO-2022-KR"), sFolder->copy()->append("/ISO-2022-KR.unicodeMap")); unicodeMaps->add(new GString("TIS-620"), sFolder->copy()->append("/TIS-620.unicodeMap")); unicodeMaps->add(new GString("ISO-8859-9"), sFolder->copy()->append("/ISO-8859-9.unicodeMap")); unicodeMaps->add(new GString("Latin2"), sFolder->copy()->append("/Latin2.unicodeMap")); AddNameToUnicode(GString(sFolder->getCString()).append("/Bulgarian.nameToUnicode")->getCString()); AddNameToUnicode(GString(sFolder->getCString()).append("/Greek.nameToUnicode")->getCString()); AddNameToUnicode(GString(sFolder->getCString()).append("/Thai.nameToUnicode")->getCString()); AddAllCMap(sFolder); toUnicodeDirs->append(sFolder->copy()); delete sFolder; } void GlobalParamsAdaptor::AddNameToUnicode(const char* sFile) { char *tok1, *tok2; FILE *f; char buf[256]; Unicode u; if (!(f = openFile(sFile, "r"))) return; while (getLine(buf, sizeof(buf), f)) { tok1 = strtok(buf, " \t\r\n"); tok2 = strtok(NULL, " \t\r\n"); if (tok1 && tok2) { sscanf(tok1, "%x", &u); nameToUnicode->add(tok2, u); } } fclose(f); } void GlobalParamsAdaptor::AddAllCMap(GString* sFolder) { if (cidToUnicodes->lookup("Adobe-GB1")) return; cidToUnicodes->add(new GString("Adobe-GB1"), sFolder ? sFolder->copy()->append("/Adobe-GB1.cidToUnicode") : new GString()); cidToUnicodes->add(new GString("Adobe-CNS1"), sFolder ? sFolder->copy()->append("/Adobe-CNS1.cidToUnicode") : new GString()); cidToUnicodes->add(new GString("Adobe-Korea1"), sFolder ? sFolder->copy()->append("/Adobe-Korea1.cidToUnicode") : new GString()); cidToUnicodes->add(new GString("Adobe-KR"), sFolder ? sFolder->copy()->append("/Adobe-KR.cidToUnicode") : new GString()); cidToUnicodes->add(new GString("Adobe-Japan1"), sFolder ? sFolder->copy()->append("/Adobe-Japan1.cidToUnicode") : new GString()); if (sFolder) sFolder->append("/CMap"); AddCMapFolder("Adobe-GB1", sFolder); AddCMapFolder("Adobe-CNS1", sFolder); AddCMapFolder("Adobe-Japan1", sFolder); AddCMapFolder("Adobe-Korea1", sFolder); AddCMapFolder("Adobe-KR", sFolder); } void GlobalParamsAdaptor::AddCMapFolder(const char* sCollection, GString* sFolder) { GList *pList = new GList(); if (!pList) return; if (sFolder) { pList->append(sFolder->copy()); } cMapDirs->add(new GString(sCollection), pList); } void GlobalParamsAdaptor::SetCMapFile(const std::wstring &wsFile) { AddAllCMap(NULL); #ifndef BUILDING_WASM_MODULE NSFile::CFileBinary::ReadAllBytes(wsFile, &m_bCMapData, m_nCMapDataLength); #endif } void GlobalParamsAdaptor::SetCMapMemory(BYTE* pData, DWORD nSizeData) { AddAllCMap(NULL); if (pData) { m_bCMapData = pData; m_nCMapDataLength = nSizeData; } } DWORD GetLength(BYTE* x) { return x ? (x[0] | x[1] << 8 | x[2] << 16 | x[3] << 24) : 4; } bool GlobalParamsAdaptor::GetCMap(const char* sName, char*& pData, unsigned int& nSize) { if (!m_bCMapData) { if (m_wsCMapFolder.empty()) SetCMapFile(NSFile::GetProcessDirectory() + L"/cmap.bin"); if (!m_bCMapData) return false; } DWORD i = 0; while (i < m_nCMapDataLength) { DWORD nPathLength = GetLength(m_bCMapData + i); i += 4; std::string sName1 = std::string((char*)(m_bCMapData + i), nPathLength); i += nPathLength; nPathLength = GetLength(m_bCMapData + i); i += 4; if (sName1 == std::string(sName)) { pData = (char*)(m_bCMapData + i); nSize = nPathLength; return true; } else { i += nPathLength; } } return false; } void GlobalParamsAdaptor::AddRedact(const std::vector& arrRedactBox) { m_arrRedactBox.insert(m_arrRedactBox.end(), arrRedactBox.begin(), arrRedactBox.end()); } double crossProduct(double x1, double y1, double x2, double y2, double x3, double y3) { return (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1); } bool GlobalParamsAdaptor::InRedact(double dX, double dY) { for (int i = 0; i < m_arrRedactBox.size(); i += 8) { double x1 = m_arrRedactBox[i + 0]; double y1 = m_arrRedactBox[i + 1]; double x2 = m_arrRedactBox[i + 2]; double y2 = m_arrRedactBox[i + 3]; double x3 = m_arrRedactBox[i + 6]; double y3 = m_arrRedactBox[i + 7]; double x4 = m_arrRedactBox[i + 4]; double y4 = m_arrRedactBox[i + 5]; if (x1 == x2 && x2 == x3 && x3 == x4 && y1 == y2 && y2 == y3 && y3 == y4) { if (dX == x1 && dY == y1) return true; continue; } // Проверяем знаки векторных произведений для всех сторон double cross1 = crossProduct(x1, y1, x2, y2, dX, dY); double cross2 = crossProduct(x2, y2, x3, y3, dX, dY); double cross3 = crossProduct(x3, y3, x4, y4, dX, dY); double cross4 = crossProduct(x4, y4, x1, y1, dX, dY); bool allPositive = (cross1 >= 0 && cross2 >= 0 && cross3 >= 0 && cross4 >= 0); bool allNegative = (cross1 <= 0 && cross2 <= 0 && cross3 <= 0 && cross4 <= 0); // Точка внутри, если все векторные произведения имеют одинаковый знак if ((allPositive || allNegative) && !(cross1 == 0 && cross2 == 0 && cross3 == 0 && cross4 == 0)) return true; } return false; } void GlobalParamsAdaptor::ClearRedact() { m_arrRedactBox.clear(); } bool operator==(const Ref &a, const Ref &b) { return a.gen == b.gen && a.num == b.num; } bool operator<(const Ref &a, const Ref &b) { if (a.num < b.num) return true; else if (a.num == b.num) return a.gen < b.gen; else return false; } bool operator<=(const Ref &a, const Ref &b) { return (a < b) || (a == b); } bool operator>=(const Ref &a, const Ref &b) { return !(a < b); } bool operator>(const Ref &a, const Ref &b) { return !(a <= b); } namespace NSStrings { GString *CreateString(const std::wstring &str) { std::string sUtf8 = U_TO_UTF8(str); return new GString(sUtf8.c_str(), sUtf8.length()); } GString *CreateString(const std::string &str) { return new GString(str.c_str(), str.length()); } std::wstring GetString(GString *str) { if (!str) return L""; return NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE *) str->getCString(), (LONG) str->getLength()); } std::string GetStringA(GString *str) { return std::string(str->getCString(), str->getLength()); } std::wstring GetStringFromUTF32(GString* str) { if (!str) return L""; TextString* s = new TextString(str); std::wstring sValue = NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength()); delete s; return sValue; } std::string GetStringAFromUTF32(GString* str) { if (!str) return ""; TextString* s = new TextString(str); std::string sValue = NSStringExt::CConverter::GetUtf8FromUTF32(s->getUnicode(), s->getLength()); delete s; return sValue; } } void AppendStringToXml(std::wstring& wsXml, const std::string& sString) { std::wstring wsTmp(sString.begin(), sString.end()); wsXml += wsTmp; } void DictToXmlR(Object* obj, std::wstring& wsXml, bool bBinary) { Object oTemp; wsXml += L" type=\""; switch (obj->getType()) { case objBool: wsXml += L"Bool\" num=\""; wsXml += obj->getBool() ? L"true" : L"false"; wsXml += L"\">"; break; case objInt: wsXml += L"Int\" num=\""; wsXml += std::to_wstring(obj->getInt()); wsXml += L"\">"; break; case objReal: wsXml += L"Real\" num=\""; wsXml += std::to_wstring(obj->getReal()); wsXml += L"\">"; break; case objString: if (bBinary) { GString* str = obj->getString(); wsXml += L"Binary\" num=\""; wsXml += std::to_wstring(str->getLength()); wsXml += L"\">"; for (int nIndex = 0; nIndex < str->getLength(); ++nIndex) { wsXml += L""; wsXml += std::to_wstring((int)str->getChar(nIndex)); wsXml += L""; } } else { TextString* s = new TextString(obj->getString()); std::wstring sValue = NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength()); wsXml += L"String\" num=\""; wsXml += sValue; wsXml += L"\">"; delete s; } break; case objName: wsXml += L"Name\" num=\""; AppendStringToXml(wsXml, obj->getName()); wsXml += L"\">"; break; case objNull: wsXml += L"Null\">"; break; case objArray: wsXml += L"Array\">"; for (int nIndex = 0; nIndex < obj->arrayGetLength(); ++nIndex) { wsXml += L"arrayGetNF(nIndex, &oTemp); DictToXmlR(&oTemp, wsXml, bBinary); oTemp.free(); wsXml += L""; } break; case objDict: wsXml += L"Dict\">"; for (int nIndex = 0; nIndex < obj->dictGetLength(); ++nIndex) { char *sKey = obj->dictGetKey(nIndex); wsXml += L"<"; AppendStringToXml(wsXml, sKey); if (strcmp("Resources", sKey) == 0 || strcmp("AcroForm", sKey) == 0) obj->dictGetVal(nIndex, &oTemp); else obj->dictGetValNF(nIndex, &oTemp); DictToXmlR(&oTemp, wsXml, strcmp("ID", sKey) == 0 ? true : bBinary); oTemp.free(); wsXml += L""; } break; case objStream: wsXml += L"Stream\">"; break; case objRef: wsXml += L"Ref\" gen=\""; wsXml += std::to_wstring(obj->getRefGen()); wsXml += L"\" num=\""; wsXml += std::to_wstring(obj->getRefNum()); wsXml += L"\">"; break; case objCmd: wsXml += L"Cmd\" num=\""; AppendStringToXml(wsXml, obj->getCmd()); wsXml += L"\">"; break; case objError: wsXml += L"Error\">"; break; case objEOF: wsXml += L"EOF\">"; break; case objNone: wsXml += L"None\">"; break; } } std::wstring XMLConverter::DictToXml(const std::wstring& wsName, Object* obj, int nNum, int nGen, bool bBinary) { std::wstring sRes = L"<" + wsName; if (nNum > 0) { sRes += (L" num=\"" + std::to_wstring(nNum) + L"\""); sRes += (L" gen=\"" + std::to_wstring(nGen) + L"\""); } DictToXmlR(obj, sRes, bBinary); sRes += (L""); return sRes; } XMLConverter::XMLConverter(XRef* pXRef, bool isParseStreams) { m_pXRef = pXRef; m_bParseStreams = isParseStreams; m_nNumMax = 0; ParseDicts(); PdfToXml(); } void XMLConverter::ParseDicts() { m_nNumMax = m_pXRef->getSize() + 1000; for (int nNum = 0, nCount = m_pXRef->getSize(); nNum < nCount; ++nNum) { XRefEntry *pEntry = m_pXRef->getEntry(nNum); if (xrefEntryFree != pEntry->type) { Object oTemp; m_pXRef->fetch(nNum, 0, &oTemp); if (oTemp.isDict() || oTemp.isStream()) { Dict* pDict = NULL; if (oTemp.isDict()) pDict = oTemp.getDict(); else if (oTemp.isStream()) pDict = oTemp.streamGetDict(); if (pDict) m_mDict.insert({pDict, nNum}); } oTemp.free(); } } } void XMLConverter::ObjectToXml(Object *pObject, bool isSkipCheck) { Object oTemp; switch (pObject->getType()) { case objBool: m_wsXml += pObject->getBool() ? L"true" : L"false"; break; case objInt: m_wsXml += std::to_wstring(pObject->getInt()); break; case objReal: m_wsXml += std::to_wstring(pObject->getReal()); break; case objString: m_wsXml += L"("; Append(pObject->getString()); m_wsXml += L")"; break; case objName: m_wsXml += L"/"; Append(pObject->getName()); break; case objNull: m_wsXml += L"null"; break; case objArray: m_wsXml += L"["; for (int nIndex = 0; nIndex < pObject->arrayGetLength(); ++nIndex) { if (nIndex > 0) m_wsXml += L" "; pObject->arrayGet(nIndex, &oTemp); ObjectToXml(&oTemp); } m_wsXml += L"]"; break; case objDict: { Dict* pDict = pObject->getDict(); if (!isSkipCheck && CheckDict(pDict)) return; DictToXml(pDict); break; } case objStream: m_wsXml += L""; // TODO: Запись стрима break; case objRef: m_wsXml += std::to_wstring(pObject->getRefNum()); m_wsXml += L" "; m_wsXml += std::to_wstring(pObject->getRefGen()); m_wsXml += L" R"; break; case objCmd: AppendStringToXml(m_wsXml, pObject->getCmd()); break; case objError: m_wsXml += L"error"; break; case objEOF: m_wsXml += L"EOF"; break; case objNone: m_wsXml += L"none"; break; } } void XMLConverter::PdfToXml() { std::vector vPassed; for (int nNum = 0, nCount = m_pXRef->getSize(); nNum < nCount; ++nNum) { XRefEntry *pEntry = m_pXRef->getEntry(nNum); if (xrefEntryFree != pEntry->type) { Object oTemp; m_pXRef->fetch(nNum, 0, &oTemp); if (oTemp.isDict() || oTemp.isStream()) { if (xrefEntryCompressed == pEntry->type) m_wsXml += L"nGen*/) + L"\" compressed=\"true\">"; else m_wsXml += L"nGen*/) + L"\">"; if (oTemp.isDict()) { ObjectToXml(&oTemp, true); } else if (oTemp.isStream()) { Dict *pStreamDict = oTemp.streamGetDict(); StreamDictToXml(pStreamDict, true); m_wsXml += L""; if (m_bParseStreams) { std::wstring wsTemp; Stream *pStream = oTemp.getStream(); pStream->reset(); Object oFilter; pStreamDict->lookup("Filter", &oFilter); if (oFilter.isNull() || oFilter.isName("FlateDecode")) { int nChar; while (EOF != (nChar = pStream->getChar())) { char sTemp[1] = {(char) nChar}; switch (sTemp[0]) { case '\"': wsTemp += L"""; break; case '&': wsTemp += L"&"; break; case '<': wsTemp += L"<"; break; case '>': wsTemp += L">"; break; default: AppendStringToXml(wsTemp, sTemp); } } } else { m_wsXml += L"BinaryData"; } m_wsXml += wsTemp; } m_wsXml += L""; } m_wsXml += L""; } oTemp.free(); } } } void XMLConverter::StreamDictToXml(Dict *pStreamDict, bool isSkipCheck) { if (!isSkipCheck && CheckDict(pStreamDict)) return; Object oTemp; for (int nIndex = 0, nCount = pStreamDict->getLength(); nIndex < nCount; ++nIndex) { char *sKey = pStreamDict->getKey(nIndex); m_wsXml += L"<"; Append(sKey); m_wsXml += L">"; pStreamDict->getVal(nIndex, &oTemp); ObjectToXml(&oTemp); oTemp.free(); m_wsXml += L""; } } void XMLConverter::DictToXml(Dict* pDict) { Object oTemp; for (int nIndex = 0, nCount = pDict->getLength(); nIndex < nCount; ++nIndex) { char *sKey = pDict->getKey(nIndex); m_wsXml += L"<"; Append(sKey); m_wsXml += L">"; pDict->getVal(nIndex, &oTemp); ObjectToXml(&oTemp); m_wsXml += L""; } } bool XMLConverter::CheckDict(Dict *pDict) { std::map::iterator iter = m_mDict.find(pDict); if (iter != m_mDict.end()) { m_wsXml += std::to_wstring(iter->second) + L" 0 R"; return true; } m_mDict.insert({pDict, ++m_nNumMax}); return false; }