/* * (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 "IFileContainer.h" #include "Rels.h" #include "FileFactory.h" #include "ContentTypes.h" #include "FileType.h" #include "FileTypes.h" #include "External/External.h" #include "External/HyperLink.h" #include "Media/Image.h" #include "Media/OleObject.h" #include "Media/ActiveX.h" #include "../PPTXFormat/LegacyDiagramText.h" #include "../XlsxFormat/FileFactory_Spreadsheet.h" #include "../VsdxFormat/FileFactory_Draw.h" namespace OOX { boost::unordered_map IFileContainer::m_mapEnumeratedGlobal; UnknowTypeFile IFileContainer::m_oUnknown(NULL); IFileContainer::IFileContainer(OOX::Document* pMain) : m_pMainDocument(pMain) { m_bVisioPages = false; m_bSpreadsheets = false; m_lMaxRid = 0; } IFileContainer::~IFileContainer() { } void IFileContainer::Read (const OOX::CPath& oRootPath, const OOX::CPath& oPath) { // Находим связи(рельсы) с данным файлом m_pCurRels = new OOX::CRels(oPath); if (m_pMainDocument) { smart_ptr pFile = dynamic_cast(this); pFile.AddRef(); m_pMainDocument->m_mapContent.insert(std::make_pair(oPath.GetPath(), pFile)); } // Читаем все файлы по рельсам Read( *m_pCurRels, oRootPath, oPath.GetDirectory() ); } void IFileContainer::Read (const OOX::CRels& oRels, const OOX::CPath& oRootPath, const OOX::CPath& oPath) { for (size_t i = 0; i < oRels.m_arRelations.size(); ++i) { if (!oRels.m_arRelations[i]) continue; std::wstring pathFile = oRels.m_arRelations[i]->IsExternal() ? oRels.m_arRelations[i]->Target().GetPath() : (oPath / oRels.m_arRelations[i]->Target()).GetPath(); if (m_pMainDocument) { std::map>::iterator pFind = m_pMainDocument->m_mapContent.find(pathFile); if (pFind != m_pMainDocument->m_mapContent.end()) { Add(oRels.m_arRelations[i]->rId(), pFind->second); continue; } } smart_ptr pFile; if (m_bSpreadsheets) pFile = OOX::Spreadsheet::CreateFile(oRootPath, oPath, oRels.m_arRelations[i], m_pMainDocument); if (m_bVisioPages) pFile = OOX::Draw::CreateFile(oRootPath, oPath, oRels.m_arRelations[i], m_pMainDocument); if (pFile.IsInit() == false || pFile->type() == FileTypes::Unknown) pFile = OOX::CreateFile(oRootPath, oPath, oRels.m_arRelations[i], m_pMainDocument); if (oRels.m_arRelations[i]->IsExternal()) { smart_ptr pMedia = pFile.smart_dynamic_cast(); if (pMedia.IsInit()) pMedia->set_filename(oRels.m_arRelations[i]->Target().GetPath(), true); } Add(oRels.m_arRelations[i]->rId(), pFile); } } void IFileContainer::Write(const OOX::CPath& oFileName, const OOX::CPath& oDirectory, OOX::CContentTypes& oContent) const { OOX::CPath oCurrent = oFileName.GetDirectory(); OOX::CRels oRels; Write( oRels, oCurrent, oDirectory, oContent ); oRels.Write( oFileName ); } void IFileContainer::Write(OOX::CRels& oRels, const OOX::CPath& oCurrent, const OOX::CPath& oDir, OOX::CContentTypes& oContent) const { const OOX::File* pFileOwner = dynamic_cast(this); for (std::map>::const_iterator pPair = m_mapContainer.begin(); pPair != m_mapContainer.end(); ++pPair) { smart_ptr pFile = pPair->second; smart_ptr pExt = pFile.smart_dynamic_cast(); smart_ptr pMedia = pFile.smart_dynamic_cast(); bool bExternal = pExt.IsInit() || ((pMedia.IsInit()) && (pMedia->IsExternal())); if ( !bExternal ) { OOX::CPath oDefDir = pFile->DefaultDirectory(); OOX::CPath oName = pFile->DefaultFileName(); if (pFile->type() == OOX::Spreadsheet::FileTypes::PivotCacheDefinition && pFileOwner->type() == OOX::Spreadsheet::FileTypes::PivotTable) { oDefDir = L"../" + oDefDir; } if (false == pFile->m_sOutputFilename.empty()) oName.SetName(pFile->m_sOutputFilename, false); boost::unordered_map::const_iterator itFind = m_mNoWriteContainer.find(pPair->first); if(m_mNoWriteContainer.end() == itFind) { OOX::CSystemUtility::CreateDirectories( oCurrent / oDefDir ); pFile->write( oCurrent / oDefDir / oName, oDir / oDefDir, oContent ); } else if(itFind->second.length() > 0) { oDefDir = itFind->second; } if(true != pFile->m_bDoNotAddRels) { if (oDefDir.GetPath().length() > 0)//todooo перенести в CPath oRels.Registration( pPair->first, pFile->type(), oDefDir / oName ); else oRels.Registration( pPair->first, pFile->type(), oName ); } } else { if (pExt.IsInit()) { oRels.Registration( pPair->first, pExt ); } else if ((pMedia.IsInit()) && (pMedia->IsExternal())) { oRels.Registration( pPair->first, pMedia->type(), pMedia->filename().GetPath(), true); } } } } void IFileContainer::Commit (const OOX::CPath& oPath) { std::map mNamepair; for (size_t i = 0; i < m_arContainer.size(); ++i) { smart_ptr &pFile = m_arContainer[i]; smart_ptr pExt = pFile.smart_dynamic_cast(); smart_ptr pMedia = pFile.smart_dynamic_cast(); bool bExternal = pExt.IsInit() || ((pMedia.IsInit()) && (pMedia->IsExternal())); if ( !bExternal ) if (!pExt.IsInit()) { OOX::CPath oDefDir = pFile->DefaultDirectory(); OOX::CPath oName = pFile->DefaultFileName(); std::map::const_iterator pNamePair = mNamepair.find( oName.m_strFilename ); if (pNamePair == mNamepair.end()) mNamepair [oName.m_strFilename] = 1; else oName = oName + pNamePair->first; OOX::CSystemUtility::CreateDirectories( oPath / oDefDir ); smart_ptr pFileBuilder = pFile.smart_dynamic_cast(); if ( pFileBuilder.is_init() ) pFileBuilder->Commit( oPath / oDefDir / oName ); } } } void IFileContainer::Finalize(const OOX::CPath& oFileName, const OOX::CPath& oDirectory, OOX::CContentTypes& oContent) { OOX::CPath oCurrent = oFileName.GetDirectory(); OOX::CRels oRels; Finalize( oRels, oCurrent, oDirectory, oContent ); oRels.Write( oFileName ); } void IFileContainer::Finalize(OOX::CRels& oRels, const OOX::CPath& oCurrent, const OOX::CPath& oDir, OOX::CContentTypes& oContent) { std::map mNamepair; for (std::map>::const_iterator pPair = m_mapContainer.begin(); pPair != m_mapContainer.end(); ++pPair) { smart_ptr pFile = pPair->second; smart_ptr pExt = pFile.smart_dynamic_cast(); smart_ptr pMedia = pFile.smart_dynamic_cast(); bool bExternal = pExt.IsInit() || ((pMedia.IsInit()) && (pMedia->IsExternal())); if ( !bExternal ) { OOX::CPath oDefDir = pFile->DefaultDirectory(); OOX::CPath oName = pFile->DefaultFileName(); std::map::iterator pNamePair = mNamepair.find( oName.m_strFilename ); if ( pNamePair == mNamepair.end() ) mNamepair [oName.m_strFilename] = 1; else oName = oName + pNamePair->first; boost::unordered_map::const_iterator itFind = m_mNoWriteContainer.find(pPair->first); if(m_mNoWriteContainer.end() == itFind) { OOX::CSystemUtility::CreateDirectories( oCurrent / oDefDir ); smart_ptr pFileBuilder = pFile.smart_dynamic_cast(); if ( pFileBuilder.is_init() ) { pFileBuilder->Finalize( oCurrent / oDefDir / oName, oDir / oDefDir, oContent ); } else { pFile->write( oCurrent / oDefDir / oName, oDir / oDefDir, oContent ); } } else if(itFind->second.length() > 0) { oDefDir = itFind->second; } oRels.Registration( pPair->first, pFile->type(), oDefDir / oName ); } else { oRels.Registration( pPair->first, pExt ); } } } const bool IFileContainer::IsExist(const RId& rId) const { std::map>::const_iterator pFind = m_mapContainer.find(rId.get()); return (pFind != m_mapContainer.end()); } template const bool IFileContainer::IsExist() const { T oFile; return IsExist( oFile.type() ); } std::wstring IFileContainer::IsExistHyperlink(const std::wstring & href) { boost::unordered_map::const_iterator pFind = m_mapHyperlinks.find(href); if (pFind != m_mapHyperlinks.end()) { return pFind->second; } return std::wstring(); } const bool IFileContainer::IsExternal(const OOX::RId& rId) const { std::map>::const_iterator pFind = m_mapContainer.find(rId.get()); if (pFind != m_mapContainer.end()) { smart_ptr mediaFile = pFind->second.smart_dynamic_cast(); if (mediaFile.IsInit()) { return mediaFile->IsExternal(); } else { return false; } } return true; } const RId IFileContainer::Add(smart_ptr& pFile) { const RId rId = GetMaxRId().next(); Add( rId, pFile ); return rId; } void IFileContainer::AssignOutputFilename(smart_ptr& pFile) { bool bEnumerated = pFile->type().Enumerated(); bool bEnumeratedGlobal = pFile->type().EnumeratedGlobal(); if((true == bEnumeratedGlobal || true == bEnumerated) && pFile->m_sOutputFilename.empty()) { int nIndex = 0; if(true == bEnumeratedGlobal) { boost::unordered_map::const_iterator pNamePair = m_mapEnumeratedGlobal.find (pFile->type().EnumerateType()); if (pNamePair != m_mapEnumeratedGlobal.end()) nIndex = pNamePair->second; } else { boost::unordered_map::const_iterator pNamePair = m_mapAddNamePair.find (pFile->type().EnumerateType()); if (pNamePair != m_mapAddNamePair.end()) nIndex = pNamePair->second; } nIndex++; if(true == bEnumeratedGlobal) { if(pFile.is()) { OOX::FileGlobalEnumerated& oFileGlobalEnumerated = pFile.as(); oFileGlobalEnumerated.SetGlobalNumber(nIndex); } } std::wstring sPath = pFile->DefaultFileName().GetPath(); size_t nDotIndex = sPath.rfind('.'); if(std::wstring::npos != nDotIndex && nDotIndex > 0) { std::wstring sDigit = std::to_wstring( nIndex); sPath.insert(sPath.begin() + nDotIndex, sDigit.begin(), sDigit.end()); } pFile->m_sOutputFilename = sPath; if(true == bEnumeratedGlobal) m_mapEnumeratedGlobal [pFile->type().EnumerateType()] = nIndex; else m_mapAddNamePair [pFile->type().EnumerateType()] = nIndex; } } void IFileContainer::Add (const OOX::RId& rId, smart_ptr& pFile) { AssignOutputFilename(pFile); m_lMaxRid = (std::max)( m_lMaxRid, rId.getNumber() ); m_arContainer.push_back(pFile); m_mapContainer [rId.get()] = pFile; smart_ptr oHyperlinkFile = pFile.smart_dynamic_cast(); if (oHyperlinkFile.IsInit()) { m_mapHyperlinks.insert(std::make_pair( oHyperlinkFile->Uri().GetPath(), rId.get() )); } } const RId IFileContainer::AddNoWrite(const smart_ptr& pFile, const std::wstring& oDefDir) { const RId rId = GetMaxRId().next(); AddNoWrite( rId, pFile, oDefDir ); return rId; } void IFileContainer::AddNoWrite (const OOX::RId& rId, const smart_ptr& pFile, const std::wstring& oDefDir) { m_lMaxRid = (std::max)( m_lMaxRid, rId.getNumber() ); m_arContainer.push_back(pFile); m_mapContainer [rId.get()] = pFile; m_mNoWriteContainer[rId.get()] = oDefDir; } smart_ptr IFileContainer::Find(const OOX::RId& rId) const { std::map>::const_iterator pPair = m_mapContainer.find(rId.get()); if ( pPair != m_mapContainer.end()) return pPair->second; return smart_ptr( (OOX::File*)new UnknowTypeFile(m_pMainDocument) ); } smart_ptr IFileContainer::Find(const FileType& oType) const { for (std::map>::const_iterator pPair = m_mapContainer.begin(); pPair != m_mapContainer.end(); ++pPair) { if (pPair->second->type() == oType) return pPair->second; } return smart_ptr( (OOX::File*)new UnknowTypeFile(m_pMainDocument) ); } template T& IFileContainer::Find() { T oFile; return dynamic_cast( Find( oFile.type() ) ); } smart_ptr IFileContainer::operator [](const OOX::RId rId) { std::map>::const_iterator pFind = m_mapContainer.find(rId.get()); if ( pFind != m_mapContainer.end()) return pFind->second; return smart_ptr( (OOX::File*)new UnknowTypeFile(m_pMainDocument) ); } smart_ptr IFileContainer::operator [](const FileType& oType) { return Find(oType); } const RId IFileContainer::GetMaxRId() { return RId( m_lMaxRid ); } void IFileContainer::SetGlobalNumberByType(const std::wstring& sOverrideType, int val) { m_mapEnumeratedGlobal [sOverrideType] = val; } int IFileContainer::GetGlobalNumberByType(const std::wstring& sOverrideType) { boost::unordered_map::const_iterator pNamePair = m_mapEnumeratedGlobal.find( sOverrideType ); int nRes = 0; if(pNamePair != m_mapEnumeratedGlobal.end()) nRes = pNamePair->second; return nRes; } } // namespace OOX