/* * (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 "VbaReader.h" #include "StreamObjects.h" #include "../Utils/simple_xml_writer.h" #include "../../../DesktopEditor/common/File.h" #include "../../../OOXML/Base/Unit.h" CVbaReader::CVbaReader(const std::wstring & vbaFileName, const std::wstring & vbaExtractFile) { vbaExtractFile_ = vbaExtractFile; vbaProject_file_ = boost::shared_ptr(new CVbaFile(vbaFileName)); if (vbaProject_file_->isError()) return; } const std::wstring CVbaReader::convert() { _UINT32 code_page_ = 0; if (false == vbaProject_file_->isDirectory(L"VBA")) return L""; CVbaFileStreamPtr strmDir = vbaProject_file_->getNamedStream(L"VBA/dir"); VBA::DirStreamObjectPtr DirStreamObject = VBA::DirStreamObjectPtr(new VBA::DirStreamObject(strmDir)); if (false == DirStreamObject->loadContent()) return L""; code_page_ = strmDir->CodePage; //------------------------------------------------------------------------------------------ CVbaFileStreamPtr strmPROJECT = vbaProject_file_->getNamedStream(L"PROJECT"); VBA::ProjectStreamObjectPtr ProjectStreamObject = VBA::ProjectStreamObjectPtr(new VBA::ProjectStreamObject(strmPROJECT)); strmPROJECT->CodePage = code_page_; ProjectStreamObject->loadContent(); //------------------------------------------------------------------------------------------ std::wstringstream strm; CP_XML_WRITER(strm) { CP_XML_NODE(L"Information") { if (DirStreamObject->InformationRecord->NameRecord) CP_XML_ATTR(L"Name", DirStreamObject->InformationRecord->NameRecord->ProjectName.value); if (DirStreamObject->InformationRecord->LcidRecord) CP_XML_ATTR(L"Lcid", DirStreamObject->InformationRecord->LcidRecord->Lcid); if (DirStreamObject->InformationRecord->ConstantsRecord) CP_XML_ATTR(L"Constants", DirStreamObject->InformationRecord->ConstantsRecord->uConstants.value.empty() ? DirStreamObject->InformationRecord->ConstantsRecord->aConstants.value : DirStreamObject->InformationRecord->ConstantsRecord->uConstants.value); } CP_XML_NODE(L"References") { for (size_t i = 0; i < DirStreamObject->ReferencesRecord->ReferenceArray.size(); ++i) { VBA::REFERENCEPtr & reference = DirStreamObject->ReferencesRecord->ReferenceArray[i]; if (!reference) continue; CP_XML_NODE(L"Reference") { if (reference->NameRecord) CP_XML_ATTR(L"Name", reference->NameRecord->uName.value.empty() ? reference->NameRecord->aName.value : reference->NameRecord->uName.value); VBA::REFERENCEORIGINAL* original = dynamic_cast(reference->ReferenceRecord.get()); VBA::REFERENCECONTROL* control = dynamic_cast(reference->ReferenceRecord.get()); VBA::REFERENCEREGISTERED* registered = dynamic_cast(reference->ReferenceRecord.get()); VBA::REFERENCEPROJECT* project = dynamic_cast(reference->ReferenceRecord.get()); if (original) { CP_XML_NODE(L"Original") { CP_XML_ATTR(L"val", original->LibidOriginal.value); } } if (project) { CP_XML_NODE(L"Project") { if (!project->LibidAbsolute.value.empty()) CP_XML_ATTR(L"LibidAbsolute", project->LibidAbsolute.value); if (!project->LibidRelative.value.empty()) CP_XML_ATTR(L"LibidRelative", project->LibidRelative.value); } } if (control) { CP_XML_NODE(L"Control") { CP_XML_ATTR(L"TypeLib", VBA::guid2bstr(control->OriginalTypeLib)); if (!control->LibidTwiddled.value.empty()) CP_XML_ATTR(L"LibidTwiddled", control->LibidTwiddled.value); if (!control->LibidExtended.value.empty()) CP_XML_ATTR(L"LibidExtended", control->LibidExtended.value); } } if (registered) { CP_XML_NODE(L"Registered") { CP_XML_ATTR(L"val", registered->Libid.value); } } } } } CP_XML_NODE(L"Modules") { for (size_t i = 0; i < DirStreamObject->ModulesRecord->modules.size(); ++i) { VBA::MODULEPtr &module = DirStreamObject->ModulesRecord->modules[i]; if (!module) continue; CP_XML_NODE(L"Module") { if (module->StreamNameRecord) { if (module->NameUnicodeRecord) CP_XML_ATTR(L"Name", module->NameUnicodeRecord->ModuleNameUnicode.value); else if (module->NameRecord) CP_XML_ATTR(L"Name", module->NameRecord->ModuleName.value); CP_XML_ATTR(L"Type", module->bProceduralModule ? L"Procedural" : L"Class"); CP_XML_ATTR(L"ReadOnly", module->bReadOnly); CP_XML_ATTR(L"Private", module->bPrivate); std::wstring moduleName = (module->StreamNameRecord->StreamNameUnicode.value.empty() ? module->StreamNameRecord->StreamName.value : module->StreamNameRecord->StreamNameUnicode.value); std::wstring streamName = L"VBA/" + moduleName; _UINT32 offset = module->OffsetRecord ? module->OffsetRecord->TextOffset : 0xffffffff;//skip cache if (offset == 0xffffffff) continue; // error record CVbaFileStreamPtr strmModule = vbaProject_file_->getNamedStream(streamName, offset); strmModule->CodePage = code_page_; VBA::ModuleStreamObjectPtr ModuleStreamObject = VBA::ModuleStreamObjectPtr(new VBA::ModuleStreamObject(strmModule)); ModuleStreamObject->loadContent(); CP_XML_NODE(L"SourceCode") { CP_XML_STREAM() << XmlUtils::EncodeXmlString(ModuleStreamObject->SourceCode); } } } } } if (false == ProjectStreamObject->DesignerModules.empty()) { CP_XML_NODE(L"DesignerModules") { for (size_t i = 0; i < ProjectStreamObject->DesignerModules.size(); ++i) { std::wstring streamName = ProjectStreamObject->DesignerModules[i] + L"/VBFrame"; CVbaFileStreamPtr strmVBFrame = vbaProject_file_->getNamedStream(streamName); if (!strmVBFrame) { continue; } strmVBFrame->CodePage = code_page_; VBA::VBFrameObjectPtr VBFrameObject = VBA::VBFrameObjectPtr(new VBA::VBFrameObject(strmVBFrame)); VBFrameObject->loadContent(); CP_XML_NODE(L"DesignerModule") { CP_XML_ATTR(L"Name", XmlUtils::EncodeXmlString(ProjectStreamObject->DesignerModules[i])); CP_XML_NODE(L"Properties") { for (size_t j = 0; j < VBFrameObject->Props.size(); ++j) { CP_XML_ATTR(VBFrameObject->Props[j].first.c_str(), XmlUtils::EncodeXmlString(VBFrameObject->Props[j].second)); } } CP_XML_STREAM() << convertObject(ProjectStreamObject->DesignerModules[i], code_page_); } } } } } return strm.str(); } std::wstring CVbaReader::convertObject(const std::wstring & name, unsigned int code_page) { VBA::FormControlStreamPtr FormControlStream; std::wstring streamName; streamName = name + L"/f"; CVbaFileStreamPtr strmForm = vbaProject_file_->getNamedStream(streamName); if (strmForm) { strmForm->CodePage = code_page; FormControlStream = VBA::FormControlStreamPtr(new VBA::FormControlStream(strmForm)); FormControlStream->loadContent(); } streamName = name + L"/o"; CVbaFileStreamPtr strmObject = vbaProject_file_->getNamedStream(streamName); _UINT32 nextStreamPositionEmbedded = 0; if (strmObject) { strmObject->CodePage = code_page; } std::wstringstream strm; CP_XML_WRITER(strm) { CP_XML_NODE(L"FormControl") { if (FormControlStream) { if (FormControlStream->Control) { CP_XML_NODE(L"Data") { CP_XML_ATTR_STR(L"Caption", FormControlStream->Control->Caption); CP_XML_ATTR_OPT(L"BackColor", FormControlStream->Control->BackColor); CP_XML_ATTR_OPT(L"ForeColor", FormControlStream->Control->ForeColor); CP_XML_ATTR_OPT(L"NextAvailableID", FormControlStream->Control->NextAvailableID); CP_XML_ATTR_OPT(L"BorderStyle", FormControlStream->Control->BorderStyle); CP_XML_ATTR_OPT(L"MousePointer", FormControlStream->Control->MousePointer); CP_XML_ATTR_OPT(L"ScrollBars", FormControlStream->Control->ScrollBars); CP_XML_ATTR_OPT(L"GroupCnt", FormControlStream->Control->GroupCnt); CP_XML_ATTR_OPT(L"Cycle", FormControlStream->Control->Cycle); CP_XML_ATTR_OPT(L"SpecialEffect", FormControlStream->Control->SpecialEffect); CP_XML_ATTR_OPT(L"BorderColor", FormControlStream->Control->BorderColor); CP_XML_ATTR_OPT(L"Zoom", FormControlStream->Control->Zoom); CP_XML_ATTR_OPT(L"PictureAlignment", FormControlStream->Control->PictureAlignment); CP_XML_ATTR_OPT(L"PictureSizeMode", FormControlStream->Control->PictureSizeMode); CP_XML_ATTR_OPT(L"ShapeCookie", FormControlStream->Control->ShapeCookie); CP_XML_ATTR_OPT(L"DrawBuffer", FormControlStream->Control->DrawBuffer); if (FormControlStream->Control->DisplayedSize) { CP_XML_NODE(L"DisplayedSize") { CP_XML_ATTR(L"Width", FormControlStream->Control->DisplayedSize->Width); CP_XML_ATTR(L"Height", FormControlStream->Control->DisplayedSize->Height); } } if (FormControlStream->Control->LogicalSize) { CP_XML_NODE(L"LogicalSize") { CP_XML_ATTR(L"Width", FormControlStream->Control->LogicalSize->Width); CP_XML_ATTR(L"Height", FormControlStream->Control->LogicalSize->Height); } } if (FormControlStream->Control->ScrollPosition) { CP_XML_NODE(L"ScrollPosition") { CP_XML_ATTR(L"Left", FormControlStream->Control->ScrollPosition->Left); CP_XML_ATTR(L"Top", FormControlStream->Control->ScrollPosition->Top); } } if (FormControlStream->Control->Font) { CP_XML_NODE(L"Font") { VBA::StdFont* stdFont = dynamic_cast(FormControlStream->Control->Font.get()); if (stdFont) { CP_XML_ATTR_STR(L"Name", stdFont->sFontName); CP_XML_ATTR_OPT(L"Height", stdFont->FontHeight); CP_XML_ATTR_OPT(L"Weight", stdFont->FontWeight); CP_XML_ATTR_OPT(L"CharSet", stdFont->FontCharSet); CP_XML_ATTR_OPT(L"PitchAndFamily", stdFont->FontPitchAndFamily); CP_XML_ATTR_OPT(L"ParagraphAlign", stdFont->ParagraphAlign); CP_XML_ATTR_OPT(L"Bold", stdFont->bFontBold); CP_XML_ATTR_OPT(L"Italic", stdFont->bFontItalic); CP_XML_ATTR_OPT(L"Underline", stdFont->bFontUnderline); CP_XML_ATTR_OPT(L"Strikeout", stdFont->bFontStrikeout); CP_XML_ATTR_OPT(L"AutoColor", stdFont->bFontAutoColor); } } } } } if (FormControlStream->DesignExData) { } if (FormControlStream->SiteData) { CP_XML_NODE(L"Sites") { for (size_t i = 0; i < FormControlStream->SiteData->Sites.size(); ++i) { VBA::OleSiteConcreteControlPtr& site = FormControlStream->SiteData->Sites[i]; if (!site) continue; if (strmObject) { site->Object = VBA::ActiveXObjectPtr(OOX::ActiveXObject::Create(site->ClsidCacheIndex ? *site->ClsidCacheIndex : 0)); if (strmObject->getDataSize() > nextStreamPositionEmbedded && site->ObjectStreamSize) { site->Object->Parse(strmObject->getData() + nextStreamPositionEmbedded, *site->ObjectStreamSize); nextStreamPositionEmbedded += *site->ObjectStreamSize; } } CP_XML_NODE(L"Site") { CP_XML_ATTR_OPT(L"ID", site->ID); CP_XML_ATTR_OPT(L"HelpContextID", site->HelpContextID); CP_XML_ATTR_OPT(L"TabIndex", site->TabIndex); CP_XML_ATTR_OPT(L"ClsidCacheIndex", site->ClsidCacheIndex); //CP_XML_ATTR_OPT(L"ObjectStreamSize", site->ObjectStreamSize); CP_XML_ATTR_OPT(L"GroupID", site->GroupID); if (site->BitFlags) { CP_XML_ATTR(L"fTabStop", site->BitFlags->fTabStop); CP_XML_ATTR(L"fVisible", site->BitFlags->fVisible); CP_XML_ATTR(L"fDefault", site->BitFlags->fDefault); CP_XML_ATTR(L"fCancel", site->BitFlags->fCancel); CP_XML_ATTR(L"fAutoSize", site->BitFlags->fAutoSize); CP_XML_ATTR(L"fPreserveHeight", site->BitFlags->fPreserveHeight); CP_XML_ATTR(L"fFitToParent", site->BitFlags->fFitToParent); CP_XML_ATTR(L"fSelectChild", site->BitFlags->fSelectChild); } CP_XML_ATTR_STR(L"Name", site->Name); CP_XML_ATTR_STR(L"Tag", site->Tag); CP_XML_ATTR_STR(L"ControlTipText", site->ControlTipText); CP_XML_ATTR_STR(L"RuntimeLicKey", site->RuntimeLicKey); CP_XML_ATTR_STR(L"ControlSource", site->ControlSource); CP_XML_ATTR_STR(L"RowSource", site->RowSource); if (site->SitePosition) { CP_XML_NODE(L"SitePosition") { CP_XML_ATTR(L"Left", site->SitePosition->Left); CP_XML_ATTR(L"Top", site->SitePosition->Top); } } if (site->Object) { CP_XML_NODE(L"EmbeddedObject") { CP_XML_STREAM() << site->Object->toXml(); } } if ((site->BitFlags) && (site->BitFlags->fPromoteControls) && (site->ID)) { //read child objects std::wstring name_child = name + L"/i" + (*site->ID < 10 ? L"0" : L"") + std::to_wstring(*site->ID); CP_XML_STREAM() << convertObject(name_child, code_page); } } } } } } } } return strm.str(); } bool CVbaReader::write() { const std::wstring sXml = convert(); NSFile::CFileBinary file; if (file.CreateFileW(vbaExtractFile_)) { std::string root = ""; file.WriteFile((BYTE*)root.c_str(), (DWORD)root.length()); file.WriteStringUTF8(sXml); file.CloseFile(); return true; } return false; } CVbaReader::~CVbaReader() { //if (vba_context) delete vba_context; //if (output_document) delete output_document; }