#include "Converter2OOXML.h" #include #include "../../../DesktopEditor/common/File.h" #include "../../../DesktopEditor/common/Directory.h" #include "../../../DesktopEditor/common/SystemUtils.h" #include "../../../OfficeUtils/src/OfficeUtils.h" #include "../../../DesktopEditor/graphics/pro/Image.h" #include "../Paragraph/ParaText.h" #include "../Paragraph/CtrlTable.h" #include "../Paragraph/CtrlEqEdit.h" #include "../Paragraph/CtrlShapeArc.h" #include "../Paragraph/CtrlShapePolygon.h" #include "../Paragraph/CtrlShapeCurve.h" #include "../Paragraph/CtrlShapeLine.h" #include "../Paragraph/CtrlShapeRect.h" #include "../HWPElements/HWPRecordParaShape.h" #include "../HWPElements/HWPRecordCharShape.h" #include "Transform.h" #define PARA_SPACING_SCALE 0.85 namespace HWP { enum class EShapeObjectType { Arc, Curve, Ellipse, Line, Ole, Picture, Polygon, Rectangle, Unknown }; EShapeObjectType GetShapeObjectType(const std::wstring& wsID) { if (L"cra$" == wsID) return EShapeObjectType::Arc; if (L"ruc$" == wsID) return EShapeObjectType::Curve; if (L"lle$" == wsID) return EShapeObjectType::Ellipse; if (L"nil$" == wsID || L"loc$" == wsID) return EShapeObjectType::Line; if (L"elo$" == wsID) return EShapeObjectType::Ole; if (L"cip$" == wsID) return EShapeObjectType::Picture; if (L"lop$" == wsID) return EShapeObjectType::Polygon; if (L"cer$" == wsID) return EShapeObjectType::Rectangle; return EShapeObjectType::Unknown; } CConverter2OOXML::CConverter2OOXML() : m_pContext(nullptr), m_ushShapeCount(0), m_ushPageCount(1), m_ushTableCount(0), m_ushEquationCount(0), m_ushBookmarkCount(0) {} CConverter2OOXML::~CConverter2OOXML() {} void CConverter2OOXML::SetContext(CWriterContext* pContext) { m_pContext = pContext; } void CConverter2OOXML::SetTempDirectory(const HWP_STRING& sTempDirectory) { m_sTempDirectory = sTempDirectory; m_oOleConverter.SetTempDir(m_sTempDirectory); } void CConverter2OOXML::CreateEmptyFiles() { NSDirectory::CreateDirectory(m_sTempDirectory + L"/_rels"); NSDirectory::CreateDirectory(m_sTempDirectory + L"/docProps"); NSDirectory::CreateDirectory(m_sTempDirectory + L"/word"); NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/_rels"); NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/media"); NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/theme"); // theme1.xml std::wstring wsTheme = L""; NSFile::CFileBinary oThemeWriter; if (oThemeWriter.CreateFileW(m_sTempDirectory + L"/word/theme/theme1.xml")) { oThemeWriter.WriteStringUTF8(wsTheme); oThemeWriter.CloseFile(); } // app.xml std::wstring wsApplication = NSSystemUtils::GetEnvVariable(NSSystemUtils::gc_EnvApplicationName); if (wsApplication.empty()) wsApplication = NSSystemUtils::gc_EnvApplicationNameDefault; std::wstring wsApp = L""; wsApp += wsApplication; wsApp += L"0falsefalsefalsefalse"; NSFile::CFileBinary oAppWriter; if (oAppWriter.CreateFileW(m_sTempDirectory + L"/docProps/app.xml")) { oAppWriter.WriteStringUTF8(wsApp); oAppWriter.CloseFile(); } // .rels std::wstring wsRels = L""; NSFile::CFileBinary oRelsWriter; if (oRelsWriter.CreateFileW(m_sTempDirectory + L"/_rels/.rels")) { oRelsWriter.WriteStringUTF8(wsRels); oRelsWriter.CloseFile(); } // fontTable.xml std::wstring wsFontTable = L""; NSFile::CFileBinary oFontTableWriter; if (oFontTableWriter.CreateFileW(m_sTempDirectory + L"/word/fontTable.xml")) { oFontTableWriter.WriteStringUTF8(wsFontTable); oFontTableWriter.CloseFile(); } // settings.xml std::wstring wsSettings = L""; NSFile::CFileBinary oSettingsWriter; if (oSettingsWriter.CreateFileW(m_sTempDirectory + L"/word/settings.xml")) { oSettingsWriter.WriteStringUTF8(wsSettings); oSettingsWriter.CloseFile(); } // core.xml std::wstring wsCore = L""; wsCore += L""; NSFile::CFileBinary oCoreWriter; if (oCoreWriter.CreateFileW(m_sTempDirectory + L"/docProps/core.xml")) { oCoreWriter.WriteStringUTF8(wsCore); oCoreWriter.CloseFile(); } FillDefaultData(); } void CConverter2OOXML::FillDefaultData() { // Заполняем начало файлов AddRelationship(L"styles", L"styles.xml"); AddRelationship(L"settings", L"settings.xml"); AddRelationship(L"webSettings", L"webSettings.xml"); AddRelationship(L"fontTable", L"fontTable.xml"); AddRelationship(L"theme", L"theme/theme1.xml"); AddContentType(L"document.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"); AddContentType(L"styles.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"); AddContentType(L"settings.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"); AddContentType(L"webSettings.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml"); AddContentType(L"fontTable.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"); AddContentType(L"theme/theme1.xml", L"application/vnd.openxmlformats-officedocument.theme+xml"); m_oNoteXmlRels.WriteString(L""); m_oDocXml .WriteString(L""); m_oWebSettings.WriteString(L""); } void CConverter2OOXML::Close() { // Дописываем концы файлов m_oDocXml.WriteString(L""); NSFile::CFileBinary oDocumentWriter; if (oDocumentWriter.CreateFileW(m_sTempDirectory + L"/word/document.xml")) { oDocumentWriter.WriteStringUTF8(m_oDocXml.GetData()); oDocumentWriter.CloseFile(); } if (m_oFootnoteConverter.SaveToFile(m_sTempDirectory + FILE_SEPARATOR_STR + L"word" + FILE_SEPARATOR_STR)) { AddRelationship(L"footnotes", L"footnotes.xml"); AddRelationship(L"endnotes", L"endnotes.xml"); AddContentType(L"footnotes.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml"); AddContentType(L"endnotes.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml"); } // styles.xml m_oStyleConverter.SaveToFile(m_sTempDirectory + FILE_SEPARATOR_STR + L"word" + FILE_SEPARATOR_STR); // numbering.xml if (m_oNumberingConverter.SaveToFile(m_sTempDirectory + FILE_SEPARATOR_STR + L"word" + FILE_SEPARATOR_STR)) { AddRelationship(L"numbering", L"numbering.xml"); AddContentType(L"numbering.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"); } // webSettings.xml m_oWebSettings.WriteString(L""); NSFile::CFileBinary oWebSettingsWriter; if (oWebSettingsWriter.CreateFileW(m_sTempDirectory + L"/word/webSettings.xml")) { oWebSettingsWriter.WriteStringUTF8(m_oWebSettings.GetData()); oWebSettingsWriter.CloseFile(); } // [Content_Types].xml NSFile::CFileBinary oContentTypeWriter; if (oContentTypeWriter.CreateFileW(m_sTempDirectory + L"/[Content_Types].xml")) { oContentTypeWriter.WriteStringUTF8(L""); oContentTypeWriter.WriteStringUTF8(L""); for (const TContentType& oContentType : m_arDefaultContentType) oContentTypeWriter.WriteStringUTF8(L""); for (const TContentType& oContentType : m_arContentTypes) oContentTypeWriter.WriteStringUTF8(L""); oContentTypeWriter.WriteStringUTF8(L""); oContentTypeWriter.WriteStringUTF8(L""); oContentTypeWriter.WriteStringUTF8(L""); oContentTypeWriter.CloseFile(); } NSFile::CFileBinary oRelsWriter; if (oRelsWriter.CreateFileW(m_sTempDirectory + L"/word/_rels/document.xml.rels")) { oRelsWriter.WriteStringUTF8(L""); for (const TRelationship& oRelationship : m_arRelationships) { oRelsWriter.WriteStringUTF8(L""); else oRelsWriter.WriteStringUTF8(L"/>"); } oRelsWriter.WriteStringUTF8(L""); oRelsWriter.CloseFile(); } } void CConverter2OOXML::Convert() { if (nullptr == m_pContext) return; TConversionState oState; std::vector arSetcions{m_pContext->GetSections()}; for (const CHWPSection* pSection : arSetcions) { const bool bIsLastSection = pSection == arSetcions.back(); for (const CHWPPargraph *pPara : pSection->GetParagraphs()) WriteParagraph(pPara, m_oDocXml, oState); if (!bIsLastSection) m_oDocXml.WriteString(L""); WriteSectionSettings(oState); if (!bIsLastSection) m_oDocXml.WriteString(L""); ++oState.m_ushSecdIndex; oState.m_oLastNode.Clear(); } } bool CConverter2OOXML::IsRasterFormat(const HWP_STRING& sFormat) { return L"png" == sFormat || L"jpg" == sFormat || L"jpeg" == sFormat || L"bmp" == sFormat; } void CConverter2OOXML::WriteCharacter(const CCtrlCharacter* pCharacter, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pCharacter) return; switch (pCharacter->GetType()) { case ECtrlCharType::PARAGRAPH_BREAK: { // Таблицы пишутся без тега , поэтому для них не открывается параграф if (TConversionState::TLastNode::ELastNodeType::Table == oState.m_oLastNode.m_eType && oState.m_unParaIndex == oState.m_oLastNode.m_unParaIndex && !oState.m_bInTable) { oState.m_oLastNode.m_eType = TConversionState::TLastNode::ELastNodeType::Table; break; } if (!oState.m_bOpenedP) WriteEmptyParagraph(shParaShapeID, shParaStyleID, pCharacter->GetCharShapeId(), oBuilder, oState); else CloseParagraph(oBuilder, oState); break; } case ECtrlCharType::LINE_BREAK: { oState.m_eBreakType = TConversionState::EBreakType::TextWrapping; break; } case ECtrlCharType::TABULATION: { OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L""); break; } case ECtrlCharType::HARD_HYPHEN: case ECtrlCharType::HARD_SPACE: break; } } void CConverter2OOXML::WriteShape(const CCtrlGeneralShape* pShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const CCtrlContainer *pContainer) { if (nullptr == pShape || oState.m_bInTextBox) return; switch (pShape->GetShapeType()) { case EShapeType::Arc: case EShapeType::Ellipse: case EShapeType::Rect: case EShapeType::Line: case EShapeType::Polygon: case EShapeType::Curve: { WriteGeometryShape(pShape, shParaShapeID, shParaStyleID, oBuilder, oState, pContainer); break; } case EShapeType::Pic: { WritePicture((const CCtrlShapePic*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState); break; } case EShapeType::EqEdit: { WriteEqEditShape((const CCtrlEqEdit*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState); break; } case EShapeType::Ole: { WriteOleShape((const CCtrlShapeOle*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState); break; } case EShapeType::Video: { WriteVideo((const CCtrlShapeVideo*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState); break; } case EShapeType::Container: { WriteContainer((const CCtrlContainer*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState); break; } case EShapeType::GeneralShape: case EShapeType::ConnectLine: case EShapeType::TextArt: break; } } void CConverter2OOXML::WriteNote(const CCtrlNote* pNote, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pNote) return; oBuilder.WriteString(L""); CRunnerStyle oRunnerStyle; oRunnerStyle.SetVerticalAlign(EVerticalAlignRun::Superscript); WriteRunnerStyle(oState.m_ushLastCharShapeId, oBuilder, oState, oRunnerStyle); oBuilder.WriteString(m_oFootnoteConverter.CreateNote((const CCtrlNote*)pNote, *this)); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteField(const CCtrlField* pShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pShape) return; switch (pShape->GetType()) { case EFieldType::Hyperlink: { HWP_STRING wsHref = pShape->GetStringParam(L"Path"); if(wsHref.empty()) { HWP_STRING sCommand = pShape->GetStringParam(L"Command"); if (sCommand.empty()) sCommand = pShape->GetCommand(); sCommand = sCommand.substr(0, sCommand.find(L';')); size_t unFound = sCommand.find(L'\\'); while (HWP_STRING::npos != unFound) { sCommand.erase(unFound, 1); unFound = sCommand.find(L'\\', unFound); } wsHref = sCommand; } if (wsHref.empty()) break; const HWP_STRING wsID = AddRelationship(L"hyperlink", wsHref, &oState); OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L""); oState.m_mOpenField.insert(std::make_pair(pShape->GetInstanceID(), pShape)); break; } case EFieldType::HyperlinkClosing: { oBuilder.WriteString(L""); break; } case EFieldType::Bookmark: { oBuilder.WriteString(L"GetStringParam(L"bookmarkname")); oBuilder.WriteString(L"\"/>"); oState.m_arOpenedBookmarks.push(m_ushBookmarkCount++); oState.m_mOpenField.insert(std::make_pair(pShape->GetInstanceID(), pShape)); break; } case EFieldType::BookmarkClosing: { if (oState.m_arOpenedBookmarks.empty()) break; oBuilder.WriteString(L""); oState.m_arOpenedBookmarks.pop(); break; } //TODO:: как-будто хочется определить тип закрывающей field на этапе парса hwpx case EFieldType::Unknown: { std::map::const_iterator itFound = oState.m_mOpenField.find(pShape->GetInstanceID()); if (oState.m_mOpenField.cend() != itFound) { switch (itFound->second->GetType()) { case EFieldType::Hyperlink: { oBuilder.WriteString(L""); break; } case EFieldType::Bookmark: { if (oState.m_arOpenedBookmarks.empty()) break; oBuilder.WriteString(L""); oState.m_arOpenedBookmarks.pop(); break; } default: break; } } break; } } } void CConverter2OOXML::WriteCaption(const CCtrlCommon* pCtrlCommon, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pCtrlCommon || !pCtrlCommon->HaveCaption()) return; for (const CCapParagraph* pCapParagraph : pCtrlCommon->GetCaptionParas()) WriteParagraph(pCapParagraph, oBuilder, oState); } void CConverter2OOXML::WriteEmptyParagraph(short shParaShapeID, short shParaStyleID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (oState.m_bOpenedP) return; oBuilder.WriteString(L""); oBuilder.WriteString(L""); WriteParaShapeProperties(shParaShapeID, shParaStyleID, oBuilder, oState); WriteRunnerStyle(shCharShapeID, oBuilder, oState); oBuilder.WriteString(L""); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteParagraph(const CHWPPargraph* pParagraph, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pParagraph) return; CloseParagraph(oBuilder, oState); if (0 < pParagraph->GetBreakType()) { if ((0x04 == (pParagraph->GetBreakType() & 0x04)) && (0 < oState.m_unParaIndex)) { oState.m_eBreakType = TConversionState::EBreakType::Page; // oBuilder.WriteString(L""); ++m_ushPageCount; } else if (0x08 == (pParagraph->GetBreakType() & 0x08)) oState.m_eBreakType = TConversionState::EBreakType::Column; // oBuilder.WriteString(L""); } ++oState.m_unParaIndex; for (const CCtrl* pCtrl : pParagraph->GetCtrls()) { switch (pCtrl->GetCtrlType()) { case ECtrlObjectType::ParaText: { WriteText((const CParaText*)pCtrl, pParagraph->GetRangeTags(), pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState); break; } case ECtrlObjectType::Character: { WriteCharacter((const CCtrlCharacter*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState); break; } case ECtrlObjectType::Shape: { WriteShape((const CCtrlGeneralShape*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState); break; } case ECtrlObjectType::Table: { WriteTable((const CCtrlTable*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState); break; } case ECtrlObjectType::Note: { WriteNote((const CCtrlNote*)pCtrl, pParagraph->GetShapeID(), oBuilder, oState); break; } case ECtrlObjectType::SectionDef: { oState.m_pSectionDef = (const CCtrlSectionDef*)pCtrl; break; } case ECtrlObjectType::ColumnDef: { oState.m_pColumnDef = (const CCtrlColumnDef*)(pCtrl); break; } case ECtrlObjectType::AutoNumber: { WriteAutoNumber((const CCtrlAutoNumber*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oState.m_ushLastCharShapeId, oBuilder, oState); break; } case ECtrlObjectType::Field: { WriteField((const CCtrlField*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState); break; } case ECtrlObjectType::HeadFoot: { if (EHanType::HWPX == m_pContext->GetType() || EHanType::HWPML == m_pContext->GetType()) oState.m_arCtrlsHeadFoot.push_back((const CCtrlHeadFoot*)pCtrl); break; } case ECtrlObjectType::PageNumPos: { oState.m_pPageNum = dynamic_cast(pCtrl); break; } case ECtrlObjectType::NewNumber: { oState.m_pNewNumber = dynamic_cast(pCtrl); break; } default: break; } } CloseParagraph(oBuilder, oState); } void CConverter2OOXML::WriteParagraphProperties(short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { oBuilder.WriteString(L""); WriteParaShapeProperties(shParaShapeID, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteParaShapeProperties(short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == m_pContext) return; const std::wstring wsStyleId = m_oStyleConverter.CreateStyle(shParaShapeID, shParaStyleID, *m_pContext, oState); if (!wsStyleId.empty()) { oBuilder.WriteString(L""); } if (oState.m_bInTable) oBuilder.WriteString(L""); if (m_oStyleConverter.GetLastParaShapeId() != shParaShapeID) m_oStyleConverter.WriteDifferenceParagraphStyles(m_oStyleConverter.GetLastParaShapeId(), shParaShapeID, *m_pContext, oBuilder); const CHWPRecordParaShape* pParaShape= dynamic_cast(m_pContext->GetParaShape(shParaShapeID)); if (nullptr == pParaShape) return; switch (pParaShape->GetHeadingType()) { case EHeadingType::NUMBER: case EHeadingType::BULLET: { const int nNumId = m_oNumberingConverter.CreateNumbering(dynamic_cast(m_pContext->GetNumbering(pParaShape->GetHeadingIdRef())), pParaShape->GetHeadingType(), *this); if (0 == nNumId) break; oBuilder.WriteString(L""); oBuilder.WriteString(L"GetHeadingLevel()) + L"\"/>"); oBuilder.WriteString(L""); oBuilder.WriteString(L""); break; } case EHeadingType::OUTLINE: case EHeadingType::NONE: break; } if (oState.m_bInTable) return; const CHwpRecordTabDef* pTabDef = m_pContext->GetTabDef(pParaShape->GetTabDef()); if (nullptr != pTabDef && 0 != pTabDef->GetCount()) { oBuilder.WriteString(L""); const TTab *pTab = nullptr; for (unsigned int unIndex = 0; unIndex < pTabDef->GetCount(); ++unIndex) { pTab = pTabDef->GetTab(unIndex); if (nullptr == pTab) continue; oBuilder.WriteString(L"m_eType) { case TTab::EType::LEFT: oBuilder.WriteString(L"start"); break; case TTab::EType::RIGHT: oBuilder.WriteString(L"end"); break; case TTab::EType::CENTER: oBuilder.WriteString(L"center"); break; case TTab::EType::DECIMAL: oBuilder.WriteString(L"decimal"); break; } oBuilder.WriteString(L"\" w:leader=\""); switch (pTab->m_eLeader) { case ELineStyle2::NONE: oBuilder.WriteString(L"none"); break; case ELineStyle2::SOLID: case ELineStyle2::DOUBLE_SLIM: case ELineStyle2::SLIM_THICK: case ELineStyle2::THICK_SLIM: case ELineStyle2::SLIM_THICK_SLIM: oBuilder.WriteString(L"heavy"); break; case ELineStyle2::DASH: case ELineStyle2::LONG_DASH: case ELineStyle2::DASH_DOT: case ELineStyle2::DASH_DOT_DOT: oBuilder.WriteString(L"hyphen"); break; case ELineStyle2::DOT: case ELineStyle2::CIRCLE: oBuilder.WriteString(L"dot"); break; } oBuilder.WriteString(L"\" w:pos=\"" + std::to_wstring(pTab->m_nPos / 10) + L"\"/>"); } oBuilder.WriteString(L""); } } void CConverter2OOXML::WriteTable(const CCtrlTable* pTable, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pTable || pTable->Empty()) return; if (TConversionState::TLastNode::ELastNodeType::Table == oState.m_oLastNode.m_eType) oBuilder.WriteString(L""); CloseParagraph(oBuilder, oState); ++m_ushTableCount; oBuilder.WriteString(L""); const bool bTableInTable = oState.m_bInTable; oState.m_bInTable = true; WriteTableProperties(pTable, shParaShapeID, shParaStyleID, oBuilder, oState); std::vector>> m_arrCells(pTable->GetRows()); for (unsigned int unRowIndex = 0; unRowIndex < pTable->GetRows(); ++unRowIndex) { m_arrCells[unRowIndex].resize(pTable->GetCols()); for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex) m_arrCells[unRowIndex][unColIndex] = std::make_pair(ECellCreator::NOT_CREATED, nullptr); } for (unsigned int unCellIndex = 0; unCellIndex < pTable->GetCountCells(); ++unCellIndex) { const CTblCell* pCell = pTable->GetCell(unCellIndex); if (nullptr == pCell || pCell->GetRowAddr() >= pTable->GetRows() || pCell->GetColAddr() >= pTable->GetCols()) continue; m_arrCells[pCell->GetRowAddr()][pCell->GetColAddr()] = std::make_pair(ECellCreator::FILE, pCell); } for (unsigned int unRowIndex = 0; unRowIndex < pTable->GetRows(); ++unRowIndex) { for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex) { std::pair oValue = m_arrCells[unRowIndex][unColIndex]; if (ECellCreator::NOT_CREATED == oValue.first) continue; if (ECellCreator::FILE == oValue.first) { if (1 != oValue.second->GetRowSpan()) { for (unsigned int unIndex = 1; unIndex < oValue.second->GetRowSpan() && unRowIndex + unIndex < pTable->GetRows(); ++unIndex) m_arrCells[unRowIndex + unIndex][unColIndex] = std::make_pair(ECellCreator::EMPTY, oValue.second); } } unColIndex += oValue.second->GetColSpan() - 1; } } //TODO:: в случаях, когда есть пустые столбцы необходимо добавить возможность удаления данных столбцов // Например для матрицы 3x2, у которой значения есть только в 2x2, необходимо удалить последний столбец for (unsigned int unRowIndex = 0; unRowIndex < pTable->GetRows(); ++unRowIndex) { oBuilder.WriteString(L""); int nHeight = 0; for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex) { std::pair oValue = m_arrCells[unRowIndex][unColIndex]; if (ECellCreator::FILE == oValue.first && 1 == oValue.second->GetRowSpan()) nHeight = (std::max)(nHeight, oValue.second->GetHeight()); } oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex) { std::pair oValue = m_arrCells[unRowIndex][unColIndex]; WriteCell(oValue.second, oBuilder, oState, oValue.first); } oBuilder.WriteString(L""); } oBuilder.WriteString(L""); oState.m_oLastNode.m_eType = TConversionState::TLastNode::ELastNodeType::Table; oState.m_oLastNode.m_unParaIndex = oState.m_unParaIndex; oState.m_bInTable = bTableInTable; } void CConverter2OOXML::WriteTableProperties(const CCtrlTable* pTable, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pTable) return; oBuilder.WriteString(L""); // TODO:: сделать вычисление oBuilder.WriteString(L""); if (0 != pTable->GetInLSpace() || 0 != pTable->GetInTSpace() || 0 != pTable->GetInRSpace() || 0 != pTable->GetInBSpace()) { oBuilder.WriteString(L""); oBuilder.WriteString(L"GetInTSpace())) + L"\" w:type=\"dxa\"/>"); oBuilder.WriteString(L"GetInLSpace())) + L"\" w:type=\"dxa\"/>"); oBuilder.WriteString(L"GetInBSpace())) + L"\" w:type=\"dxa\"/>"); oBuilder.WriteString(L"GetInRSpace())) + L"\" w:type=\"dxa\"/>"); oBuilder.WriteString(L""); } WriteParaShapeProperties(shParaShapeID, shParaStyleID, oBuilder, oState); // const CHWPRecordBorderFill* pBorderFill = nullptr; // if (nullptr != m_pContext) // pBorderFill = dynamic_cast(m_pContext->GetBorderFill(pTable->GetBorderFillID())); // if (nullptr == pBorderFill) // { // oBuilder.WriteString(L""); // return; // } oBuilder.WriteString(L""); } void CConverter2OOXML::WriteCell(const CTblCell* pCell, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, ECellCreator eCellCreator) { if (nullptr == pCell) return; oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L"GetWidth())) + L"\" w:type=\"dxa\"/>"); if (1 != pCell->GetColSpan()) oBuilder.WriteString(L"GetColSpan()) + L"\"/>"); if (1 != pCell->GetRowSpan()) oBuilder.WriteString(L""); WriteCellProperties(pCell->GetBorderFillID(), oBuilder); switch(pCell->GetVertAlign()) { case EVertAlign::TOP: oBuilder.WriteString(L""); break; case EVertAlign::CENTER: oBuilder.WriteString(L""); break; case EVertAlign::BOTTOM: oBuilder.WriteString(L""); break; case EVertAlign::INSIDE: case EVertAlign::OUTSIDE: break; } oBuilder.WriteString(L""); if (ECellCreator::FILE == eCellCreator && !pCell->GetParagraphs().empty()) { for (const CHWPPargraph* pParagraph : pCell->GetParagraphs()) { NSStringUtils::CStringBuilder oCellBuilder; TConversionState oCellState; oCellState.m_pRelationships = oState.m_pRelationships; oCellState.m_bInTable = oState.m_bInTable; WriteParagraph(pParagraph, oCellBuilder, oCellState); if (0 == oCellBuilder.GetCurSize()) { OpenParagraph(pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oCellState); CloseParagraph(oBuilder, oCellState); } else oBuilder.Write(oCellBuilder); } } else oBuilder.WriteString(L""); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteCellProperties(short shBorderFillID, NSStringUtils::CStringBuilder& oBuilder) { const CHWPRecordBorderFill* pBorderFill = nullptr; if (nullptr != m_pContext) pBorderFill = dynamic_cast(m_pContext->GetBorderFill(shBorderFillID)); if (nullptr == pBorderFill) return; if(nullptr != pBorderFill->GetFill()) { const CFill* pFill{pBorderFill->GetFill()}; if (pFill->ColorFill()) oBuilder.WriteString(L"GetFaceColor()) + L"\"/>"); // In OOXML, there is no gradient support for cell fills, so we fill in the first color of the gradient. else if (pFill->GradFill() && 0 != pFill->GetGradColorNum()) oBuilder.WriteString(L"GetGradColors().front()) + L"\"/>"); } oBuilder.WriteString(L""); WriteBorder(pBorderFill->GetTopBorder(), L"top", oBuilder); WriteBorder(pBorderFill->GetLeftBorder(), L"left", oBuilder); WriteBorder(pBorderFill->GetBottomBorder(), L"bottom", oBuilder); WriteBorder(pBorderFill->GetRightBorder(), L"right", oBuilder); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteBorder(const TBorder& oBorder, const HWP_STRING& sBorderName, NSStringUtils::CStringBuilder& oBuilder) { if (sBorderName.empty()) return; HWP_STRING sType; //TODO:: проверить стиль линий switch(oBorder.m_eStyle) { case ELineStyle2::NONE: oBuilder.WriteString(L""); return; case ELineStyle2::SOLID: sType = L"single"; break; case ELineStyle2::DASH: sType = L"dashed"; break; case ELineStyle2::DOT: sType = L"dotted"; break; case ELineStyle2::DASH_DOT: sType = L"dotDash"; break; case ELineStyle2::DASH_DOT_DOT: sType = L"dotDotDash"; break; case ELineStyle2::LONG_DASH: sType = L"dashed"; break; case ELineStyle2::CIRCLE: sType = L"dashed"; break; case ELineStyle2::DOUBLE_SLIM: sType = L"double"; break; case ELineStyle2::SLIM_THICK: sType = L"thinThickSmallGap"; break; case ELineStyle2::THICK_SLIM: sType = L"thickThinSmallGap"; break; case ELineStyle2::SLIM_THICK_SLIM: sType = L"thinThickThinSmallGap"; break; } oBuilder.WriteString(L""); } VECTOR ArcToBezier(const TPoint& oStart, const TPoint& oEnd, const TPoint& oCenter) { const double dRadiusX = std::abs(oStart.m_nX - oCenter.m_nX); const double dRadiusY = std::abs(oStart.m_nY - oCenter.m_nY); // Вычисление углов double dStartAngle = std::atan2(oStart.m_nY - oCenter.m_nY, oStart.m_nX - oCenter.m_nX); double dEndAngle = std::atan2(oEnd.m_nY - oCenter.m_nY, oEnd.m_nX - oCenter.m_nX); if (dEndAngle < dStartAngle) std::swap(dStartAngle, dEndAngle); TPoint oControl1{static_cast(oStart.m_nX + dRadiusX * std::cos(dStartAngle)), static_cast(oStart.m_nY + dRadiusY * std::sin(dStartAngle))}; TPoint oControl2{static_cast(oEnd.m_nX - dRadiusX * std::cos(dEndAngle )), static_cast(oEnd.m_nY + dRadiusY * std::sin(dEndAngle ))}; return {oStart, oControl1, oControl2, oEnd}; } void CConverter2OOXML::WriteGeometryShape(const CCtrlGeneralShape* pGeneralShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const CCtrlContainer* pContainer) { if (nullptr == pGeneralShape) return; EShapeObjectType eShapeType = GetShapeObjectType(pGeneralShape->GetID()); if (EShapeObjectType::Unknown == eShapeType) return; ++m_ushShapeCount; WriteCaption((const CCtrlCommon*)pGeneralShape, oBuilder, oState); OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); const int nWidth = Transform::HWPUINT2OOXML(pGeneralShape->GetFinalWidth()); const int nHeight = Transform::HWPUINT2OOXML(pGeneralShape->GetFinalHeight()); const std::wstring wsWidth = std::to_wstring(nWidth); const std::wstring wsHeight = std::to_wstring(nHeight); oBuilder.WriteString(L""); oBuilder.WriteString(L""); OpenDrawingNode((nullptr != pContainer) ? pContainer : pGeneralShape, oBuilder); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); switch (eShapeType) { case EShapeObjectType::Arc: { const CCtrlShapeArc *pShapeArc = (const CCtrlShapeArc*)pGeneralShape; TPoint oStartPoint {pShapeArc->GetFirstPoint()}, oEndPoint {pShapeArc->GetSecondPoint()}, oCenterPoint{pShapeArc->GetCenterPoint()}; const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()}; oMatrix.ApplyToPoint(oStartPoint .m_nX, oStartPoint .m_nY); oMatrix.ApplyToPoint(oEndPoint .m_nX, oEndPoint .m_nY); oMatrix.ApplyToPoint(oCenterPoint.m_nX, oCenterPoint.m_nY); VECTOR arBezierPoints{ArcToBezier({Transform::HWPUINT2OOXML(oStartPoint .m_nX), Transform::HWPUINT2OOXML(oStartPoint .m_nY)}, {Transform::HWPUINT2OOXML(oEndPoint .m_nX), Transform::HWPUINT2OOXML(oEndPoint .m_nY)}, {Transform::HWPUINT2OOXML(oCenterPoint.m_nX), Transform::HWPUINT2OOXML(oCenterPoint.m_nY)})}; oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); break; } case EShapeObjectType::Ellipse: { oBuilder.WriteString(L""); break; } case EShapeObjectType::Line: { const CCtrlShapeLine *pShapeLine = (const CCtrlShapeLine*)pGeneralShape; TPoint oStartPoint{pShapeLine->GetStartX(), pShapeLine->GetStartY()}, oEndPoint {pShapeLine->GetEndX(), pShapeLine->GetEndY() }; const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()}; oMatrix.ApplyToPoint(oStartPoint .m_nX, oStartPoint .m_nY); oMatrix.ApplyToPoint(oEndPoint .m_nX, oEndPoint .m_nY); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); // oBuilder.WriteString(L""); break; } case EShapeObjectType::Rectangle: { const CCtrlShapeRect* pShapeRect = (const CCtrlShapeRect*)pGeneralShape; TPoint arPoints[4]; pShapeRect->GetPoints(arPoints); const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()}; for (TPoint& oPoint : arPoints) { oMatrix.ApplyToPoint(oPoint.m_nX, oPoint.m_nY); oPoint.m_nX = Transform::HWPUINT2OOXML(oPoint.m_nX); oPoint.m_nY = Transform::HWPUINT2OOXML(oPoint.m_nY); } oBuilder.WriteString(L""); oBuilder.WriteString(L""); for (unsigned short ushIndex = 1; ushIndex < 4; ++ushIndex) oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); // oBuilder.WriteString(L""); break; } case EShapeObjectType::Polygon: { VECTOR arPoints{((const CCtrlShapePolygon*)pGeneralShape)->GetPoints()}; if (2 > arPoints.size()) break; const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()}; for (TPoint& oPoint : arPoints) { oMatrix.ApplyToPoint(oPoint.m_nX, oPoint.m_nY); oPoint.m_nX = Transform::HWPUINT2OOXML(oPoint.m_nX); oPoint.m_nY = Transform::HWPUINT2OOXML(oPoint.m_nY); } oBuilder.WriteString(L""); oBuilder.WriteString(L""); for (unsigned short ushIndex = 1; ushIndex < arPoints.size(); ++ushIndex) oBuilder.WriteString(L""); oBuilder.WriteString(L""); break; } case EShapeObjectType::Curve: { VECTOR arPoints{((const CCtrlShapeCurve*)pGeneralShape)->GetPoints()}; if (2 > arPoints.size()) break; const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()}; for (TPoint& oPoint : arPoints) { oPoint.m_nX = Transform::HWPUINT2OOXML(oPoint.m_nX); oPoint.m_nY = Transform::HWPUINT2OOXML(oPoint.m_nY); oMatrix.ApplyToPoint(oPoint.m_nX, oPoint.m_nY); } VECTOR arSegmentType{((const CCtrlShapeCurve*)pGeneralShape)->GetSegmentsType()}; oBuilder.WriteString(L""); oBuilder.WriteString(L""); for (unsigned short ushIndex = 0; ushIndex < arSegmentType.size(); ++ushIndex) { if (0x01 == arSegmentType[ushIndex]) { oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); ushIndex += 2; } else oBuilder.WriteString(L""); } oBuilder.WriteString(L""); break; } case EShapeObjectType::Ole: case EShapeObjectType::Picture: case EShapeObjectType::Unknown: break; } const CFill *pFill = pGeneralShape->GetFill(); if (nullptr == pFill || pFill->NoneFill()) oBuilder.WriteString(L""); else if (pFill->ColorFill()) oBuilder.WriteString(L"GetFaceColor()) + L"\"/>"); else if (pFill->ImageFill()) { const HWP_STRING sPictureId = SavePicture(pFill->GetBinItemID(), oState); if (!sPictureId.empty()) oBuilder.WriteString(L""); else oBuilder.WriteString(L""); } WriteLineSettings(pGeneralShape, oBuilder); oBuilder.WriteString(L""); unsigned int nCountParagraphs = pGeneralShape->GetCountParagraphs(); if (0 < nCountParagraphs) { oBuilder.WriteString(L""); TConversionState oShapeState; oShapeState.m_bInTextBox = true; for (unsigned int unParaIndex = 0; unParaIndex < nCountParagraphs; ++unParaIndex) WriteParagraph(pGeneralShape->GetParagraphs(unParaIndex), oBuilder, oShapeState); oBuilder.WriteString(L""); } oBuilder.WriteString(L""); oBuilder.WriteString(L""); CloseDrawingNode(pGeneralShape, oBuilder); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteEqEditShape(const CCtrlEqEdit* pEqEditShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { //TODO:: добавить конвертацию eqn формулы в ooxml ++m_ushEquationCount; WriteCaption((const CCtrlCommon*)pEqEditShape, oBuilder, oState); OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteEncodeXmlString(pEqEditShape->GetEqn()); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteOleShape(const CCtrlShapeOle* pOleShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { //TODO:: добавить конвертацию hwp ole -> ooxml chart //TODO:: необходимо добавить поддержку формата "Hwp Document File Formats - Charts" (для случаев, когда нет ooxml представления) // Пока можем вытащить лишь ooxml представление данных // Реализовать с использованием pole.h? if (nullptr == m_pContext) return; CHWPStream oBuffer; HWP_STRING sFileName; if (!m_pContext->GetBinBytes(pOleShape->GetBinDataID(), oBuffer, sFileName)) return; m_oOleConverter.CreateChart(oBuffer); const unsigned int unChartIndex = m_oOleConverter.GetChartsCount(); if (0 == unChartIndex) return; ++m_ushShapeCount; WriteCaption((const CCtrlCommon*)pOleShape, oBuilder, oState); const std::wstring wsWidth = std::to_wstring(Transform::HWPUINT2OOXML(pOleShape->GetWidth())); const std::wstring wsHeight = std::to_wstring(Transform::HWPUINT2OOXML(pOleShape->GetHeight())); const std::wstring wsRelID = AddRelationship(L"chart", L"charts/chart" + std::to_wstring(unChartIndex) + L".xml", &oState); OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L""); OpenDrawingNode(pOleShape, oBuilder); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); CloseDrawingNode(pOleShape, oBuilder); oBuilder.WriteString(L""); AddContentType(L"charts/chart" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.openxmlformats-officedocument.drawingml.chart+xml"); AddContentType(L"charts/style" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.ms-office.chartstyle+xml"); AddContentType(L"charts/colors" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.ms-office.chartcolorstyle+xml"); } void CConverter2OOXML::WriteContainer(const CCtrlContainer* pContainer, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { for (const CCtrlGeneralShape* pGeneralShape : pContainer->GetShapes()) WriteShape(pGeneralShape, shParaShapeID, shParaStyleID, oBuilder, oState, pContainer); } void CConverter2OOXML::WriteSectionSettings(TConversionState& oState) { m_oDocXml.WriteString(L""); if (nullptr != oState.m_pSectionDef) { std::vector arCtrlsHeadFoot; switch (m_pContext->GetType()) { case EHanType::HWP: { arCtrlsHeadFoot = oState.m_pSectionDef->GetHeaderFooters(); break; } case EHanType::HWPX: case EHanType::HWPML: { arCtrlsHeadFoot = oState.m_arCtrlsHeadFoot; oState.m_arCtrlsHeadFoot.clear(); break; } default: return; } #define WRITE_ID(id)\ if (!id.empty() && id.length() > 6)\ {\ const std::wstring wsType = id.substr(0, 6);\ AddContentType(id, L"application/vnd.openxmlformats-officedocument.wordprocessingml." + wsType + L"+xml");\ m_oDocXml.WriteString(L"");\ } if (nullptr != oState.m_pPageNum) { const std::wstring wsID = m_oFootnoteConverter.CreatePageNum(oState.m_pPageNum, *this); WRITE_ID(wsID); oState.m_pPageNum = nullptr; } for (const CCtrlHeadFoot* pCtrlHeadFoot : arCtrlsHeadFoot) { const std::wstring wsID = m_oFootnoteConverter.CreateHeadOrFoot((const CCtrlHeadFoot*)pCtrlHeadFoot, *this); WRITE_ID(wsID); } } if (nullptr != oState.m_pNewNumber && ENumType::PAGE == oState.m_pNewNumber->GetNumType()) m_oDocXml.WriteString(L"GetNum()) + L"\"/>"); const CPage *pPage = (nullptr != oState.m_pSectionDef) ? oState.m_pSectionDef->GetPage() : nullptr; if (nullptr == pPage) { //DEFAULT_VALUE m_oDocXml.WriteString(L""); m_oDocXml.WriteString(L""); } else { m_oDocXml.WriteString(L"GetWidth())) + L"\" w:h=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetHeight())) + L"\"/>"); m_oDocXml.WriteString(L"GetMarginTop() + pPage->GetMarginHeader())) + L"\" w:right=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginRight())) + L"\" w:bottom=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginBottom() + pPage->GetMarginFooter())) + L"\" w:left=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginRight())) + L"\" w:header=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginHeader())) + L"\" w:footer=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginFooter())) + L"\" w:gutter=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginGutter())) + L"\"/>"); } if (nullptr != oState.m_pColumnDef && 1 < oState.m_pColumnDef->GetColCount()) { //TODO:: Добавить поддержку остальный свойств m_oDocXml.WriteString(L"GetColCount()) + L"\" w:space=\"454\""); if (ELineStyle2::NONE != oState.m_pColumnDef->GetColLineStyle()) m_oDocXml.WriteString(L" w:sep=\"true\""); m_oDocXml.WriteString(L"/>"); } else m_oDocXml.WriteString(L""); m_oDocXml.WriteString(L""); } void CConverter2OOXML::WritePicture(const CCtrlShapePic* pCtrlPic, short shParaShapeId, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pCtrlPic) return; HWP_STRING sPictureID = SavePicture(pCtrlPic->GetBinDataID(), oState); if (sPictureID.empty()) return; ++m_ushShapeCount; WriteCaption((const CCtrlCommon*)pCtrlPic, oBuilder, oState); OpenParagraph(shParaShapeId, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L""); OpenDrawingNode(pCtrlPic, oBuilder); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L"HorzFlip()) oBuilder.WriteString(L" flipH=\"1\""); if (pCtrlPic->VertFlip()) oBuilder.WriteString(L" flipV=\"1\""); oBuilder.WriteString(L">GetFinalWidth()) + L"\" cy=\"" + std::to_wstring(pCtrlPic->GetFinalHeight()) + L"\"/>"); oBuilder.WriteString(L""); WriteBorderSettings(pCtrlPic, oBuilder); oBuilder.WriteString(L""); CloseDrawingNode(pCtrlPic, oBuilder); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteVideo(const CCtrlShapeVideo* pCtrlVideo, short shParaShapeId, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pCtrlVideo || 1 != pCtrlVideo->GetVideoType()) return; HWP_STRING sPictureID = SavePicture(pCtrlVideo->GetThumnailBinID(), oState); if (sPictureID.empty()) return; ++m_ushShapeCount; WriteCaption((const CCtrlCommon*)pCtrlVideo, oBuilder, oState); OpenParagraph(shParaShapeId, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L""); OpenDrawingNode(pCtrlVideo, oBuilder); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L"GetDesc() + L"\">"); oBuilder.WriteString(L"GetWebUrl(), &oState) + L"\"/>"); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); const int nIFrameWidth = (int)((double)Transform::HWPUINT2OOXML(pCtrlVideo->GetWidth()) / 22860.); const int nIFrameHeight = (int)((double)Transform::HWPUINT2OOXML(pCtrlVideo->GetHeight()) / 22860.); oBuilder.WriteString(L""); oBuilder.WriteString(L"GetWebUrl() + L"\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen=\"\" title=\"\" sandbox=\"allow-scripts allow-same-origin allow-popups\">"); oBuilder.WriteString(L"\" h=\"" + std::to_wstring(nIFrameWidth) + L"\" w=\"" + std::to_wstring(nIFrameHeight) + L"\"/>"); oBuilder.WriteString(L""); oBuilder.WriteString(L"GetFinalWidth())) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlVideo->GetFinalHeight())) + L"\"/>"); oBuilder.WriteString(L""); CloseDrawingNode(pCtrlVideo, oBuilder); oBuilder.WriteString(L""); } bool CConverter2OOXML::SaveSVGFile(const HWP_STRING& sSVG, HWP_STRING& sFileName) { if (sSVG.empty()) return false; NSFonts::IApplicationFonts* pFonts = NSFonts::NSApplication::Create(); pFonts->Initialize(); MetaFile::IMetaFile* pSvgReader = MetaFile::Create(pFonts); if (!pSvgReader->LoadFromString(sSVG)) { RELEASEINTERFACE(pSvgReader); RELEASEINTERFACE(pFonts); return false; } double dX, dY, dW, dH; pSvgReader->GetBounds(&dX, &dY, &dW, &dH); if (dW < 0) dW = -dW; if (dH < 0) dH = -dH; sFileName = sFileName.substr(0, sFileName.find(L'.')); sFileName += L".png"; const std::wstring wsImagePath{m_sTempDirectory + L"/word/media/" + sFileName}; pSvgReader->ConvertToRaster(wsImagePath.c_str(), 4, dW, dH); RELEASEINTERFACE(pSvgReader); RELEASEINTERFACE(pFonts); return true; } HWP_STRING CConverter2OOXML::SavePicture(const HWP_STRING& sBinItemId, TConversionState& oState) { if (nullptr == m_pContext || sBinItemId.empty()) return HWP_STRING(); //TODO:: добавить поддержку устновки размеров изображения из свойств шейпа CHWPStream oBuffer; HWP_STRING sFileName; if (!m_pContext->GetBinBytes(sBinItemId, oBuffer, sFileName)) return HWP_STRING(); oBuffer.MoveToStart(); if (IsRasterFormat(NSFile::GetFileExtention(sFileName))) { NSFile::CFileBinary oFile; oFile.CreateFileW(m_sTempDirectory + L"/word/media/" + sFileName); if (!oFile.WriteFile((unsigned char*)oBuffer.GetCurPtr(), oBuffer.GetSize())) { oFile.CloseFile(); return HWP_STRING(); } oFile.CloseFile(); } else if (L"svg" == NSFile::GetFileExtention(sFileName)) { std::string sSVG(oBuffer.GetCurPtr(), oBuffer.GetSize()); if (!SaveSVGFile(UTF8_TO_U(sSVG), sFileName)) return HWP_STRING(); } AddContentType(L"media/" + sFileName, L"image/" + NSFile::GetFileExtention(sFileName)); return AddRelationship(L"image", L"media/" + sFileName, &oState); } void CConverter2OOXML::WriteRunnerStyle(short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const CRunnerStyle& sExternStyles) { if (nullptr == m_pContext) return; oBuilder.WriteString(L""); if (m_oStyleConverter.GetLastCharShapeId() != shCharShapeID) m_oStyleConverter.WriteDifferenceRunnerStyles(m_oStyleConverter.GetLastCharShapeId(), shCharShapeID, *m_pContext, oBuilder); const CHWPRecordCharShape* pCharShape = dynamic_cast(m_pContext->GetCharShape(shCharShapeID)); if (nullptr != pCharShape) { WriteTextBorderStyle(pCharShape->GetBorderFillID(), oBuilder, oState); oState.m_ushLastCharShapeId = shCharShapeID; } m_oStyleConverter.WriteRunnerProperties(sExternStyles, oBuilder); oBuilder.WriteString(L""); switch(oState.m_eBreakType) { case TConversionState::EBreakType::Page: oBuilder.WriteString(L""); break; case TConversionState::EBreakType::Column: oBuilder.WriteString(L""); break; case TConversionState::EBreakType::TextWrapping: oBuilder.WriteString(L""); break; case TConversionState::EBreakType::None: break; } oState.m_eBreakType = TConversionState::EBreakType::None; } void CConverter2OOXML::WriteTextBorderStyle(short shBorderFillId, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { const CHWPRecordBorderFill* pBorderFill = dynamic_cast(m_pContext->GetBorderFill(shBorderFillId)); if (nullptr == pBorderFill) return; TBorder oBorder{pBorderFill->GetLeftBorder()}; if (ELineStyle2::NONE == oBorder.m_eStyle) return; WriteBorder(pBorderFill->GetLeftBorder(), L"bdr", oBuilder); } void CConverter2OOXML::OpenDrawingNode(const CCtrlObjElement* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlShape) return; oBuilder.WriteString(L""); if (pCtrlShape->GetTreatAsChar()) { oBuilder.WriteString(L"GetTopOutMargin() / 10)) + L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomOutMargin() / 10)) + L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftOutMargin() / 10)) + L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightOutMargin() / 10)) + L"\">"); WriteShapeExtent(pCtrlShape, oBuilder); } else { oBuilder.WriteString(L"GetTextWrap() ? L"1" : L"0")) + L"\" relativeHeight=\"" + std::to_wstring(pCtrlShape->GetZOrder()) + L"\" distT=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetTopOutMargin() / 10)) + L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomOutMargin() / 10)) + L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftOutMargin() / 10)) + L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightOutMargin() / 10)) + L"\" simplePos=\"0\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"); WriteShapePosition(pCtrlShape, oBuilder); WriteShapeExtent(pCtrlShape, oBuilder); WriteShapeWrapMode(pCtrlShape, oBuilder); } WriteShapeProperty(pCtrlShape, oBuilder); } void CConverter2OOXML::CloseDrawingNode(const CCtrlObjElement* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlShape) return; if (pCtrlShape->GetTreatAsChar()) oBuilder.WriteString(L""); else oBuilder.WriteString(L""); oBuilder.WriteString(L""); } HWP_STRING GetVRelativeFrom(EVRelTo eRelTo) { switch (eRelTo) { case EVRelTo::PARA: return L"paragraph"; case EVRelTo::PAPER: case EVRelTo::PAGE: return L"page"; } } HWP_STRING GetHRelativeFrom(EHRelTo eRelTo) { switch (eRelTo) { case EHRelTo::PAPER: case EHRelTo::PAGE: return L"page"; case EHRelTo::COLUMN: return L"column"; case EHRelTo::PARA: return L"margin"; } } void CConverter2OOXML::WriteShapeProperty(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlShape) return; oBuilder.WriteString(L"GetDesc()); oBuilder.WriteString(L"\"/>"); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteShapePosition(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlShape) return; oBuilder.WriteString(L""); const int nHorzOffset = pCtrlShape->GetHorzOffset(); const int nVertOffset = pCtrlShape->GetVertOffset(); oBuilder.WriteString(L"GetHorzRelTo()) + L"\">" + std::to_wstring(Transform::HWPUINT2OOXML(nHorzOffset)) + L""); oBuilder.WriteString(L"GetVertRelTo()) + L"\">" + std::to_wstring(Transform::HWPUINT2OOXML(nVertOffset)) + L""); } void CConverter2OOXML::WriteShapeExtent(const CCtrlObjElement* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlShape) return; const int nFinalWidth = std::abs(pCtrlShape->GetFinalWidth()); const int nFinalHeight = std::abs(pCtrlShape->GetFinalHeight()); oBuilder.WriteString(L""); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteShapeWrapMode(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlShape) return; switch (pCtrlShape->GetTextWrap()) { case ETextWrap::SQUARE: { oBuilder.WriteString(L"GetTextFlow()) { case 0x0: default: oBuilder.WriteString(L"bothSides"); break; case 0x1: oBuilder.WriteString(L"left"); break; case 0x2: oBuilder.WriteString(L"right"); break; case 0x3: oBuilder.WriteString(L"largest"); break; } oBuilder.WriteString(L"\"/>"); break; } case ETextWrap::TOP_AND_BOTTOM: { oBuilder.WriteString(L""); break; } case ETextWrap::BEHIND_TEXT: case ETextWrap::IN_FRONT_OF_TEXT: default: { oBuilder.WriteString(L""); break; } } } void CConverter2OOXML::OpenParagraph(short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (oState.m_bOpenedP) return; oBuilder.WriteString(L""); oState.m_bOpenedP = true; WriteParagraphProperties(shParaShapeID, shParaStyleID, oBuilder, oState); } void CConverter2OOXML::CloseParagraph(NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (!oState.m_bOpenedP) return; oBuilder.WriteString(L""); oState.m_bOpenedP = false; oState.m_oLastNode.m_unParaIndex = oState.m_unParaIndex; oState.m_oLastNode.m_eType = TConversionState::TLastNode::ELastNodeType::Paragraph; } void CConverter2OOXML::WriteText(const CParaText* pParaText, const std::vector& arRangeTags, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pParaText) return; if (arRangeTags.empty()) { WriteText(pParaText->GetText(), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState); return; } HWP_STRING wsText = pParaText->GetText(); int nParaTextPosition = pParaText->GetStartIDx(); int unStartText = 0; TColor *pHighlightColor = nullptr; for (size_t unTextPosition = 0; unTextPosition < wsText.length(); ++unTextPosition) { for (const TRangeTag& oRangeTag : arRangeTags) { if (unTextPosition + nParaTextPosition == oRangeTag.m_nStartPos) { WriteText(wsText.substr(unStartText, unTextPosition - unStartText), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState); unStartText = unTextPosition; switch (oRangeTag.m_chType) { case 0x02: //highlight { pHighlightColor = new TColor{(unsigned char)oRangeTag.m_arData[0], (unsigned char)oRangeTag.m_arData[1], (unsigned char)oRangeTag.m_arData[2]}; break; } default: break; } } else if (unTextPosition + nParaTextPosition == oRangeTag.m_nEndPos) { if (nullptr == pHighlightColor) { WriteText(wsText.substr(unStartText, unTextPosition - unStartText), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState); unStartText = unTextPosition; continue; } CRunnerStyle oRunnerStyle; oRunnerStyle.SetHighlight(NormalizeHighlightColor(*pHighlightColor)); WriteText(wsText.substr(unStartText, unTextPosition - unStartText), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState, oRunnerStyle); unStartText = unTextPosition; switch (oRangeTag.m_chType) { case 0x02: //highlight { if (nullptr != pHighlightColor) { delete pHighlightColor; pHighlightColor = nullptr; } break; } default: break; } } } } if (unStartText < wsText.length()) WriteText(wsText.substr(unStartText), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState); } std::vector SplitText(const std::wstring& wsText) { if (wsText.empty()) return std::vector{L""}; std::vector arTexts; std::wstring wsCurrentText; bool bWasLetter = iswalpha(wsText[0]); wsCurrentText.push_back(wsText[0]); for (unsigned int unIndex = 1; unIndex < wsText.length(); ++unIndex) { bool bCurrentIsLetter = iswalnum(wsText[unIndex]); if (bCurrentIsLetter != bWasLetter) { arTexts.push_back(wsCurrentText); wsCurrentText.clear(); bWasLetter = bCurrentIsLetter; } wsCurrentText.push_back(wsText[unIndex]); } if (!wsCurrentText.empty()) arTexts.push_back(wsCurrentText); return arTexts; } void CConverter2OOXML::WriteText(const HWP_STRING& wsText, short shParaShapeID, short shParaStyleID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const CRunnerStyle& oExternalStyle) { if (!oState.m_bOpenedP && wsText.empty()) return; OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); if (wsText.empty()) { oBuilder.WriteString(L""); WriteRunnerStyle(shCharShapeID, oBuilder, oState, oExternalStyle); oBuilder.WriteString(L""); return; } oBuilder.WriteString(L""); WriteRunnerStyle(shCharShapeID, oBuilder, oState, oExternalStyle); oBuilder.WriteString(L""); else oBuilder.WriteString(L">"); if (bNeedAddSpace) oBuilder.WriteString(L" "); oBuilder.WriteEncodeXmlString(wsText); oBuilder.WriteString(L""); return; for (const std::wstring& wsTextElement : SplitText(wsText)) { oBuilder.WriteString(L""); WriteRunnerStyle(shCharShapeID, oBuilder, oState, oExternalStyle); if (!wsTextElement.empty()) { oBuilder.WriteString(L""); oBuilder.WriteEncodeXmlString(wsTextElement); oBuilder.WriteString(L""); } oBuilder.WriteString(L""); } } void CConverter2OOXML::WriteLineSettings(const CCtrlGeneralShape* pCtrlGeneralShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlGeneralShape) return; WriteLineSettings({pCtrlGeneralShape->GetLineStyle(), pCtrlGeneralShape->GetLineColor(), pCtrlGeneralShape->GetLineThick(), 1, pCtrlGeneralShape->GetLineHeadStyle(), pCtrlGeneralShape->GetLineHeadSize(), pCtrlGeneralShape->GetLineTailStyle(), pCtrlGeneralShape->GetLineTailSize()}, oBuilder); } void WriteLineArrowStyles(ELineArrowStyle eArrowStyle, ELineArrowSize eArrowSize, NSStringUtils::CStringBuilder& oBuilder) { switch (eArrowStyle) { case ELineArrowStyle::ARROW: oBuilder.WriteString(L" type=\"triangle\""); break; case ELineArrowStyle::SPEAR: oBuilder.WriteString(L" type=\"arrow\""); break; case ELineArrowStyle::CONCAVE_ARROW: oBuilder.WriteString(L" type=\"stealth\""); break; case ELineArrowStyle::DIAMOND: case ELineArrowStyle::EMPTY_DIAMOND: case ELineArrowStyle::BOX: case ELineArrowStyle::EMPTY_BOX: oBuilder.WriteString(L" type=\"diamond\""); break; case ELineArrowStyle::CIRCLE: case ELineArrowStyle::EMPTY_CIRCLE: oBuilder.WriteString(L" type=\"oval\""); break; case ELineArrowStyle::NORMAL: break; } switch (eArrowSize) { case ELineArrowSize::SMALL_SMALL: oBuilder.WriteString(L" w=\"sm\" len=\"sm\""); break; case ELineArrowSize::SMALL_MEDIUM: oBuilder.WriteString(L" w=\"sm\" len=\"med\""); break; case ELineArrowSize::SMALL_LARGE: oBuilder.WriteString(L" w=\"sm\" len=\"lg\""); break; case ELineArrowSize::MEDIUM_SMALL: oBuilder.WriteString(L" w=\"med\" len=\"sm\""); break; case ELineArrowSize::MEDIUM_MEDIUM: oBuilder.WriteString(L" w=\"med\" len=\"med\""); break; case ELineArrowSize::MEDIUM_LARGE: oBuilder.WriteString(L" w=\"med\" len=\"lg\""); break; case ELineArrowSize::LARGE_SMALL: oBuilder.WriteString(L" w=\"lg\" len=\"sm\""); break; case ELineArrowSize::LARGE_MEDIUM: oBuilder.WriteString(L" w=\"lg\" len=\"med\""); break; case ELineArrowSize::LARGE_LARGE: oBuilder.WriteString(L" w=\"lg\" len=\"lg\""); break; break; } } void CConverter2OOXML::WriteLineSettings(const TLineData& oLineData, NSStringUtils::CStringBuilder& oBuilder) { if (ELineStyle2::NONE == oLineData.m_eStyle) { oBuilder.WriteString(L""); return; } int nThick{oLineData.m_nThick}; if (0 == oLineData.m_nThick) nThick = 100; oBuilder.WriteString(L""); oBuilder.WriteString(L""); switch (oLineData.m_eStyle) { case ELineStyle2::DASH: { oBuilder.WriteString(L""); break; } case ELineStyle2::DOT: { oBuilder.WriteString(L""); break; } case ELineStyle2::DASH_DOT: { oBuilder.WriteString(L""); break; } case ELineStyle2::DASH_DOT_DOT: { oBuilder.WriteString(L""); break; } case ELineStyle2::LONG_DASH: { oBuilder.WriteString(L""); break; } case ELineStyle2::CIRCLE: { oBuilder.WriteString(L""); break; } default: break; } if (ELineArrowStyle::NORMAL != oLineData.m_eHeadStyle) { oBuilder.WriteString(L""); } if (ELineArrowStyle::NORMAL != oLineData.m_eTailStyle) { oBuilder.WriteString(L""); } switch (oLineData.m_nCompoundLineType) { case 0x00: { oBuilder.WriteString(L""); break; } case 0x01: { oBuilder.WriteString(L""); break; } } oBuilder.WriteString(L""); } void CConverter2OOXML::WriteBorderSettings(const CCtrlShapePic* pCtrlPic, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlPic || nullptr == m_pContext) return; if (EHanType::HWP == m_pContext->GetType()) WriteLineSettings({pCtrlPic->GetBorderLineStyle(), pCtrlPic->GetBorderColor(), pCtrlPic->GetBorderThick(), pCtrlPic->GetBorderCompoundLineType()}, oBuilder); else if (EHanType::HWPX == m_pContext->GetType() || EHanType::HWPML == m_pContext->GetType()) WriteLineSettings({pCtrlPic->GetLineStyle(), pCtrlPic->GetLineColor(), pCtrlPic->GetLineThick(), 1}, oBuilder); } void CConverter2OOXML::WriteAutoNumber(const CCtrlAutoNumber* pAutoNumber, short shParaShapeID, short shParaStyleID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pAutoNumber) return; unsigned short ushValue = 0; HWP_STRING wsType; //TODO:: лучше перейти не на ручной подсчет, а на автоматический в word (но там есть свои проблемы) switch (pAutoNumber->GetNumType()) { case ENumType::PAGE: { OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L"1"); return; } case ENumType::TOTAL_PAGE: { OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L"1"); return; } case ENumType::FOOTNOTE: { OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L""); CRunnerStyle oRunnerStyle; oRunnerStyle.SetVerticalAlign(EVerticalAlignRun::Superscript); WriteRunnerStyle(shCharShapeID, oBuilder, oState, oRunnerStyle); oBuilder.WriteString(L""); return; } case ENumType::ENDNOTE: { OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState); oBuilder.WriteString(L""); CRunnerStyle oRunnerStyle; oRunnerStyle.SetVerticalAlign(EVerticalAlignRun::Superscript); WriteRunnerStyle(shCharShapeID, oBuilder, oState, oRunnerStyle); oBuilder.WriteString(L""); return; } case ENumType::FIGURE: { wsType = L"Figure"; ushValue = m_ushShapeCount; break; } case ENumType::TABLE: { wsType = L"Table"; ushValue = m_ushTableCount; break; } case ENumType::EQUATION: { wsType = L"Equation"; ushValue = m_ushEquationCount; break; } } if (0 == ushValue) return; if (!wsType.empty()) oBuilder.WriteString(L""); WriteText(std::to_wstring(ushValue), shParaShapeID, shParaStyleID, shCharShapeID, oBuilder, oState); if (!wsType.empty()) oBuilder.WriteString(L""); } HWP_STRING CConverter2OOXML::AddRelationship(const HWP_STRING& wsType, const HWP_STRING& wsTarget, TConversionState* pState) { if (wsType.empty() || wsTarget.empty()) return HWP_STRING(); VECTOR *pRelationships = nullptr; if (nullptr != pState && nullptr != pState->m_pRelationships) pRelationships = pState->m_pRelationships; else pRelationships = &m_arRelationships; VECTOR::const_iterator itFound = std::find_if(pRelationships->cbegin(), pRelationships->cend(), [wsTarget](const TRelationship& oRelationship){ return wsTarget == oRelationship.m_wsTarget; }); if (pRelationships->cend() != itFound) return itFound->m_wsID; if (L"hyperlink" == wsType) { NSStringUtils::CStringBuilder oBuilder; oBuilder.WriteEncodeXmlString(wsTarget); pRelationships->push_back({L"rId" + std::to_wstring(pRelationships->size() + 1), wsType, oBuilder.GetData()}); } else pRelationships->push_back({L"rId" + std::to_wstring(pRelationships->size() + 1), wsType, wsTarget}); return pRelationships->back().m_wsID; } void CConverter2OOXML::AddContentType(const HWP_STRING& wsName, const HWP_STRING& wsType) { if (wsName.empty() || wsType.empty()) return; VECTOR::const_iterator itFound = std::find_if(m_arContentTypes.cbegin(), m_arContentTypes.cend(), [wsName](const TContentType& oContentType){ return wsName == oContentType.m_wsName; }); if (m_arContentTypes.cend() != itFound) return; AddDefaultContentType(NSFile::GetFileExtention(wsName)); m_arContentTypes.push_back({wsName, wsType}); } void CConverter2OOXML::AddDefaultContentType(const HWP_STRING& wsName) { if (wsName.empty()) return; VECTOR::const_iterator itFound = std::find_if(m_arDefaultContentType.cbegin(), m_arDefaultContentType.cend(), [wsName](const TContentType& oContentType){ return wsName == oContentType.m_wsName; }); if (m_arDefaultContentType.cend() != itFound) return; if (IsRasterFormat(wsName)) m_arDefaultContentType.push_back({wsName, L"image/" + wsName}); else if (L"xml" == wsName) m_arDefaultContentType.push_back({wsName, L"application/xml"}); } bool CConverter2OOXML::ConvertToFile(const HWP_STRING& sFilePath) { if (nullptr == m_pContext || sFilePath.empty()) return false; CreateEmptyFiles(); Convert(); Close(); COfficeUtils oZip; oZip.CompressFileOrDirectory(m_sTempDirectory, sFilePath); return true; } bool CConverter2OOXML::ConvertToDir(const HWP_STRING& sDirectoryPath) { if (nullptr == m_pContext || sDirectoryPath.empty()) return false; HWP_STRING sCurrentTempDir{m_sTempDirectory}; SetTempDirectory(sDirectoryPath); CreateEmptyFiles(); Convert(); Close(); SetTempDirectory(sCurrentTempDir); return true; } HWP_STRING CConverter2OOXML::GetTempDirectory() const { return m_sTempDirectory; } TLineData::TLineData(ELineStyle2 eStyle, int nColor, int nThick, HWP_BYTE nCompoundLineType, ELineArrowStyle eHeadStyle, ELineArrowSize eHeadSize, ELineArrowStyle eTailStyle, ELineArrowSize eTailSize) :m_eStyle(eStyle), m_nColor(nColor), m_nThick(nThick), m_nCompoundLineType(nCompoundLineType), m_eHeadStyle(eHeadStyle), m_eHeadSize(eHeadSize), m_eTailStyle(eTailStyle), m_eTailSize(eTailSize) {} TLineData::TLineData(ELineStyle2 eStyle, int nColor, int nThick, HWP_BYTE nCompoundLineType) :m_eStyle(eStyle), m_nColor(nColor), m_nThick(nThick), m_nCompoundLineType(nCompoundLineType), m_eHeadStyle(ELineArrowStyle::NORMAL), m_eHeadSize(ELineArrowSize::SMALL_SMALL), m_eTailStyle(ELineArrowStyle::NORMAL), m_eTailSize(ELineArrowSize::SMALL_SMALL) {} }