/* * 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 "OnlineOfficeBinToPdf.h" #include "../../DesktopEditor/common/Directory.h" #include "../../DesktopEditor/graphics/MetafileToRenderer.h" #include "../../DesktopEditor/graphics/commands/AnnotField.h" namespace NSOnlineOfficeBinToPdf { class CMetafileToRenderterPDF : public IMetafileToRenderter { public: CMetafileToRenderterPDF(IRenderer* pRenderer) : IMetafileToRenderter(pRenderer) { } public: virtual void SetLinearGradiant(const double& x0, const double& y0, const double& x1, const double& y1) { ((CPdfFile*)m_pRenderer)->SetLinearGradient(x0, y0, x1, y1); } virtual void SetRadialGradiant(const double& dX0, const double& dY0, const double& dR0, const double& dX1, const double& dY1, const double& dR1) { ((CPdfFile*)m_pRenderer)->SetRadialGradient(dX0, dY0, dR0, dX1, dY1, dR1); } }; static bool ConvertBufferToPdf(CPdfFile* pPdf, BYTE* pBuffer, LONG lBufferLen, CConvertFromBinParams* pParams) { CMetafileToRenderterPDF oCorrector(pPdf); oCorrector.SetTempDirectory(pPdf->GetTempDirectory()); if (pParams) { oCorrector.SetMediaDirectory(pParams->m_sMediaDirectory); oCorrector.SetInternalMediaDirectory(pParams->m_sInternalMediaDirectory); oCorrector.SetThemesDirectory(pParams->m_sThemesDirectory); if (pParams->m_bIsUsePicker) oCorrector.InitPicker(pPdf->GetFonts()); } NSOnlineOfficeBinToPdf::ConvertBufferToRenderer(pBuffer, lBufferLen, &oCorrector); return true; } bool ConvertBinToPdf(CPdfFile* pPdf, const std::wstring& wsSrcFile, const std::wstring& wsDstFile, bool bBinary, CConvertFromBinParams* pParams) { NSFile::CFileBinary oFile; if (!oFile.OpenFile(wsSrcFile)) return false; DWORD dwFileSize = oFile.GetFileSize(); BYTE* pFileContent = new BYTE[dwFileSize]; if (!pFileContent) { oFile.CloseFile(); return false; } DWORD dwReaded; oFile.ReadFile(pFileContent, dwFileSize, dwReaded); oFile.CloseFile(); bool bIsNeedDestroy = (NULL == pParams) ? true : false; if (bIsNeedDestroy) pParams = new CConvertFromBinParams(); if (pParams->m_sMediaDirectory.empty()) pParams->m_sMediaDirectory = NSFile::GetDirectoryName(wsSrcFile); if (bBinary) { ConvertBufferToPdf(pPdf, pFileContent, dwFileSize, pParams); } else { int nBufferLen = NSBase64::Base64DecodeGetRequiredLength(dwFileSize); BYTE* pBuffer = new BYTE[nBufferLen]; if (!pBuffer) { RELEASEARRAYOBJECTS(pFileContent); if (bIsNeedDestroy) RELEASEOBJECT(pParams); return false; } if (NSBase64::Base64Decode((const char*)pFileContent, dwFileSize, pBuffer, &nBufferLen)) { ConvertBufferToPdf(pPdf, pBuffer, nBufferLen, pParams); } else { RELEASEARRAYOBJECTS(pBuffer); RELEASEARRAYOBJECTS(pFileContent); if (bIsNeedDestroy) RELEASEOBJECT(pParams); return false; } RELEASEARRAYOBJECTS(pBuffer); } RELEASEARRAYOBJECTS(pFileContent); if (bIsNeedDestroy) RELEASEOBJECT(pParams); if (!wsDstFile.empty()) { if (0 != pPdf->SaveToFile(wsDstFile)) return false; } return true; } enum class AddCommandType { EditPage = 0, AddPage = 1, RemovePage = 2, WidgetInfo = 3, MovePage = 4, MergePages = 5, SetType = 6, RedactInfo = 7, Undefined = 255 }; bool AddBinToPdf(CPdfFile* pPdf, BYTE* pBuffer, unsigned int nBufferLen, CConvertFromBinParams* pParams) { CMetafileToRenderterPDF oCorrector(pPdf); oCorrector.SetTempDirectory(pPdf->GetTempDirectory()); if (pParams) { oCorrector.SetMediaDirectory(pParams->m_sMediaDirectory); oCorrector.SetInternalMediaDirectory(pParams->m_sInternalMediaDirectory); oCorrector.SetThemesDirectory(pParams->m_sThemesDirectory); if (pParams->m_bIsUsePicker) oCorrector.InitPicker(pPdf->GetFonts()); } NSOnlineOfficeBinToPdf::CBufferReader oReader(pBuffer, (int)nBufferLen); while (oReader.Check()) { int nLen = oReader.ReadInt(); AddCommandType CommandType = (AddCommandType)oReader.ReadByte(); int nPageNum = 0; if (CommandType != AddCommandType::WidgetInfo && CommandType != AddCommandType::MergePages && CommandType != AddCommandType::SetType) nPageNum = oReader.ReadInt(); if (nPageNum < 0) return false; switch (CommandType) { case AddCommandType::EditPage: { if (!pPdf->EditPage(nPageNum)) { oReader.Skip(nLen - 9); break; } NSOnlineOfficeBinToPdf::ConvertBufferToRenderer(oReader.GetCurrentBuffer(), (LONG)(nLen - 9) , &oCorrector); oReader.Skip(nLen - 9); break; } case AddCommandType::AddPage: { if (!pPdf->AddPage(nPageNum)) { oReader.Skip(nLen - 9); break; } NSOnlineOfficeBinToPdf::ConvertBufferToRenderer(oReader.GetCurrentBuffer(), (LONG)(nLen - 9) , &oCorrector); oReader.Skip(nLen - 9); break; } case AddCommandType::MovePage: { int nPos = oReader.ReadInt(); pPdf->MovePage(nPageNum, nPos); break; } case AddCommandType::RemovePage: { pPdf->DeletePage(nPageNum); break; } case AddCommandType::MergePages: { std::wstring wsPath = NSFile::CFileBinary::CreateTempFileWithUniqueName(pPdf->GetTempDirectory(), L"PDF"); int nLength = oReader.ReadInt(); BYTE* pFile = oReader.GetCurrentBuffer(); oReader.Skip(nLength); if (!wsPath.empty()) { NSFile::CFileBinary oFile; if (oFile.CreateFileW(wsPath)) oFile.WriteFile(pFile, nLength); oFile.CloseFile(); } int nMaxID = oReader.ReadInt(); std::wstring wsPrefix = oReader.ReadString(); pPdf->MergePages(wsPath, nMaxID, wsPrefix); break; } case AddCommandType::WidgetInfo: { NSOnlineOfficeBinToPdf::ConvertBufferToRenderer(oReader.GetCurrentBuffer(), (LONG)(nLen - 5) , &oCorrector); oReader.Skip(nLen - 5); break; } case AddCommandType::SetType: { pPdf->SetEditType(1); break; } case AddCommandType::RedactInfo: { int nFlags = nPageNum; std::vector arrForms; if (nFlags & (1 << 5)) // Form Fields { int nN = oReader.ReadInt(); for (int i = 0; i < nN; ++i) { bool bNewChange = oReader.ReadBool(); if (bNewChange) { NSOnlineOfficeBinToPdf::CommandType eCommand = (NSOnlineOfficeBinToPdf::CommandType)oReader.ReadByte(); if (eCommand == NSOnlineOfficeBinToPdf::CommandType::ctAnnotField) { BYTE* cur = oReader.GetCurrentBuffer(); int nLen2 = oReader.ReadInt(); CAnnotFieldInfo* command = new CAnnotFieldInfo(); if (command->Read(&oReader, &oCorrector)) arrForms.push_back(command); else RELEASEOBJECT(command); oReader.SetCurrentBuffer(cur + nLen2); } else { BYTE* cur = oReader.GetCurrentBuffer(); oReader.SetCurrentBuffer(cur + oReader.ReadInt()); } } else { CRedactAnnot* command = new CRedactAnnot(); if (command->Read(&oReader, &oCorrector)) arrForms.push_back(command); else RELEASEOBJECT(command); } } } pPdf->RedactInfo(nPageNum, arrForms); break; } default: return false; } } return true; } }