/* * (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 "oox_package.h" #include #include "../../Common/utf8cpp/utf8.h" #include "mediaitems.h" #include "../../../DesktopEditor/common/File.h" #include "../../../DesktopEditor/common/SystemUtils.h" #include "../../../DesktopEditor/graphics/pro/Image.h" #include "../../../DesktopEditor/raster/Metafile/MetaFileCommon.h" #include "../../../DesktopEditor/raster/ImageFileFormatChecker.h" #include "../../../OOXML/Base/Base.h" #include "../../../Common/cfcpp/compoundfile.h" #include "../../../Common/3dParty/pole/pole.h" namespace cpdoccore { namespace oox { namespace package { static void ConvertSvmToImage(std::wstring &file_svm, std::wstring &file_png, NSFonts::IApplicationFonts *pAppFonts) { MetaFile::IMetaFile* pMetaFile = MetaFile::Create(pAppFonts); if (pMetaFile->LoadFromFile(file_svm.c_str())) { MetaFile::ConvertToRasterMaxSize(pMetaFile, file_png.c_str(), _CXIMAGE_FORMAT_PNG, 1000); pMetaFile->Close(); } RELEASEOBJECT(pMetaFile); } static std::wstring get_mime_type(const std::wstring & extension) { if (L"eps" == extension) return L"image/x-eps"; else if (L"wmf" == extension) return L"image/x-wmf"; else if (L"emf" == extension) return L"image/x-emf"; else if (L"gif" == extension) return L"image/x-gif"; else if (L"png" == extension) return L"image/x-png"; else if (L"jpg" == extension) return L"image/x-jpeg"; else if (L"jpeg" == extension) return L"image/x-jpeg"; else if (L"tif" == extension) return L"image/x-tiff"; else if (L"tiff" == extension) return L"image/x-tiff"; else if (L"pdf" == extension) return L"application/pdf"; else if (L"bmp" == extension) return L"image/bmp"; else if (L"wdp" == extension) return L"image/vnd.ms-photo"; else if (L"wav" == extension) return L"audio/wav"; else if (L"mp3" == extension) return L"audio/mpeg"; else if (L"wma" == extension) return L"audio/x-ms-wma"; else if (L"m4a" == extension) return L"audio/m4a"; else if (L"avi" == extension) return L"video/x-msvideo"; else if (L"wmv" == extension) return L"video/x-ms-wmv"; else if (L"mov" == extension) return L"video/mov"; else if (L"mp4" == extension) return L"video/mp4"; else if (L"m4v" == extension) return L"video/m4v"; else if (L"mkv" == extension) return L"video/mkv"; else if (L"webm" == extension) return L"video/webm"; else if (L"bin" == extension) return L"application/vnd.openxmlformats-officedocument.oleObject"; else if (L"xlsx" == extension) return L"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; else if (L"docx" == extension) return L"application/vnd.openxmlformats-officedocument.wordprocessingml.document"; else if (L"doc" == extension) return L"application/msword"; else if (L"vsd" == extension) return L"application/vnd.visio"; else if (L"vsdx" == extension) return L"application/vnd.ms-visio.drawing"; else return L"application/octet-stream"; return L""; } //---------------------------------------------------------------- void element::set_main_document(document * _document) { document_ = _document; } document * element::get_main_document() { return document_; } content_types_file::content_types_file() : filename_(L"[Content_Types].xml") {} void content_types_file::write(const std::wstring & RootPath) { std::wstringstream resStream; content_type_content_.xml_to_stream(resStream); std::wstring res = resStream.str(); simple_element elm(filename_, res); elm.write(RootPath); } content_type * content_types_file::content() { return &content_type_content_; } bool content_types_file::add_or_find_default(const std::wstring & extension) { if (extension.empty()) return true; std::vector & defaults = content_type_content_.get_default(); for (size_t i = 0 ; i < defaults.size(); i++) { if (defaults[i].extension() == extension) return true; } content_type_content_.add_default(extension, get_mime_type(extension)); return true; } bool content_types_file::add_or_find_override(const std::wstring & fileName) { std::vector & override_ = content_type_content_.get_override(); for (size_t i = 0 ; i < override_.size(); i++) { if (override_[i].part_name() == fileName) return true; } std::wstring content_type; int pos = fileName.rfind(L"."); std::wstring extension = pos >= 0 ? fileName.substr(pos + 1) : L""; if (extension == L"xlsx") { content_type = L"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; content_type_content_.add_override(fileName, content_type); } if (extension == L"bin") { //content_type = L"application/vnd.openxmlformats-officedocument.oleObject"; add_or_find_default(extension); } return true; } void content_types_file::set_media(mediaitems_ptr & _Mediaitems) { std::vector & items_ = _Mediaitems->items(); for (size_t i = 0; i < items_.size(); i++) { if ((items_[i].type == typeImage || items_[i].type == typeMedia || items_[i].type == typeVideo || items_[i].type == typeAudio) && items_[i].mediaInternal) { int n = items_[i].outputName.rfind(L"."); if (n > 0) { add_or_find_default(items_[i].outputName.substr(n + 1, items_[i].outputName.length() - n)); } } } } void content_types_file::set_media(mediaitems & _Mediaitems) { std::vector & items_ = _Mediaitems.items(); for (size_t i = 0; i < items_.size(); i++) { if ((items_[i].type == typeImage || items_[i].type == typeMedia || items_[i].type == typeVideo || items_[i].type == typeAudio) && items_[i].mediaInternal) { int n = items_[i].outputName.rfind(L"."); if (n > 0) { add_or_find_default(items_[i].outputName.substr(n + 1, items_[i].outputName.length() - n)); } } } } ///////////////////////////////////////////////////////////////////////// simple_element::simple_element(const std::wstring & FileName, const std::wstring & Content) : file_name_(FileName), bXml(true) { utf8::utf16to8(Content.begin(), Content.end(), std::back_inserter(content_utf8_)); } simple_element::simple_element(const std::wstring & FileName, const std::string & Content) : file_name_(FileName), content_utf8_(Content), bXml(false) { } void simple_element::write(const std::wstring & RootPath) { std::wstring name_ = RootPath + FILE_SEPARATOR_STR + file_name_; NSFile::CFileBinary file; if ( file.CreateFileW(name_) == true) { if (bXml) { std::string root = ""; file.WriteFile((BYTE*)root.c_str(), root.length()); } file.WriteFile((BYTE*)content_utf8_.c_str(), content_utf8_.length()); file.CloseFile(); } } rels_file::rels_file(std::wstring const & FileName) : filename_(FileName) {}; rels_file_ptr rels_file::create(std::wstring const & FileName) { return boost::make_shared( boost::ref(FileName) ); } void rels_file::write(const std::wstring & RootPath) { std::wstringstream resStream; rels_.xml_to_stream(resStream); simple_element elm(filename_, resStream.str()); elm.write(RootPath); } void rels_files::write(const std::wstring & RootPath) { std::wstring path = RootPath + FILE_SEPARATOR_STR + L"_rels"; NSDirectory::CreateDirectory(path.c_str()); if (rels_file_) rels_file_->write(path); } void rels_files::add(relationship const & r) { if (rels_file * rf = get_rel_file()) { rf->get_rels().relationships().push_back(r); } } void rels_files::add(std::wstring const & Id, std::wstring const & Type, std::wstring const & Target, std::wstring const & TargetMode) { return add(relationship(Id, Type, Target, TargetMode)); } //----------------------------------------------------------------------------------------------- chart_content::chart_content() : rels_(rels_file::create(L"")) { } _CP_PTR(chart_content) chart_content::create() { return boost::make_shared(); } void chart_content::add_rel(relationship const & r) { rels_->get_rels().add(r); } //----------------------------------------------------------------------------------------------- _CP_PTR(customXml_content) customXml_content::create(const std::wstring &item, const std::wstring &props) { return boost::make_shared(item, props); } //----------------------------------------------------------------------------------------------- simple_element_ptr simple_element::create(const std::wstring & FileName, const std::wstring & Content) { return boost::make_shared(FileName, Content); } simple_element_ptr simple_element::create(const std::wstring & FileName, const std::string & Content) { return boost::make_shared(FileName, Content); } //----------------------------------------------------------------------------------------------- docProps_files::docProps_files() { } std::wstring docProps_files::create_core() { std::wstringstream resStream; resStream << L""; resStream << L"1"; resStream << L""; return resStream.str(); } std::wstring docProps_files::create_app() { std::wstringstream resStream; resStream << L""; resStream << L""; std::wstring sApplication = NSSystemUtils::GetEnvVariable(NSSystemUtils::gc_EnvApplicationName); if (sApplication.empty()) sApplication = NSSystemUtils::gc_EnvApplicationNameDefault; resStream << sApplication; #if defined(INTVER) std::string s = VALUE2STR(INTVER); resStream << L"/" << std::wstring(s.begin(), s.end()) ; #endif resStream << L""; return resStream.str(); } void docProps_files::set_app(element_ptr Element) { app_ = Element; } void docProps_files::set_core(element_ptr Element) { core_ = Element; } void docProps_files::set_custom(element_ptr Element) { custom_ = Element; } void docProps_files::write(const std::wstring & RootPath) { std::wstring path = RootPath + FILE_SEPARATOR_STR + L"docProps"; NSDirectory::CreateDirectory(path.c_str()); if (!core_) core_ = simple_element::create(L"core.xml", create_core()); if (!app_) app_ = simple_element::create(L"app.xml", create_app()); core_->write(path); app_->write(path); if (custom_) custom_->write(path); } //--------------------------------------------------------------------------------------------------- media::media(mediaitems_ptr & _mediaitems, NSFonts::IApplicationFonts *pAppFonts) : mediaItems_(_mediaitems), appFonts_(pAppFonts) { } void media::write(const std::wstring & RootPath) { std::wstring path = RootPath + FILE_SEPARATOR_STR + L"media"; NSDirectory::CreateDirectory(path.c_str()); mediaitems::items_array & items = mediaItems_->items(); for (size_t i = 0; i < items.size(); i++ ) { if (items[i].valid && ( items[i].type == typeImage || items[i].type == typeMedia || items[i].type == typeAudio || items[i].type == typeVideo )) { std::wstring &file_name = items[i].href; std::wstring file_name_out = RootPath + FILE_SEPARATOR_STR + items[i].outputName; if (file_name.empty()) continue; CImageFileFormatChecker svmFileChecker; if (svmFileChecker.isSvmFile(file_name)) { ConvertSvmToImage(file_name, file_name_out, appFonts_); } else NSFile::CFileBinary::Copy(file_name, file_name_out); } } } //------------------------------------------------------------------------------------------------------------ charts::charts(mediaitems_ptr & _chartsItems) : chartsItems_(_chartsItems) { } void charts::write(const std::wstring & RootPath) { } //-------------------------------------------------------------------------------------------------------------- embeddings::embeddings(mediaitems_ptr & _EmbeddingsItems) : embeddingsItems_(_EmbeddingsItems) { } void embeddings::write(const std::wstring & RootPath) { std::wstring path = RootPath + FILE_SEPARATOR_STR + L"embeddings"; NSDirectory::CreateDirectory(path.c_str()); content_types_file & content_types = get_main_document()->get_content_types_file(); mediaitems::items_array & items = embeddingsItems_->items(); for (size_t i = 0; i < items.size(); i++ ) { if (items[i].valid && (items[i].type == typeMsObject || items[i].type == typeOleObject || items[i].type == typeActiveX || items[i].type == typePDF || items[i].type == typePDF || items[i].type == typeControlProps || items[i].type == typeControl)) { int pos = items[i].outputName.rfind(L"."); std::wstring extension = pos >= 0 ? items[i].outputName.substr(pos + 1) : L""; content_types.add_or_find_default(extension); std::wstring file_name_out = RootPath + FILE_SEPARATOR_STR + items[i].outputName; if (items[i].mediaInternal && items[i].valid && (items[i].type == typeMsObject || items[i].type == typeOleObject)) { NSFile::CFileBinary::Copy(items[i].href, file_name_out); } else if (items[i].type == typePDF) { std::string name = "Acrobat Document"; std::string class_name = "Acrobat.Document.DC"; _UINT32 name_size = name.size() + 1; _UINT32 class_name_size = class_name.size() + 1; DWORD nativeDataSize = 0; BYTE* nativeData = NULL; NSFile::CFileBinary file; file.ReadAllBytes(items[i].href, &nativeData, nativeDataSize); CFCPP::CompoundFile* storageOut = new CFCPP::CompoundFile(CFCPP::Ver_3, CFCPP::Default); if (storageOut && nativeData) { _UINT32 tmp = 0; //CompObj BYTE dataCompObjHeader[28] = { 0x01, 0x00, 0xfe, 0xff, 0x03, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x65, 0xca, 0x01, 0xb8, 0xfc, 0xa1, 0xd0, 0x11, 0x85, 0xad, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 }; std::shared_ptr oStreamCompObj = storageOut->RootStorage()->AddStream(L"\001CompObj"); long long posStreamCompObj = 0; oStreamCompObj->Write((char*)dataCompObjHeader, 0, 28); posStreamCompObj += 28; oStreamCompObj->Write((char*)&name_size, posStreamCompObj, 4); posStreamCompObj += 4; oStreamCompObj->Write((char*)name.c_str(), posStreamCompObj, name_size); posStreamCompObj += name_size; tmp = 0; oStreamCompObj->Write((char*)&tmp, posStreamCompObj, 4); posStreamCompObj += 4; oStreamCompObj->Write((char*)&class_name_size, posStreamCompObj, 4); posStreamCompObj += 4; oStreamCompObj->Write((char*)class_name.c_str(), posStreamCompObj, class_name_size); posStreamCompObj += class_name_size; tmp = 0x71B239F4; oStreamCompObj->Write((char*)&tmp, posStreamCompObj, 4); posStreamCompObj += 4;// UnicodeMarker tmp = 0; oStreamCompObj->Write((char*)&tmp, posStreamCompObj, 4); posStreamCompObj += 4;// UnicodeUserType oStreamCompObj->Write((char*)&tmp, posStreamCompObj, 4); posStreamCompObj += 4;// UnicodeClipboardFormat oStreamCompObj->Write((char*)&tmp, posStreamCompObj, 4); posStreamCompObj += 4;// //Ole BYTE dataOleInfo[] = { 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; std::shared_ptr oStreamOle = storageOut->RootStorage()->AddStream(L"\001Ole"); oStreamOle->Write((char*)dataOleInfo, 0, 20); //ObjInfo std::shared_ptr oStreamObjInfo = storageOut->RootStorage()->AddStream(L"\003ObjInfo"); BYTE dataObjInfo[] = { 0x00, 0x00, 0x03, 0x00, 0x01, 0x00 }; oStreamObjInfo->Write((char*)dataObjInfo, 0, 6); //CONTENTS std::shared_ptr oStreamCONTENTS = storageOut->RootStorage()->AddStream(L"CONTENTS"); oStreamCONTENTS->Write((char*)nativeData, 0, nativeDataSize); bool result = storageOut->Save(file_name_out); storageOut->Close(); } if (storageOut) delete storageOut; //POLE::Storage* storageOut = new POLE::Storage(file_name_out.c_str()); //if ((storageOut) && (storageOut->open(true, true))) //{ // _UINT32 tmp = 0; // std::string name = class_name; // _UINT32 name_size = (_UINT32)name.length() + 1; ////Ole // BYTE dataOleInfo[] = { 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; // POLE::Stream oStream3(storageOut, L"\001Ole", true, 20); // oStream3.write(dataOleInfo, 20); // oStream3.flush(); ////CompObj // BYTE dataCompObjHeader[28] = { 0x01, 0x00, 0xfe, 0xff, 0x03, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, // 0x65, 0xca, 0x01, 0xb8, 0xfc, 0xa1, 0xd0, 0x11, 0x85, 0xad, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 }; // POLE::Stream oStream1(storageOut, L"\001CompObj", true, 28 + (class_name_size + 4) + (class_name2_size + 4) + 4 * 4); // oStream1.write(dataCompObjHeader, 28); // oStream1.write((BYTE*)&class_name_size, 4); // oStream1.write((BYTE*)class_name.c_str(), class_name_size); // tmp = 0; // oStream1.write((BYTE*)&tmp, 4); // oStream1.write((BYTE*)&class_name2_size, 4); // oStream1.write((BYTE*)class_name2.c_str(), class_name2_size); // tmp = 0x71B239F4; // oStream1.write((BYTE*)&tmp, 4); // UnicodeMarker // tmp = 0; // oStream1.write((BYTE*)&tmp, 4); // UnicodeUserType // oStream1.write((BYTE*)&tmp, 4); // UnicodeClipboardFormat // oStream1.write((BYTE*)&tmp, 4); // // oStream1.flush(); // //ObjInfo // BYTE dataObjInfo[] = { 0x00,0x00,0x03,0x00,0x0D,0x00 }; // POLE::Stream oStream2(storageOut, L"\003ObjInfo", true, 6); // oStream2.write(dataObjInfo, 6); // oStream2.flush(); // POLE::Stream streamData(storageOut, L"CONTENTS", true, nativeDataSize); // _UINT32 sz_write = 0; // _UINT32 sz = 4096; // while (sz_write < nativeDataSize) // { // if (sz_write + sz > nativeDataSize) // sz = nativeDataSize - sz_write; // streamData.write(nativeData + sz_write, sz); // sz_write += sz; // } // streamData.flush(); // storageOut->close(); // delete storageOut; //} if (nativeData) delete[]nativeData; } } } } } } }