#include "Converter2OOXML.h" #include "../../../DesktopEditor/common/File.h" #include "../../../DesktopEditor/common/Directory.h" #include "../../../DesktopEditor/common/SystemUtils.h" #include "../../../DesktopEditor/raster/BgraFrame.h" #include "../../../OfficeUtils/src/OfficeUtils.h" #include "../../../DesktopEditor/graphics/pro/Graphics.h" #include "../Paragraph/ParaText.h" #include "../Paragraph/CtrlTable.h" #include "../Paragraph/CtrlEqEdit.h" #include "../HWPElements/HWPRecordParaShape.h" #include "../HWPElements/HWPRecordCharShape.h" #include "Transform.h" #define DEFAULT_FONT_FAMILY std::wstring(L"Arial") #define DEFAULT_FONT_SIZE 18 #define DEFAULT_LANGUAGE std::wstring(L"en") #define PARA_SPACING_SCALE 0.85 #define SPACING_SCALE_MS_WORD 1.21 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) {} 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""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.WriteString(L""); m_oStylesXml.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_oStylesXml.WriteString(L""); NSFile::CFileBinary oStylesWriter; if (oStylesWriter.CreateFileW(m_sTempDirectory + L"/word/styles.xml")) { oStylesWriter.WriteStringUTF8(m_oStylesXml.GetData()); oStylesWriter.CloseFile(); } // 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""); 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; } } 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, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pCharacter) return; switch (pCharacter->GetType()) { case ECtrlCharType::PARAGRAPH_BREAK: { if (oState.m_bOpenedP) { oState.m_bOpenedP = false; oBuilder.WriteString(L""); } else WriteText(L"", shParaShapeID, pCharacter->GetCharShapeId(), oBuilder, oState); break; } case ECtrlCharType::LINE_BREAK: { oState.m_eBreakType = TConversionState::EBreakType::TextWrapping; break; } case ECtrlCharType::HARD_HYPHEN: case ECtrlCharType::HARD_SPACE: break; } } void CConverter2OOXML::WriteShape(const CCtrlGeneralShape* pShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pShape) return; switch (pShape->GetShapeType()) { case EShapeType::Arc: case EShapeType::Ellipse: case EShapeType::Rect: case EShapeType::Line: { WriteGeometryShape(pShape, oBuilder, oState); break; } case EShapeType::Pic: { WritePicture((const CCtrlShapePic*)pShape, oBuilder, oState); break; } case EShapeType::EqEdit: { WriteEqEditShape((const CCtrlEqEdit*)pShape, oBuilder, oState); break; } case EShapeType::Ole: { WriteOleShape((const CCtrlShapeOle*)pShape, oBuilder, oState); break; } case EShapeType::Video: { WriteVideo((const CCtrlShapeVideo*)pShape, oBuilder, oState); break; } case EShapeType::GeneralShape: case EShapeType::ConnectLine: case EShapeType::Container: case EShapeType::Polygon: case EShapeType::TextArt: case EShapeType::Curve: break; } } void CConverter2OOXML::WriteNote(const CCtrlNote* pNote, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { oBuilder.WriteString(L""); WriteRunnerStyle(oState.m_ushLastCharShapeId, oBuilder, oState, L""); oBuilder.WriteString(m_oFootnoteConverter.CreateNote((const CCtrlNote*)pNote, *this)); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteParagraph(const CHWPPargraph* pParagraph, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pParagraph) return; if (0 < pParagraph->GetBreakType()) { if ((0x04 == (pParagraph->GetBreakType() & 0x04)) && (0 < oState.m_unParaIndex)) { if (oState.m_bOpenedP) oBuilder.WriteString(L""); OpenParagraph(pParagraph->GetShapeID(), oBuilder, oState); oBuilder.WriteString(L""); oState.m_bOpenedP = true; ++m_ushPageCount; } else if (0x08 == (pParagraph->GetBreakType() & 0x08)) { if (oState.m_bOpenedP) oBuilder.WriteString(L""); OpenParagraph(pParagraph->GetShapeID(), oBuilder, oState); oBuilder.WriteString(L""); oState.m_bOpenedP = true; } } ++oState.m_unParaIndex; std::vector arNotes; for (const CCtrl* pCtrl : pParagraph->GetCtrls()) { switch (pCtrl->GetCtrlType()) { case ECtrlObjectType::ParaText: { WriteText(((const CParaText*)pCtrl)->GetText(), pParagraph->GetShapeID(), ((const CParaText*)pCtrl)->GetCharShapeID(), oBuilder, oState); break; } case ECtrlObjectType::Character: { WriteCharacter((const CCtrlCharacter*)pCtrl, pParagraph->GetShapeID(), oBuilder, oState); break; } case ECtrlObjectType::Shape: { WriteShape((const CCtrlGeneralShape*)pCtrl, oBuilder, oState); break; } case ECtrlObjectType::Table: { WriteTable((const CCtrlTable*)pCtrl, pParagraph->GetShapeID(), oBuilder, oState); break; } case ECtrlObjectType::Note: { arNotes.push_back((const CCtrlNote*)pCtrl); 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(), ((const CParaText*)pCtrl)->GetCharShapeID(), oBuilder, oState); break; } default: break; } if (!arNotes.empty() && ECtrlObjectType::Note != pCtrl->GetCtrlType() && oState.m_bOpenedP) { for (const CCtrlNote* pNote: arNotes) WriteNote(pNote, pParagraph->GetShapeID(), oBuilder, oState); arNotes.clear(); } } if (oState.m_bOpenedP && !arNotes.empty()) { for (const CCtrlNote* pNote: arNotes) WriteNote(pNote, pParagraph->GetShapeID(), oBuilder, oState); } CloseParagraph(oBuilder, oState); } void CConverter2OOXML::WriteParagraphProperties(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { oBuilder.WriteString(L""); WriteParaShapeProperties(shParaShapeID, oBuilder, oState); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteParaShapeProperties(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == m_pContext) return; const CHWPRecordParaShape* pParaShape = dynamic_cast(m_pContext->GetParaShape(shParaShapeID)); if (nullptr == pParaShape) return; if (pParaShape->GetPageBreakBefore()) oState.m_eBreakType = TConversionState::EBreakType::Page; oBuilder.WriteString(L"KeepWithNext()) ? L"true" : L"false") + L"\"/>"); switch(pParaShape->GetHorizantalAlign()) { case EHorizontalAlign::JUSTIFY: oBuilder.WriteString(L""); break; case EHorizontalAlign::LEFT: oBuilder.WriteString(L""); break; case EHorizontalAlign::RIGHT: oBuilder.WriteString(L""); break; case EHorizontalAlign::CENTER: oBuilder.WriteString(L""); break; case EHorizontalAlign::DISTRIBUTE: case EHorizontalAlign::DISTRIBUTE_SPACE: oBuilder.WriteString(L""); break; } switch(pParaShape->GetVerticalAlign()) { case EVerticalAlign::BOTTOM: oBuilder.WriteString(L""); break; case EVerticalAlign::TOP: oBuilder.WriteString(L""); break; case EVerticalAlign::CENTER: oBuilder.WriteString(L""); break; case EVerticalAlign::BASELINE: break; } int nLineSpacing = 240; HWP_STRING sType = L"auto"; switch(pParaShape->GetLineSpacingType()) { case 0x0: { sType = L"auto"; nLineSpacing = static_cast(240. * (double)pParaShape->GetLineSpacing() / 100.); // TODO:: в hwp изначально межстрочный интервал меньше. Множитель 1 в hwp ≈ 0.65 MS break; } case 0x01: { sType = L"exact"; nLineSpacing = static_cast((double)pParaShape->GetLineSpacing() / 2. * 20)/*0.352778*/; //(1pt=0.352778mm) //TODO:: проверить, как найдется пример break; break; } case 0x02: case 0x03: default: { sType = L"atLeast"; nLineSpacing = static_cast((double)pParaShape->GetLineSpacing()); //TODO:: проверить, как найдется пример break; } } oBuilder.WriteString(L"((double)pParaShape->GetMarginPrev() / 10.)) + L"\" w:after=\"" + std::to_wstring(static_cast((double)pParaShape->GetMarginNext() / 10.)) + L"\"/>"); switch (pParaShape->GetHeadingType()) { case EHeadingType::NUMBER: case EHeadingType::BULLET: { const int nNumId = m_oNumberingConverter.CreateNumbering(dynamic_cast(m_pContext->GetNumbering(pParaShape->GetHeadingIdRef())), pParaShape->GetHeadingType()); if (0 == nNumId) break; oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); break; } case EHeadingType::OUTLINE: case EHeadingType::NONE: break; } } void CConverter2OOXML::WriteTable(const CCtrlTable* pTable, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pTable || pTable->Empty()) return; ++m_ushTableCount; oBuilder.WriteString(L""); WriteTableProperties(pTable, shParaShapeID, 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""); } void CConverter2OOXML::WriteTableProperties(const CCtrlTable* pTable, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pTable) return; oBuilder.WriteString(L""); oBuilder.WriteString(L""); WriteParaShapeProperties(shParaShapeID, 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()) { TConversionState oCellState; // Так как даже в пустой ячейки нужен параграф, то открываем его заранее, чтобы он 100% был (закроется он автоматически в WriteParagraph) OpenParagraph(pParagraph->GetShapeID(), oBuilder, oCellState); WriteParagraph(pParagraph, oBuilder, oCellState); } } 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() && pBorderFill->GetFill()->ColorFill()) oBuilder.WriteString(L"GetFill()->GetFaceColor()) + L"\"/>"); oBuilder.WriteString(L""); WriteCellBorder(pBorderFill->GetTopBorder(), L"top", oBuilder); WriteCellBorder(pBorderFill->GetLeftBorder(), L"left", oBuilder); WriteCellBorder(pBorderFill->GetBottomBorder(), L"bottom", oBuilder); WriteCellBorder(pBorderFill->GetRightBorder(), L"right", oBuilder); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteCellBorder(const TBorder& oBorder, const HWP_STRING& sBorderName, NSStringUtils::CStringBuilder& oBuilder) { if (0x00 == oBorder.m_chWidth || 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"thickThinMediumGap"; break; case ELineStyle2::SLIM_THICK: sType = L"thickThinMediumGap"; break; case ELineStyle2::THICK_SLIM: sType = L"thickThinMediumGap"; break; case ELineStyle2::SLIM_THICK_SLIM: sType = L"thickThinMediumGap"; break; break; } oBuilder.WriteString(L""); } void CConverter2OOXML::WriteGeometryShape(const CCtrlGeneralShape* pGeneralShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pGeneralShape) return; EShapeObjectType eShapeType = GetShapeObjectType(pGeneralShape->GetID()); if (EShapeObjectType::Unknown == eShapeType) return; const std::wstring wsWidth = std::to_wstring(Transform::HWPUINT2OOXML(pGeneralShape->GetWidth())); const std::wstring wsHeight = std::to_wstring(Transform::HWPUINT2OOXML(pGeneralShape->GetHeight())); if (!oState.m_bOpenedP) oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); OpenDrawingNode(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: { oBuilder.WriteString(L""); break; } case EShapeObjectType::Ellipse: { oBuilder.WriteString(L""); break; } case EShapeObjectType::Line: { oBuilder.WriteString(L""); break; } case EShapeObjectType::Rectangle: { oBuilder.WriteString(L""); break; } case EShapeObjectType::Curve: case EShapeObjectType::Ole: case EShapeObjectType::Picture: case EShapeObjectType::Polygon: 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()); 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; 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""); if (!oState.m_bOpenedP) oBuilder.WriteString(L""); } void CConverter2OOXML::WriteEqEditShape(const CCtrlEqEdit* pEqEditShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { //TODO:: добавить конвертацию eqn формулы в ooxml ++m_ushEquationCount; if (!oState.m_bOpenedP) { oBuilder.WriteString(L""); oState.m_bOpenedP = true; } oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteEncodeXmlString(pEqEditShape->GetEqn()); oBuilder.WriteString(L""); } void CConverter2OOXML::WriteOleShape(const CCtrlShapeOle* pOleShape, 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; 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"); if (!oState.m_bOpenedP) oBuilder.WriteString(L""); oBuilder.WriteString(L""); OpenDrawingNode(pOleShape, oBuilder); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); CloseDrawingNode(pOleShape, oBuilder); oBuilder.WriteString(L""); if (!oState.m_bOpenedP) 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::WriteSectionSettings(TConversionState& oState) { m_oDocXml.WriteString(L""); if (nullptr != oState.m_pSectionDef) { for (const CCtrlHeadFoot* pCtrlHeadFoot : oState.m_pSectionDef->GetHeaderFooters()) { const std::wstring wsID = m_oFootnoteConverter.CreateHeadOrFoot((const CCtrlHeadFoot*)pCtrlHeadFoot, *this); if (!wsID.empty() && wsID.length() > 6) { const std::wstring wsType = wsID.substr(0, 6); AddContentType(wsID, L"application/vnd.openxmlformats-officedocument.wordprocessingml." + wsType + L"+xml"); m_oDocXml.WriteString(L""); } } } if (nullptr != oState.m_pColumnDef && 1 < oState.m_pColumnDef->GetColCount()) { //TODO:: Добавить поддержку остальный свойств m_oDocXml.WriteString(L"GetColCount()) + L"\" w:space=\"454\" w:equalWidth=\"true\""); if (ELineStyle2::NONE != oState.m_pColumnDef->GetColLineStyle()) m_oDocXml.WriteString(L" w:sep=\"true\""); m_oDocXml.WriteString(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())) + L"\" w:right=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginRight())) + L"\" w:bottom=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginBottom())) + 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"\"/>"); } m_oDocXml.WriteString(L""); m_oDocXml.WriteString(L""); m_oDocXml.WriteString(L""); } void CConverter2OOXML::WritePicture(const CCtrlShapePic* pCtrlPic, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState) { if (nullptr == pCtrlPic) return; HWP_STRING sPictureID = SavePicture(pCtrlPic->GetBinDataID()); if (sPictureID.empty()) return; if (!oState.m_bOpenedP) oBuilder.WriteString(L""); 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"GetFinalWidth())) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlPic->GetFinalHeight())) + L"\"/>"); oBuilder.WriteString(L""); WriteBorderSettings(pCtrlPic, oBuilder); oBuilder.WriteString(L""); CloseDrawingNode(pCtrlPic, oBuilder); oBuilder.WriteString(L""); if (!oState.m_bOpenedP) oBuilder.WriteString(L""); } void CConverter2OOXML::WriteVideo(const CCtrlShapeVideo* pCtrlVideo, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState) { if (nullptr == pCtrlVideo) return; HWP_STRING sPictureID = SavePicture(pCtrlVideo->GetThumnailBinID()); if (sPictureID.empty()) return; if (!oState.m_bOpenedP) oBuilder.WriteString(L""); oBuilder.WriteString(L""); OpenDrawingNode(pCtrlVideo, oBuilder); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L""); oBuilder.WriteString(L"GetThumnailBinID() + L"\" name=\"Video " + pCtrlVideo->GetThumnailBinID() + L"\"/>"); oBuilder.WriteString(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""); if (!oState.m_bOpenedP) 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; } NSGraphics::IGraphicsRenderer* pGrRenderer = NSGraphics::Create(); pGrRenderer->SetFontManager(pSvgReader->get_FontManager()); double dX, dY, dW, dH; pSvgReader->GetBounds(&dX, &dY, &dW, &dH); if (dW < 0) dW = -dW; if (dH < 0) dH = -dH; double dOneMaxSize = (double)1000.; if (dW > dH && dW > dOneMaxSize) { dH *= (dOneMaxSize / dW); dW = dOneMaxSize; } else if (dH > dW && dH > dOneMaxSize) { dW *= (dOneMaxSize / dH); dH = dOneMaxSize; } int nWidth = static_cast(dW + 0.5); int nHeight = static_cast(dH + 0.5); double dWidth = 25.4 * nWidth / 96; double dHeight = 25.4 * nHeight / 96; unsigned char* pBgraData = (unsigned char*)malloc(nWidth * nHeight * 4); if (!pBgraData) { double dKoef = 2000.0 / (nWidth > nHeight ? nWidth : nHeight); nWidth = (int)(dKoef * nWidth); nHeight = (int)(dKoef * nHeight); dWidth = 25.4 * nWidth / 96; dHeight = 25.4 * nHeight / 96; pBgraData = (unsigned char*)malloc(nWidth * nHeight * 4); } if (!pBgraData) return false; unsigned int alfa = 0xffffff; //дефолтный тон должен быть прозрачным, а не белым //memset(pBgraData, 0xff, nWidth * nHeight * 4); for (int i = 0; i < nWidth * nHeight; i++) { ((unsigned int*)pBgraData)[i] = alfa; } CBgraFrame oFrame; oFrame.put_Data(pBgraData); oFrame.put_Width(nWidth); oFrame.put_Height(nHeight); oFrame.put_Stride(-4 * nWidth); pGrRenderer->CreateFromBgraFrame(&oFrame); pGrRenderer->SetSwapRGB(false); pGrRenderer->put_Width(dWidth); pGrRenderer->put_Height(dHeight); pSvgReader->SetTempDirectory(m_sTempDirectory); pSvgReader->DrawOnRenderer(pGrRenderer, 0, 0, dWidth, dHeight); oFrame.SaveFile(m_sTempDirectory + L"/word/media/" + sFileName, 4); oFrame.put_Data(NULL); RELEASEINTERFACE(pGrRenderer); if (pBgraData) free(pBgraData); RELEASEINTERFACE(pSvgReader); RELEASEINTERFACE(pFonts); return true; } HWP_STRING CConverter2OOXML::SavePicture(const HWP_STRING& sBinItemId) { if (nullptr == m_pContext) 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); } void CConverter2OOXML::WriteRunnerStyle(short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const HWP_STRING& sExternStyles) { if (nullptr == m_pContext) return; const CHWPRecordCharShape* pCharShape = dynamic_cast(m_pContext->GetCharShape(shCharShapeID)); if (nullptr == pCharShape) return; oState.m_ushLastCharShapeId = shCharShapeID; oBuilder.WriteString(L""); HWP_STRING sFontFamily = pCharShape->GetFontName(ELang::LATIN); HWP_STRING sFontFamilyAsian = pCharShape->GetFontName(ELang::HANGUL); if (sFontFamilyAsian.empty() && !sFontFamily.empty()) sFontFamilyAsian = sFontFamily; else if (!sFontFamilyAsian.empty() && sFontFamily.empty()) sFontFamily = sFontFamilyAsian; if (!sFontFamily.empty() && !sFontFamilyAsian.empty()) { oBuilder.WriteString(L""); } if (pCharShape->Bold()) oBuilder.WriteString(L""); if (pCharShape->Italic()) oBuilder.WriteString(L""); const int nHeight = static_cast(((double)(std::abs)(pCharShape->GetHeight()) * ((double)pCharShape->GetRelSize(ELang::LATIN) / 100.) / 100.) * 2.); oBuilder.WriteString(L""); oBuilder.WriteString(L"GetTextColor()) + L"\"/>"); bool bStrike = false; if (pCharShape->Underline()) { EUnderline eUnderlineType = pCharShape->GetUnderlineType(); ELineStyle1 eUnderlineStyle = pCharShape->GetUnderlineStyle(); if (EUnderline::BOTTOM == eUnderlineType) { oBuilder.WriteString(L"GetUnderlineColor()) + L"\"/>"); } else if (EUnderline::CENTER == eUnderlineType) { if (eUnderlineStyle == ELineStyle1::DOUBLE_SLIM || eUnderlineStyle == ELineStyle1::DOUBLE_WAVE) oBuilder.WriteString(L""); else oBuilder.WriteString(L""); bStrike = true; } } if (!bStrike && pCharShape->StrikeOut()) oBuilder.WriteString(L""); double dSpacing = ((double)pCharShape->GetHeight() / 100.) * ((double)pCharShape->GetSpacing(ELang::HANGUL) / 100) * 0.8 + 0.4; dSpacing *= 20; // pt to twips (20 = 1440 / 72) oBuilder.WriteString(L""); oBuilder.WriteString(sExternStyles); 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::OpenDrawingNode(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlShape) return; oBuilder.WriteString(L""); if (pCtrlShape->GetTreatAsChar()) { oBuilder.WriteString(L"GetTopMargin() / 10)) + L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomMargin() / 10)) + L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftMargin() / 10)) + L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightMargin() / 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->GetTopMargin() / 10)) + L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomMargin() / 10)) + L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftMargin() / 10)) + L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightMargin() / 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 CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlShape) return; if (pCtrlShape->GetTreatAsChar()) oBuilder.WriteString(L""); else { oBuilder.WriteString(L"00"); 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"character"; } } 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""); oBuilder.WriteString(L"GetHorzRelTo()) + L"\">" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetHorzOffset())) + L""); oBuilder.WriteString(L"GetVertRelTo()) + L"\">" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetVertOffset())) + L""); } void CConverter2OOXML::WriteShapeExtent(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) { if (nullptr == pCtrlShape) return; oBuilder.WriteString(L"GetWidth())) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetHeight())) + 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: { oBuilder.WriteString(L""); break; } } } void CConverter2OOXML::OpenParagraph(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (oState.m_bOpenedP) return; oBuilder.WriteString(L""); oState.m_bOpenedP = true; WriteParagraphProperties(shParaShapeID, oBuilder, oState); } void CConverter2OOXML::CloseParagraph(NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (!oState.m_bOpenedP) return; oBuilder.WriteString(L""); oState.m_bOpenedP = false; } 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 std::wstring& wsText, short shParaShapeID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { OpenParagraph(shParaShapeID, oBuilder, oState); if (wsText.empty()) { oBuilder.WriteString(L""); WriteRunnerStyle(shCharShapeID, oBuilder, oState); oBuilder.WriteString(L""); return; } oBuilder.WriteString(L""); WriteRunnerStyle(shCharShapeID, oBuilder, oState); oBuilder.WriteString(L""); oBuilder.WriteEncodeXmlString(wsText); oBuilder.WriteString(L""); return; for (const std::wstring& wsTextElement : SplitText(wsText)) { oBuilder.WriteString(L""); WriteRunnerStyle(shCharShapeID, oBuilder, oState); 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, oBuilder); } void CConverter2OOXML::WriteLineSettings(ELineStyle2 eLineStyle, int nColor, int nThick, HWP_BYTE nCompoundLineType, NSStringUtils::CStringBuilder& oBuilder) { if (ELineStyle2::NONE == eLineStyle || 0 >= nThick) { oBuilder.WriteString(L""); return; } oBuilder.WriteString(L""); oBuilder.WriteString(L""); switch (eLineStyle) { 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; } switch (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) return; WriteLineSettings(pCtrlPic->GetBorderLineStyle(), pCtrlPic->GetBorderColor(), pCtrlPic->GetBorderThick(), pCtrlPic->GetBorderCompoundLineType(), oBuilder); } void CConverter2OOXML::WriteAutoNumber(const CCtrlAutoNumber* pAutoNumber,short shParaShapeID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState) { if (nullptr == pAutoNumber) return; unsigned short ushValue = 0; //TODO:: лучше перейти не на ручной подсчет, а на автоматический в word (но там есть свои проблемы) switch (pAutoNumber->GetNumType()) { case ENumType::PAGE: case ENumType::TOTAL_PAGE: ushValue = m_ushPageCount; break; case ENumType::FOOTNOTE: ushValue = m_oFootnoteConverter.GetFootnoteCount(); break; case ENumType::ENDNOTE: ushValue = m_oFootnoteConverter.GetEndnoteCount(); break; case ENumType::FIGURE: ushValue = m_ushShapeCount; break; case ENumType::TABLE: ushValue = m_ushTableCount; break; case ENumType::EQUATION: ushValue = m_ushEquationCount; break; } if (0 == ushValue) return; WriteText(std::to_wstring(ushValue), shParaShapeID, shCharShapeID, oBuilder, oState); } HWP_STRING CConverter2OOXML::AddRelationship(const HWP_STRING& wsType, const HWP_STRING& wsTarget) { if (wsType.empty() || wsTarget.empty()) return HWP_STRING(); VECTOR::const_iterator itFound = std::find_if(m_arRelationships.cbegin(), m_arRelationships.cend(), [wsTarget](const TRelationship& oRelationship){ return wsTarget == oRelationship.m_wsTarget; }); if (m_arRelationships.cend() != itFound) return itFound->m_wsID; m_arRelationships.push_back({L"rId" + std::to_wstring(m_arRelationships.size() + 1), wsType, wsTarget}); return m_arRelationships.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; } TConversionState::TConversionState() : m_bOpenedP(false), m_bOpenedR(false), m_ushLastCharShapeId(-1), m_ushSecdIndex(0), m_unParaIndex(0), m_pSectionDef(nullptr), m_pColumnDef(nullptr), m_eBreakType(EBreakType::None) {} }