From b78e2cb33c73e8fa5fde329ceded1e57a16da310 Mon Sep 17 00:00:00 2001 From: Green Date: Fri, 17 Jan 2025 02:42:21 +0300 Subject: [PATCH] Adding parsing of hwpx format elements --- HwpFile/HWPFile.cpp | 32 +- HwpFile/HWPFile.h | 13 +- HwpFile/HWPFile.pro | 4 +- HwpFile/HwpDoc/Common/Common.h | 6 + HwpFile/HwpDoc/Conversion/Converter2OOXML.cpp | 367 +++++++++--------- HwpFile/HwpDoc/Conversion/Converter2OOXML.h | 8 +- HwpFile/HwpDoc/Conversion/WriterContext.cpp | 169 ++++++-- HwpFile/HwpDoc/Conversion/WriterContext.h | 15 +- HwpFile/HwpDoc/HWPDocInfo.cpp | 87 ++++- HwpFile/HwpDoc/HWPDocInfo.h | 11 +- .../HWPElements/HWPRecordBorderFill.cpp | 6 +- .../HwpDoc/HWPElements/HWPRecordBorderFill.h | 1 - HwpFile/HwpDoc/HWPFile_Private.cpp | 22 +- HwpFile/HwpDoc/HWPFile_Private.h | 4 +- HwpFile/HwpDoc/HWPSection.cpp | 12 + HwpFile/HwpDoc/HWPSection.h | 1 + HwpFile/HwpDoc/HWPXFile_Private.cpp | 159 ++++++++ HwpFile/HwpDoc/HWPXFile_Private.h | 38 ++ HwpFile/HwpDoc/HwpFileHeader.cpp | 13 + HwpFile/HwpDoc/HwpFileHeader.h | 2 + HwpFile/HwpDoc/Paragraph/CtrlGeneralShape.cpp | 2 +- HwpFile/HwpDoc/Paragraph/CtrlObjElement.cpp | 2 +- HwpFile/HwpDoc/Paragraph/HWPPargraph.cpp | 11 +- 23 files changed, 719 insertions(+), 266 deletions(-) create mode 100644 HwpFile/HwpDoc/HWPXFile_Private.cpp create mode 100644 HwpFile/HwpDoc/HWPXFile_Private.h diff --git a/HwpFile/HWPFile.cpp b/HwpFile/HWPFile.cpp index 62c882cb64..365f33876c 100644 --- a/HwpFile/HWPFile.cpp +++ b/HwpFile/HWPFile.cpp @@ -1,12 +1,12 @@ #include "HWPFile.h" -#include "HwpDoc/HWPFile_Private.h" +#include "HwpDoc/Conversion/WriterContext.h" #include "../DesktopEditor/common/File.h" #include "HwpDoc/Conversion/Converter2OOXML.h" -CHWPFile::CHWPFile(const std::wstring& wsFileName) - : m_pInternal(new HWP::CHWPFile_Private(wsFileName)) +CHWPFile::CHWPFile() + : m_pInternal(new HWP::CWriterContext()) {} CHWPFile::~CHWPFile() @@ -20,12 +20,20 @@ void CHWPFile::SetTempDirectory(const std::wstring& wsTempDirectory) m_wsTempDirectory = wsTempDirectory; } -bool CHWPFile::Open() +bool CHWPFile::OpenHWP(const std::wstring& wsFilePath) { if (nullptr == m_pInternal) return false; - return m_pInternal->Open(); + return m_pInternal->Open(wsFilePath, HWP::EHanType::HWP); +} + +bool CHWPFile::OpenHWPX(const std::wstring& wsFilePath) +{ + if (nullptr == m_pInternal) + return false; + + return m_pInternal->Open(wsFilePath, HWP::EHanType::HWPX); } void CHWPFile::Close() @@ -38,7 +46,7 @@ bool CHWPFile::ConvertToOOXML(const std::wstring& wsFilePath) { HWP::CConverter2OOXML oConverter; - oConverter.SetHWPFile(m_pInternal); + oConverter.SetContext(m_pInternal); oConverter.SetTempDirectory(m_wsTempDirectory); return oConverter.ConvertToFile(wsFilePath); @@ -48,7 +56,17 @@ bool CHWPFile::ConvertToOOXML_Dir(const std::wstring& wsDirectoryPath) { HWP::CConverter2OOXML oConverter; - oConverter.SetHWPFile(m_pInternal); + oConverter.SetContext(m_pInternal); return oConverter.ConvertToDir(wsDirectoryPath); } + +bool CHWPFile::IsHWPFormat(const std::wstring& wsFilePath) +{ + return HWP::EHanType::HWP == HWP::CWriterContext::DetectHancom(wsFilePath); +} + +bool CHWPFile::IsHWPXFormat(const std::wstring& wsFilePath) +{ + return HWP::EHanType::HWPX == HWP::CWriterContext::DetectHancom(wsFilePath); +} diff --git a/HwpFile/HWPFile.h b/HwpFile/HWPFile.h index 1af81c2f82..4d6970b412 100644 --- a/HwpFile/HWPFile.h +++ b/HwpFile/HWPFile.h @@ -10,21 +10,26 @@ #define HWP_FILE_DECL_EXPORT Q_DECL_EXPORT #endif -namespace HWP { class CHWPFile_Private; } +namespace HWP { class CWriterContext; } class HWP_FILE_DECL_EXPORT CHWPFile { - HWP::CHWPFile_Private *m_pInternal; + HWP::CWriterContext *m_pInternal; + std::wstring m_wsFileName; std::wstring m_wsTempDirectory; public: - CHWPFile(const std::wstring& wsFileName); + CHWPFile(); ~CHWPFile(); void SetTempDirectory(const std::wstring& wsTempDirectory); - bool Open(); + bool OpenHWP(const std::wstring& wsFilePath); + bool OpenHWPX(const std::wstring& wsFilePath); void Close(); bool ConvertToOOXML(const std::wstring& wsFilePath); bool ConvertToOOXML_Dir(const std::wstring& wsDirectoryPath); + + static bool IsHWPFormat(const std::wstring& wsFilePath); + static bool IsHWPXFormat(const std::wstring& wsFilePath); }; #endif // HWPFILE_H diff --git a/HwpFile/HWPFile.pro b/HwpFile/HWPFile.pro index 436c8026a7..2fca715f17 100644 --- a/HwpFile/HWPFile.pro +++ b/HwpFile/HWPFile.pro @@ -46,8 +46,8 @@ SOURCES += \ HwpDoc/HWPFile_Private.cpp \ HwpDoc/HWPSection.cpp \ HwpDoc/HWPStream.cpp \ + HwpDoc/HWPXFile_Private.cpp \ HwpDoc/HwpFileHeader.cpp \ - HwpDoc/OCFdoc/OWPMLFile.cpp \ HwpDoc/OLEdoc/CompoundFile.cpp \ HwpDoc/OLEdoc/DirectoryEntry.cpp \ HwpDoc/Paragraph/CapParagraph.cpp \ @@ -127,9 +127,9 @@ HEADERS += \ HwpDoc/HWPFile_Private.h \ HwpDoc/HWPSection.h \ HwpDoc/HWPStream.h \ + HwpDoc/HWPXFile_Private.h \ HwpDoc/HanType.h \ HwpDoc/HwpFileHeader.h \ - HwpDoc/OCFdoc/OWPMLFile.h \ HwpDoc/OLEdoc/CompoundFile.h \ HwpDoc/OLEdoc/DirectoryEntry.h \ HwpDoc/OLEdoc/Sector.h \ diff --git a/HwpFile/HwpDoc/Common/Common.h b/HwpFile/HwpDoc/Common/Common.h index c80de406f2..816a7dd93e 100644 --- a/HwpFile/HwpDoc/Common/Common.h +++ b/HwpFile/HwpDoc/Common/Common.h @@ -25,6 +25,12 @@ typedef char HWP_BYTE; #define CASE(value) case value : return value #define DEFAULT(value) case value: default: return value +#define RETURN_VECTOR_CONST_PTR(type, array_values) \ + std::vector arTempVector(array_values.size()); \ + for (unsigned int unIndex = 0; unIndex < array_values.size(); ++unIndex) \ + arTempVector[unIndex] = dynamic_cast(array_values[unIndex]); \ + return arTempVector + class IRef { unsigned long m_ulRef; diff --git a/HwpFile/HwpDoc/Conversion/Converter2OOXML.cpp b/HwpFile/HwpDoc/Conversion/Converter2OOXML.cpp index 2eafa7495e..7f41d2e776 100644 --- a/HwpFile/HwpDoc/Conversion/Converter2OOXML.cpp +++ b/HwpFile/HwpDoc/Conversion/Converter2OOXML.cpp @@ -65,15 +65,15 @@ EShapeObjectType GetShapeObjectType(const std::wstring& wsID) } CConverter2OOXML::CConverter2OOXML() - : m_pHWPFile(nullptr), m_ushShapeCount(0), m_ushPageCount(1), m_ushTableCount(0), m_ushEquationCount(0) + : m_pContext(nullptr), m_ushShapeCount(0), m_ushPageCount(1), m_ushTableCount(0), m_ushEquationCount(0) {} CConverter2OOXML::~CConverter2OOXML() {} -void CConverter2OOXML::SetHWPFile(CHWPFile_Private* pHWPFile) +void CConverter2OOXML::SetContext(CWriterContext* pContext) { - m_pHWPFile = pHWPFile; + m_pContext = pContext; } void CConverter2OOXML::SetTempDirectory(const HWP_STRING& sTempDirectory) @@ -271,16 +271,19 @@ void CConverter2OOXML::Close() void CConverter2OOXML::Convert() { + if (nullptr == m_pContext) + return; + TConversionState oState; - for (const CHWPSection* pSection : m_pHWPFile->GetSections()) + std::vector arSetcions{m_pContext->GetSections()}; + + for (const CHWPSection* pSection : arSetcions) { - const bool bIsLastSection = pSection == m_pHWPFile->GetSections().back(); + const bool bIsLastSection = pSection == arSetcions.back(); for (const CHWPPargraph *pPara : pSection->GetParagraphs()) - { WriteParagraph(pPara, m_oDocXml, oState); - } if (!bIsLastSection) m_oDocXml.WriteString(L""); @@ -364,6 +367,7 @@ void CConverter2OOXML::WriteShape(const CCtrlGeneralShape* pShape, NSStringUtils } case EShapeType::GeneralShape: case EShapeType::ConnectLine: + case EShapeType::Container: case EShapeType::Polygon: case EShapeType::TextArt: case EShapeType::Curve: @@ -486,15 +490,10 @@ void CConverter2OOXML::WriteParagraphProperties(short shParaShapeID, NSStringUti void CConverter2OOXML::WriteParaShapeProperties(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState) { - const CHWPDocInfo* pDocInfo = nullptr; - - if (nullptr != m_pHWPFile) - pDocInfo = m_pHWPFile->GetDocInfo(); - - if (nullptr == m_pHWPFile) + if (nullptr == m_pContext) return; - const CHWPRecordParaShape* pParaShape = dynamic_cast(pDocInfo->GetParaShape(shParaShapeID)); + const CHWPRecordParaShape* pParaShape = dynamic_cast(m_pContext->GetParaShape(shParaShapeID)); if (nullptr == pParaShape) return; @@ -523,29 +522,32 @@ void CConverter2OOXML::WriteParaShapeProperties(short shParaShapeID, NSStringUti int nLineSpacing = 0; HWP_STRING sType = L"auto"; - switch(pParaShape->GetLineSpacingType()) - { - case 0x0: - { - sType = L"auto"; - nLineSpacing = static_cast(240. * (double)pParaShape->GetLineSpacing() / 100.); - break; - } - case 0x01: - { - sType = L"exact"; - nLineSpacing = static_cast((double)pParaShape->GetLineSpacing() / 2. * 20)/*0.352778*/; //(1pt=0.352778mm) //TODO:: проверить, как найдется пример - break; - } - case 0x02: - case 0x03: - default: - { - sType = L"atLeast"; - nLineSpacing = static_cast((double)pParaShape->GetLineSpacing()); //TODO:: проверить, как найдется пример - break; - } - } + // switch(pParaShape->GetLineSpacingType()) + // { + // case 0x0: + // { + // sType = L"atLeast"; + // nLineSpacing = static_cast((double)pParaShape->GetLineSpacing()); + // nLineSpacing = 57; + // // nLineSpacing = static_cast(240. * (double)pParaShape->GetLineSpacing() / 100.); + // break; + // } + // case 0x01: + // { + // sType = L"exact"; + // nLineSpacing = static_cast(240. * (double)pParaShape->GetLineSpacing() / 100.); + // // nLineSpacing = static_cast((double)pParaShape->GetLineSpacing() / 2. * 20)/*0.352778*/; //(1pt=0.352778mm) //TODO:: проверить, как найдется пример + // break; + // } + // case 0x02: + // case 0x03: + // default: + // { + // sType = L"atLeast"; + // nLineSpacing = static_cast((double)pParaShape->GetLineSpacing()); //TODO:: проверить, как найдется пример + // break; + // } + // } oBuilder.WriteString(L"((double)pParaShape->GetMarginPrev() / 10.)) + @@ -556,7 +558,7 @@ void CConverter2OOXML::WriteParaShapeProperties(short shParaShapeID, NSStringUti case EHeadingType::NUMBER: case EHeadingType::BULLET: { - const int nNumId = m_oNumberingConverter.CreateNumbering(dynamic_cast(pDocInfo->GetNumbering(pParaShape->GetHeadingIdRef())), pParaShape->GetHeadingType()); + const int nNumId = m_oNumberingConverter.CreateNumbering(dynamic_cast(m_pContext->GetNumbering(pParaShape->GetHeadingIdRef())), pParaShape->GetHeadingType()); if (0 == nNumId) break; @@ -675,8 +677,8 @@ void CConverter2OOXML::WriteTableProperties(const CCtrlTable* pTable, short shPa const CHWPRecordBorderFill* pBorderFill = nullptr; - if (nullptr != m_pHWPFile) - pBorderFill = dynamic_cast(m_pHWPFile->GetDocInfo()->GetBorderFill(pTable->GetBorderFillID())); + if (nullptr != m_pContext) + pBorderFill = dynamic_cast(m_pContext->GetBorderFill(pTable->GetBorderFillID())); if (nullptr == pBorderFill) { @@ -737,8 +739,8 @@ void CConverter2OOXML::WriteCellProperties(short shBorderFillID, NSStringUtils:: { const CHWPRecordBorderFill* pBorderFill = nullptr; - if (nullptr != m_pHWPFile) - pBorderFill = dynamic_cast(m_pHWPFile->GetDocInfo()->GetBorderFill(shBorderFillID)); + if (nullptr != m_pContext) + pBorderFill = dynamic_cast(m_pContext->GetBorderFill(shBorderFillID)); if (nullptr == pBorderFill) return; @@ -914,11 +916,15 @@ void CConverter2OOXML::WriteOleShape(const CCtrlShapeOle* pOleShape, NSStringUti //TODO:: добавить конвертацию hwp ole -> ooxml chart //TODO:: необходимо добавить поддержку формата "Hwp Document File Formats - Charts" (для случаев, когда нет ooxml представления) // Пока можем вытащить лишь ooxml представление данных + // Реализовать с использованием pole.h? + + if (nullptr == m_pContext) + return; CHWPStream oBuffer; HWP_STRING sFormat; - if (!GetBinBytes(pOleShape->GetBinDataID(), oBuffer, sFormat)) + if (!m_pContext->GetBinBytes(pOleShape->GetBinDataID(), oBuffer, sFormat)) return; m_oOleConverter.CreateChart(oBuffer); @@ -1177,11 +1183,14 @@ bool CConverter2OOXML::SaveSVGFile(const HWP_STRING& sSVG, const HWP_STRING& sIn HWP_STRING CConverter2OOXML::SavePicture(const HWP_STRING& sBinItemId) { + if (nullptr == m_pContext) + return HWP_STRING(); + //TODO:: добавить поддержку устновки размеров изображения из свойств шейпа CHWPStream oBuffer; HWP_STRING sFormat; - if (!GetBinBytes(sBinItemId, oBuffer, sFormat)) + if (!m_pContext->GetBinBytes(sBinItemId, oBuffer, sFormat)) return HWP_STRING(); oBuffer.MoveToStart(); @@ -1213,96 +1222,92 @@ HWP_STRING CConverter2OOXML::SavePicture(const HWP_STRING& sBinItemId) void CConverter2OOXML::WriteRunnerStyle(short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState) { - const CHWPDocInfo* pDocInfo = nullptr; + if (nullptr == m_pContext) + return; - if (nullptr != m_pHWPFile) + const CHWPRecordCharShape* pCharShape = dynamic_cast(m_pContext->GetCharShape(shCharShapeID)); + + if (nullptr == pCharShape) + return; + + 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()) { - pDocInfo = m_pHWPFile->GetDocInfo(); - - const CHWPRecordCharShape* pCharShape = dynamic_cast(pDocInfo->GetCharShape(shCharShapeID)); - - if (nullptr == pCharShape) - return; - - 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"\"/>"); - - 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""); - } - } - - 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(L""); + 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"\"/>"); + + 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""); + } + } + + 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(L""); } void CConverter2OOXML::OpenAnchorNode(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder) @@ -1416,23 +1421,57 @@ void CConverter2OOXML::CloseParagraph(NSStringUtils::CStringBuilder& oBuilder, T oState.m_bOpenedP = false; } +std::vector SplitText(const std::wstring& wsText) +{ + if (wsText.empty()) + return std::vector(); + + 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 = iswalpha(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); - oBuilder.WriteString(L""); - - WriteRunnerStyle(shCharShapeID, oBuilder, oState); - - if (oState.m_bNeedLineBreak) + for (const std::wstring& wsTextElement : SplitText(wsText)) { - oBuilder.WriteString(L""); - oState.m_bNeedLineBreak = false; - } + oBuilder.WriteString(L""); - oBuilder.WriteString(L""); - oBuilder.WriteEncodeXmlString(wsText); - oBuilder.WriteString(L""); + WriteRunnerStyle(shCharShapeID, oBuilder, oState); + + if (oState.m_bNeedLineBreak) + { + oBuilder.WriteString(L""); + oState.m_bNeedLineBreak = false; + } + + oBuilder.WriteString(L""); + oBuilder.WriteEncodeXmlString(wsTextElement); + oBuilder.WriteString(L""); + } } void CConverter2OOXML::WriteLineSettings(const CCtrlGeneralShape* pCtrlGeneralShape, NSStringUtils::CStringBuilder& oBuilder) @@ -1579,42 +1618,6 @@ void CConverter2OOXML::WriteAutoNumber(const CCtrlAutoNumber* pAutoNumber,short WriteText(std::to_wstring(ushValue), shParaShapeID, shCharShapeID, oBuilder, oState); } -bool CConverter2OOXML::GetBinBytes(const HWP_STRING& sID, CHWPStream& oBuffer, HWP_STRING& sFormat) -{ - const CHWPDocInfo* pDocInfo = nullptr; - - if (nullptr != m_pHWPFile) - { - pDocInfo = m_pHWPFile->GetDocInfo(); - - const CHWPRecordBinData* pBinData = dynamic_cast(pDocInfo->GetBinData(sID)); - - if (nullptr == pBinData) - return false; - - if (EType::LINK == pBinData->GetType()) - { - NSFile::CFileBinary oFile; - unsigned char *pBuffer = nullptr; - unsigned long ulSize = 0; - - oFile.ReadAllBytes(pBinData->GetPath(), &pBuffer, ulSize); - oBuffer.SetStream((HWP_BYTE*)pBuffer, ulSize, false); - sFormat = NSFile::GetFileExtention(pBinData->GetPath()); - } - else - { - std::wostringstream oStringStream; - oStringStream << L"BIN" << std::setw(4) << std::setfill(L'0') << std::hex << pBinData->GetBinDataID() << L"." << pBinData->GetFormat(); - sFormat = pBinData->GetFormat(); - - return m_pHWPFile->GetChildStream(oStringStream.str(), pBinData->GetCompressed(), oBuffer); - } - } - - return true; -} - HWP_STRING CConverter2OOXML::AddRelationship(const HWP_STRING& wsType, const HWP_STRING& wsTarget) { if (wsType.empty() || wsTarget.empty()) @@ -1635,7 +1638,7 @@ void CConverter2OOXML::AddContentType(const HWP_STRING& wsName, const HWP_STRING bool CConverter2OOXML::ConvertToFile(const HWP_STRING& sFilePath) { - if (nullptr == m_pHWPFile || sFilePath.empty()) + if (nullptr == m_pContext || sFilePath.empty()) return false; CreateEmptyFiles(); @@ -1650,15 +1653,19 @@ bool CConverter2OOXML::ConvertToFile(const HWP_STRING& sFilePath) bool CConverter2OOXML::ConvertToDir(const HWP_STRING& sDirectoryPath) { - if (nullptr == m_pHWPFile || sDirectoryPath.empty()) + if (nullptr == m_pContext || sDirectoryPath.empty()) return false; + HWP_STRING sCurrentTempDir{m_sTempDirectory}; + SetTempDirectory(sDirectoryPath); CreateEmptyFiles(); Convert(); Close(); + SetTempDirectory(sCurrentTempDir); + return true; } diff --git a/HwpFile/HwpDoc/Conversion/Converter2OOXML.h b/HwpFile/HwpDoc/Conversion/Converter2OOXML.h index 539204a68e..51700ce2fb 100644 --- a/HwpFile/HwpDoc/Conversion/Converter2OOXML.h +++ b/HwpFile/HwpDoc/Conversion/Converter2OOXML.h @@ -17,6 +17,8 @@ #include "OleConverter.h" #include "NumberingConverter.h" +#include "WriterContext.h" + namespace HWP { struct TConversionState @@ -50,7 +52,7 @@ enum class ECellCreator class CConverter2OOXML { - CHWPFile_Private *m_pHWPFile; + CWriterContext * m_pContext; HWP_STRING m_sTempDirectory; NSStringUtils::CStringBuilder m_oStylesXml; // styles.xml @@ -113,8 +115,6 @@ class CConverter2OOXML void WriteCharacter(const CCtrlCharacter* pCharacter, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState); void WriteShape(const CCtrlGeneralShape* pShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState); - bool GetBinBytes(const HWP_STRING& sID, CHWPStream& oBuffer, HWP_STRING& sFormat); - HWP_STRING AddRelationship(const HWP_STRING& wsType, const HWP_STRING& wsTarget); void AddContentType(const HWP_STRING& wsName, const HWP_STRING& wsType); public: @@ -123,7 +123,7 @@ public: void WriteParagraph(const CHWPPargraph* pParagraph, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState); - void SetHWPFile(CHWPFile_Private* pHWPFile); + void SetContext(CWriterContext* pContext); void SetTempDirectory(const HWP_STRING& sTempDirectory); bool ConvertToFile(const HWP_STRING& sFilePath); bool ConvertToDir(const HWP_STRING& sDirectoryPath); diff --git a/HwpFile/HwpDoc/Conversion/WriterContext.cpp b/HwpFile/HwpDoc/Conversion/WriterContext.cpp index 9b95b9c995..e71f3ab8e5 100644 --- a/HwpFile/HwpDoc/Conversion/WriterContext.cpp +++ b/HwpFile/HwpDoc/Conversion/WriterContext.cpp @@ -1,19 +1,26 @@ #include "WriterContext.h" #include "../HWPFile_Private.h" +#include "../HWPXFile_Private.h" + +#include +#include namespace HWP { CWriterContext::CWriterContext() - : m_eType(EHanType::NONE), m_pHWPFile(nullptr) + : m_eType(EHanType::NONE), m_pHWPFile(nullptr), m_pHWPXFile(nullptr) {} CWriterContext::~CWriterContext() { if (nullptr != m_pHWPFile) delete m_pHWPFile; + + if (nullptr != m_pHWPXFile) + delete m_pHWPXFile; } -VECTOR CWriterContext::GetSections() +VECTOR CWriterContext::GetSections() { switch(m_eType) { @@ -26,34 +33,52 @@ VECTOR CWriterContext::GetSections() break; } case EHanType::HWPX: + { + if(nullptr != m_pHWPXFile) + return m_pHWPXFile->GetSections(); + break; + } } - return VECTOR(); + return VECTOR(); } -HWP_STRING CWriterContext::DetectHancom(const HWP_STRING& sPathToFile) +EHanType CWriterContext::DetectHancom(const HWP_STRING& sPathToFile) { - HWP_STRING sDetectingType; + bool bDetected = false; CHWPFile_Private* pHwpTemp = new CHWPFile_Private(sPathToFile); if (nullptr != pHwpTemp) { if (pHwpTemp->Detect()) { - sDetectingType = L"HWP"; + bDetected = true; pHwpTemp->Close(); } delete pHwpTemp; } - if (!sDetectingType.empty()) - return sDetectingType; + if (bDetected) + return EHanType::HWP; - //TODO:: добавить HWPX + CHWPXFile_Private* pHwpxTemp = new CHWPXFile_Private(sPathToFile); + if (nullptr != pHwpxTemp) + { + if (pHwpxTemp->Detect()) + { + bDetected = true; + pHwpxTemp->Close(); + } - return sDetectingType; + delete pHwpxTemp; + } + + if (bDetected) + return EHanType::HWPX; + + return EHanType::NONE; } bool CWriterContext::Detect() @@ -67,23 +92,44 @@ bool CWriterContext::Detect() return m_pHWPFile->Detect(); } - case EHanType::NONE: case EHanType::HWPX: + { + if (nullptr == m_pHWPXFile) + return false; + + return m_pHWPXFile->Detect(); + } + case EHanType::NONE: return false; } } -bool CWriterContext::Open(const HWP_STRING& sPathToFile, const HWP_STRING& sHanType) +bool CWriterContext::Open(const HWP_STRING& sPathToFile, EHanType eHanType) { - if (L"HWP" == sHanType) + m_eType = eHanType; + + switch (m_eType) { - m_eType = EHanType::HWP; - m_pHWPFile = new CHWPFile_Private(sPathToFile); + case EHanType::HWP: + { + m_pHWPFile = new CHWPFile_Private(sPathToFile); - if (nullptr == m_pHWPFile) - return false; + if (nullptr == m_pHWPFile) + return false; - return m_pHWPFile->Open(); + return m_pHWPFile->Open(); + } + case EHanType::HWPX: + { + m_pHWPXFile = new CHWPXFile_Private(sPathToFile); + + if (nullptr == m_pHWPXFile) + return false; + + return m_pHWPXFile->Open(); + } + case EHanType::NONE: + break; } return false; @@ -99,8 +145,13 @@ void CWriterContext::Close() m_pHWPFile->Close(); break; } - case EHanType::NONE: case EHanType::HWPX: + { + if (nullptr != m_pHWPXFile) + m_pHWPXFile->Close(); + break; + } + case EHanType::NONE: break; } } @@ -116,8 +167,14 @@ const CHWPDocInfo* CWriterContext::GetDocInfo() return m_pHWPFile->GetDocInfo(); } - case EHanType::NONE: case EHanType::HWPX: + { + if (nullptr == m_pHWPXFile) + return nullptr; + + return m_pHWPXFile->GetDocInfo(); + } + case EHanType::NONE: return nullptr; } } @@ -194,14 +251,76 @@ const CHwpRecordTabDef* CWriterContext::GetTabDef(short shId) HWP_STRING CWriterContext::GetBinFilename(const HWP_STRING& sId) { - //TODO::реализовать - return HWP_STRING(); + const CHWPDocInfo* pDocInfo = GetDocInfo(); + + if (nullptr == pDocInfo) + return HWP_STRING(); + + const CHWPRecordBinData* pBinData = dynamic_cast(pDocInfo->GetBinData(sId)); + + return (nullptr != pBinData) ? pBinData->GetPath() : HWP_STRING(); } -bool CWriterContext::GetBinBytes(const HWP_STRING& sId, CHWPStream& oBuffer) +bool CWriterContext::GetBinBytes(const HWP_STRING& sId, CHWPStream& oBuffer, HWP_STRING& sFormat) { - //TODO::реализовать - return false; + const CHWPDocInfo* pDocInfo = nullptr; + + switch (m_eType) + { + case EHanType::HWP: + { + if (nullptr == m_pHWPFile) + return false; + + pDocInfo = m_pHWPFile->GetDocInfo(); + + if (nullptr == pDocInfo) + return false; + + const CHWPRecordBinData* pBinData = dynamic_cast(pDocInfo->GetBinData(sId)); + + if (nullptr == pBinData) + return false; + + if (EType::LINK == pBinData->GetType()) + { + NSFile::CFileBinary oFile; + unsigned char *pBuffer = nullptr; + unsigned long ulSize = 0; + + oFile.ReadAllBytes(pBinData->GetPath(), &pBuffer, ulSize); + oBuffer.SetStream((HWP_BYTE*)pBuffer, ulSize, false); + sFormat = NSFile::GetFileExtention(pBinData->GetPath()); + } + else + { + std::wostringstream oStringStream; + oStringStream << L"BIN" << std::setw(4) << std::setfill(L'0') << std::hex << pBinData->GetBinDataID() << L"." << pBinData->GetFormat(); + sFormat = pBinData->GetFormat(); + + return m_pHWPFile->GetChildStream(oStringStream.str(), pBinData->GetCompressed(), oBuffer); + } + } + case EHanType::HWPX: + { + if (nullptr == m_pHWPXFile) + return false; + + pDocInfo = m_pHWPXFile->GetDocInfo(); + + if (nullptr == pDocInfo) + return false; + + const CHWPRecordBinData* pBinData = dynamic_cast(pDocInfo->GetBinData(sId)); + + if (nullptr == pBinData) + return false; + + //TODO:: реализовать + } + case EHanType::NONE: + return false; + } } HWP_STRING CWriterContext::GetBinFormat(const HWP_STRING& sId) diff --git a/HwpFile/HwpDoc/Conversion/WriterContext.h b/HwpFile/HwpDoc/Conversion/WriterContext.h index a203c25034..5ce90f22a7 100644 --- a/HwpFile/HwpDoc/Conversion/WriterContext.h +++ b/HwpFile/HwpDoc/Conversion/WriterContext.h @@ -1,9 +1,9 @@ #ifndef WRITERCONTEXT_H #define WRITERCONTEXT_H -#include "../HWPFile.h" #include "../HanType.h" -#include "../HWPSection.h" +#include "../HWPFile_Private.h" +#include "../HWPXFile_Private.h" #include "../HWPElements/HWPRecordParaShape.h" #include "../HWPElements/HWPRecordStyle.h" @@ -17,16 +17,17 @@ namespace HWP class CWriterContext { EHanType m_eType; - CHWPFile_Private* m_pHWPFile; + CHWPFile_Private* m_pHWPFile; + CHWPXFile_Private* m_pHWPXFile; int m_nVersion; public: CWriterContext(); ~CWriterContext(); - VECTOR GetSections(); - HWP_STRING DetectHancom(const HWP_STRING& sPathToFile); + VECTOR GetSections(); + static EHanType DetectHancom(const HWP_STRING& sPathToFile); bool Detect(); - bool Open(const HWP_STRING& sPathToFile, const HWP_STRING& sHanType); + bool Open(const HWP_STRING& sPathToFile, EHanType eHanType); void Close(); const CHWPDocInfo* GetDocInfo(); @@ -39,7 +40,7 @@ public: const CHwpRecordTabDef* GetTabDef(short shId); HWP_STRING GetBinFilename(const HWP_STRING& sId); - bool GetBinBytes(const HWP_STRING& sId, CHWPStream& oBuffer); + bool GetBinBytes(const HWP_STRING& sId, CHWPStream& oBuffer, HWP_STRING& sFormat); HWP_STRING GetBinFormat(const HWP_STRING& sId); }; } diff --git a/HwpFile/HwpDoc/HWPDocInfo.cpp b/HwpFile/HwpDoc/HWPDocInfo.cpp index 4ab9dd3cfb..17ca1cd56e 100644 --- a/HwpFile/HwpDoc/HWPDocInfo.cpp +++ b/HwpFile/HwpDoc/HWPDocInfo.cpp @@ -30,9 +30,9 @@ CHWPDocInfo::CHWPDocInfo(EHanType eHanType) : m_eHanType(eHanType), m_eCompatibleDoc(ECompatDoc::HWP) {} -// CHWPDocInfo::CHWPDocInfo(CHWPXFile* pHWPXFile) -// : m_eHanType(EHanType::HWPX), m_pParentHWPX(pHWPXFile) -// {} +CHWPDocInfo::CHWPDocInfo(CHWPXFile_Private* pHWPXFile) + : m_eHanType(EHanType::HWPX), m_pParentHWPX(pHWPXFile), m_eCompatibleDoc(ECompatDoc::UNKNOWN) +{} CHWPDocInfo::CHWPDocInfo(CHWPFile_Private* pHWPFile) : m_eHanType(EHanType::HWP), m_pParentHWP(pHWPFile), m_eCompatibleDoc(ECompatDoc::HWP) @@ -58,7 +58,7 @@ CHWPDocInfo::~CHWPDocInfo() REMOVE_LIST_DATA(m_arStyles); REMOVE_LIST_DATA(m_arTabDefs); - for (std::pair oBinData : m_mBinDatas) + for (const std::pair& oBinData : m_mBinDatas) { if (nullptr != oBinData.second) delete oBinData.second; @@ -182,6 +182,85 @@ bool CHWPDocInfo::Parse(CHWPStream& oBuffer, int nVersion) return true; } +bool CHWPDocInfo::Parse(CXMLNode& oNode, int nVersion) +{ + for (CXMLNode& oChild : oNode.GetChilds()) + { + if (L"hh:beginNum" == oChild.GetName()) + m_arRecords.push_back(new CHWPRecordDocumentProperties(*this, oChild, nVersion)); + else if (L"hh:refList" == oChild.GetName()) + ReadRefList(oChild, nVersion); + } + + return true; +} + +bool CHWPDocInfo::ReadRefList(CXMLNode& oNode, int nVersion) +{ + for (CXMLNode& oChild : oNode.GetChilds()) + { + if (L"hh:fontfaces" == oChild.GetName()) + { + for (CXMLNode& oFontFaceNode : oChild.GetChilds(L"hh:fontface")) + for (CXMLNode& oFontNode : oFontFaceNode.GetChilds(L"hh:font")) + m_arFaseNames.push_back(new CHWPRecordFaceName(*this, oFontNode, nVersion)); + } + else if (L"hh:borderFills" == oChild.GetName()) + { + for (CXMLNode& oBorderFillNode : oChild.GetChilds(L"hh:borderFill")) + m_arBorderFills.push_back(new CHWPRecordBorderFill(*this, oBorderFillNode, nVersion)); + } + else if (L"hh:charProperties" == oChild.GetName()) + { + for (CXMLNode& oCharPrNode : oChild.GetChilds(L"hh:charPr")) + m_arCharShapes.push_back(new CHWPRecordCharShape(*this, oCharPrNode, nVersion)); + } + else if (L"hh:tabProperties" == oChild.GetName()) + { + for (CXMLNode& oTabPrNode : oChild.GetChilds(L"hh:tabPr")) + m_arTabDefs.push_back(new CHwpRecordTabDef(*this, oTabPrNode, nVersion)); + } + else if (L"hh:numberings" == oChild.GetName()) + { + for (CXMLNode& oNumberingNode : oChild.GetChilds(L"hh:numbering")) + m_arNumberings.push_back(new CHWPRecordNumbering(*this, oNumberingNode, nVersion)); + } + else if (L"hh:bullets" == oChild.GetName()) + { + for (CXMLNode& oBulletNode : oChild.GetChilds()) + m_arBullets.push_back(new CHWPRecordBullet(*this, oBulletNode, nVersion)); + } + else if (L"hh:paraProperties" == oChild.GetName()) + { + for (CXMLNode& oParaPrNode : oChild.GetChilds(L"hh:paraPr")) + m_arParaShapes.push_back(new CHWPRecordParaShape(*this, oParaPrNode, nVersion)); + } + else if (L"hh:styles" == oChild.GetName()) + { + for (CXMLNode& oStyleNode : oChild.GetChilds(L"hh:style")) + m_arStyles.push_back(new CHWPRecordStyle(*this, oStyleNode, nVersion)); + } + } + + return true; +} + +bool CHWPDocInfo::ReadContentHpf(CXMLNode& oNode, int nVersion) +{ + CHWPRecordBinData *pRecordBinData = nullptr; + + for (CXMLNode& oChild : oNode.GetChilds(L"opf:manifest")) + { + for (CXMLNode& oGrandChild : oChild.GetChilds(L"opf:item")) + { + pRecordBinData = new CHWPRecordBinData(oGrandChild, nVersion); + m_mBinDatas.insert(std::make_pair(pRecordBinData->GetItemID(), pRecordBinData)); + } + } + + return true; +} + #define GET_RECORD(array_records, index) \ if (array_records.size() <= index) \ return nullptr; \ diff --git a/HwpFile/HwpDoc/HWPDocInfo.h b/HwpFile/HwpDoc/HWPDocInfo.h index e3f459be4e..2630bd3ff1 100644 --- a/HwpFile/HwpDoc/HWPDocInfo.h +++ b/HwpFile/HwpDoc/HWPDocInfo.h @@ -4,7 +4,7 @@ #include "HanType.h" #include "HWPStream.h" #include "HWPElements/HWPRecord.h" - +#include "Common/XMLNode.h" #include @@ -19,10 +19,11 @@ enum class ECompatDoc }; class CHWPFile_Private; +class CHWPXFile_Private; class CHWPDocInfo { EHanType m_eHanType; - // CHWPXFile *m_pParentHWPX; + CHWPXFile_Private *m_pParentHWPX; CHWPFile_Private *m_pParentHWP; VECTOR m_arRecords; @@ -39,12 +40,14 @@ class CHWPDocInfo ECompatDoc m_eCompatibleDoc; public: CHWPDocInfo(EHanType eHanType); - // CHWPDocInfo(CHWPXFile* pHWPXFile); + CHWPDocInfo(CHWPXFile_Private* pHWPXFile); CHWPDocInfo(CHWPFile_Private* pHWPFile); ~CHWPDocInfo(); bool Parse(CHWPStream& oBuffer, int nVersion); + bool Parse(CXMLNode& oNode, int nVersion); + bool ReadContentHpf(CXMLNode& oNode, int nVersion); const CHWPRecord* GetRecord(int nIndex) const; const CHWPRecord* GetFaceName(int nIndex) const; @@ -61,6 +64,8 @@ public: const CHWPRecord* GetBinData(const HWP_STRING& sID) const; EHanType GetHanType() const; ECompatDoc GetCompatibleDoc() const; +private: + bool ReadRefList(CXMLNode& oNode, int nVersion); }; } diff --git a/HwpFile/HwpDoc/HWPElements/HWPRecordBorderFill.cpp b/HwpFile/HwpDoc/HWPElements/HWPRecordBorderFill.cpp index 80e02e29df..5372c44738 100644 --- a/HwpFile/HwpDoc/HWPElements/HWPRecordBorderFill.cpp +++ b/HwpFile/HwpDoc/HWPElements/HWPRecordBorderFill.cpp @@ -264,11 +264,11 @@ HWP_STRING CFill::GetBinItemID() const } CHWPRecordBorderFill::CHWPRecordBorderFill(int nTagNum, int nLevel, int nSize) - : CHWPRecord(nTagNum, nLevel, nSize), m_pParent(nullptr), m_pFill(nullptr) + : CHWPRecord(nTagNum, nLevel, nSize), m_pFill(nullptr) {} CHWPRecordBorderFill::CHWPRecordBorderFill(CHWPDocInfo& oDocInfo, int nTagNum, int nLevel, int nSize, CHWPStream& oBuffer, int nOff, int nVersion) - : CHWPRecord(nTagNum, nLevel, nSize), m_pParent(&oDocInfo), m_pFill(nullptr) + : CHWPRecord(nTagNum, nLevel, nSize), m_pFill(nullptr) { short shTypeBits; oBuffer.ReadShort(shTypeBits); @@ -302,7 +302,7 @@ CHWPRecordBorderFill::CHWPRecordBorderFill(CHWPDocInfo& oDocInfo, int nTagNum, i } CHWPRecordBorderFill::CHWPRecordBorderFill(CHWPDocInfo& oDocInfo, CXMLNode& oNode, int nVersion) - : CHWPRecord(EHWPTag::HWPTAG_BORDER_FILL, 0, 0), m_pParent(&oDocInfo), m_pFill(nullptr) + : CHWPRecord(EHWPTag::HWPTAG_BORDER_FILL, 0, 0), m_pFill(nullptr) { m_bThreeD = oNode.GetAttributeBool(L"threeD"); m_bShadow = oNode.GetAttributeBool(L"shadow"); diff --git a/HwpFile/HwpDoc/HWPElements/HWPRecordBorderFill.h b/HwpFile/HwpDoc/HWPElements/HWPRecordBorderFill.h index 792d78c490..55568594a4 100644 --- a/HwpFile/HwpDoc/HWPElements/HWPRecordBorderFill.h +++ b/HwpFile/HwpDoc/HWPElements/HWPRecordBorderFill.h @@ -106,7 +106,6 @@ public: class CHWPRecordBorderFill : public CHWPRecord { - CHWPDocInfo *m_pParent; static constexpr const float LINE_THICK[] = { 0.1f, 0.12f, 0.15f, 0.2f, 0.25f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 5.0f }; bool m_bThreeD; diff --git a/HwpFile/HwpDoc/HWPFile_Private.cpp b/HwpFile/HwpDoc/HWPFile_Private.cpp index 6c7bb89efb..c0e0bd535f 100644 --- a/HwpFile/HwpDoc/HWPFile_Private.cpp +++ b/HwpFile/HwpDoc/HWPFile_Private.cpp @@ -4,8 +4,6 @@ #include "../OfficeUtils/src/OfficeUtils.h" #include "../DesktopEditor/common/Directory.h" -#include - #define DEFAULT_BUFFER_SIZE 8096 namespace HWP @@ -20,12 +18,16 @@ CHWPFile_Private::~CHWPFile_Private() CLEAR_ARRAY(CHWPSection, m_arViewTexts); } -VECTOR CHWPFile_Private::GetSections() +std::vector CHWPFile_Private::GetSections() { if (m_oFileHeader.Distributable()) - return m_arViewTexts; + { + RETURN_VECTOR_CONST_PTR(CHWPSection, m_arViewTexts); + } else - return m_arBodyTexts; + { + RETURN_VECTOR_CONST_PTR(CHWPSection, m_arBodyTexts); + } } const CCompoundFile* CHWPFile_Private::GetOleFile() const @@ -74,14 +76,6 @@ void CHWPFile_Private::Close() m_oOleFile.Close(); } -void CHWPFile_Private::SaveHWPComponent() -{ - ECompressed eCompressed = m_oFileHeader.Compressed() ? ECompressed::COMPRESS : ECompressed::NO_COMPRESS; - - // Save internal component for debugging purpose. - // TODO:: перенести -} - bool CHWPFile_Private::GetFileHeader() { CHWPStream oBuffer; @@ -313,7 +307,7 @@ bool CHWPFile_Private::Decrypt(CHWPStream& oInput, CHWPStream& oBuffer) oInput.ReadInt(nHeader); int nTagNum = nHeader & 0x3FF; // 10 bits (0 - 9 bit) - int nLevel = (nHeader & 0xFFC00) >> 10; // 10 bits (10-19 bit) + // int nLevel = (nHeader & 0xFFC00) >> 10; // 10 bits (10-19 bit) int nSize = (nHeader & 0xFFF00000) >> 20; // 12 bits (20-31 bit) EHWPTag eTag = GetTagFromNum(nTagNum); diff --git a/HwpFile/HwpDoc/HWPFile_Private.h b/HwpFile/HwpDoc/HWPFile_Private.h index ccd734a42b..f0d200d5fb 100644 --- a/HwpFile/HwpDoc/HWPFile_Private.h +++ b/HwpFile/HwpDoc/HWPFile_Private.h @@ -21,15 +21,13 @@ public: CHWPFile_Private(const HWP_STRING& sFileName); ~CHWPFile_Private(); - VECTOR GetSections(); + VECTOR GetSections(); const CCompoundFile* GetOleFile() const; bool Detect(); bool Open(); void Close(); - void SaveHWPComponent(); - bool GetFileHeader(); const CHWPDocInfo* GetDocInfo() const; bool GetDocInfo(int nVersion); diff --git a/HwpFile/HwpDoc/HWPSection.cpp b/HwpFile/HwpDoc/HWPSection.cpp index 03584dee46..9dfe3b4c8f 100644 --- a/HwpFile/HwpDoc/HWPSection.cpp +++ b/HwpFile/HwpDoc/HWPSection.cpp @@ -111,6 +111,18 @@ CHWPSection::~CHWPSection() CLEAR_ARRAY(CHWPPargraph, m_arParas); } +bool CHWPSection::Parse(CXMLNode& oNode, int nVersion) +{ + std::vector arParagraphNodes{oNode.GetChilds(L"hp:p")}; + + m_arParas.resize(arParagraphNodes.size()); + + for (unsigned int unIndex = 0; unIndex < arParagraphNodes.size(); ++unIndex) + m_arParas[unIndex] = new CHWPPargraph(arParagraphNodes[unIndex], nVersion); + + return true; +} + bool CHWPSection::Parse(CHWPStream& oBuffer, int nVersion) { oBuffer.MoveToStart(); diff --git a/HwpFile/HwpDoc/HWPSection.h b/HwpFile/HwpDoc/HWPSection.h index 37a0851c18..dbeb8ffd24 100644 --- a/HwpFile/HwpDoc/HWPSection.h +++ b/HwpFile/HwpDoc/HWPSection.h @@ -16,6 +16,7 @@ public: CHWPSection(); ~CHWPSection(); + bool Parse(CXMLNode& oNode, int nVersion); bool Parse(CHWPStream& oBuffer, int nVersion); int ParseRecurse(CHWPPargraph* oCurrPara, int nRunLevel, CHWPStream& oBuffer, int nOff, int nVersion); int ParseCtrlRecurse(CCtrl* oCurrCtrl, int nRunLevel, CHWPStream& oBuffer, int nOff, int nVersion); diff --git a/HwpFile/HwpDoc/HWPXFile_Private.cpp b/HwpFile/HwpDoc/HWPXFile_Private.cpp new file mode 100644 index 0000000000..822b3eafff --- /dev/null +++ b/HwpFile/HwpDoc/HWPXFile_Private.cpp @@ -0,0 +1,159 @@ +#include "HWPXFile_Private.h" + +namespace HWP +{ +CHWPXFile_Private::CHWPXFile_Private(const HWP_STRING& sFileName) + : m_sFileName(sFileName), m_pZipFolder(nullptr), m_oDocInfo(this) +{} + +CHWPXFile_Private::~CHWPXFile_Private() +{ + Close(); + CLEAR_ARRAY(CHWPSection, m_arSections); +} + +VECTOR CHWPXFile_Private::GetSections() const +{ + RETURN_VECTOR_CONST_PTR(CHWPSection, m_arSections); +} + +bool CHWPXFile_Private::Detect() +{ + BYTE *pBuffer = NULL; + DWORD dwBufferSize = 0; + + if (!NSFile::CFileBinary::ReadAllBytes(m_sFileName, &pBuffer, dwBufferSize)) + return false; + + m_pZipFolder = new CZipFolderMemory(pBuffer, dwBufferSize); + + return GetFileHeader(); +} + +bool CHWPXFile_Private::Open() +{ + if (!NSFile::CFileBinary::Exists(m_sFileName)) + return false; + + if (m_oFileHeader.VersionEmpty() && !Detect()) + return false; + + m_nVersion = std::stoi(m_oFileHeader.GetVersion()); + + if (!GetDocInfo(m_nVersion)) + return false; + + std::vector arPathToSections{GetPathsToSections()}; + + for (const std::wstring& wsPath : arPathToSections) + ReadSection(wsPath, m_nVersion); + + return true; +} + +void CHWPXFile_Private::Close() +{ + if (nullptr != m_pZipFolder) + { + delete m_pZipFolder; + m_pZipFolder = nullptr; + } +} + +VECTOR CHWPXFile_Private::GetPathsToSections() const +{ + VECTOR arPaths{m_pZipFolder->getFiles(L"Contents", false)}; + + if (arPaths.empty()) + return VECTOR{}; + + struct TPathInfo + { + std::wstring m_wsPath; + unsigned short m_ushIndex; + + bool operator<(const TPathInfo& oPathInfo) + { + return m_ushIndex < oPathInfo.m_ushIndex; + } + }; + + VECTOR arPathsToSectors; + size_t unFoundPos, unNumberStart, unNumberEnd; + + for (const std::wstring& wsPath : arPaths) + { + unFoundPos = wsPath.find(L"/Contents/section"); + if (std::wstring::npos ==unFoundPos) + continue; + + unNumberStart = unFoundPos + 17; + unNumberEnd = unNumberStart; + + while (unNumberEnd < wsPath.length() && iswdigit(wsPath[unNumberEnd])) + ++unNumberEnd; + + if (unNumberEnd == unNumberStart || + unNumberEnd >= wsPath.length() || + L".xml" != wsPath.substr(unNumberEnd, 4)) + continue; + + arPathsToSectors.push_back({wsPath, static_cast(std::stoi(wsPath.substr(unNumberStart, unNumberEnd - unNumberStart)))}); + } + + std::sort(arPathsToSectors.begin(), arPathsToSectors.end()); + + VECTOR arResult{arPathsToSectors.size()}; + + for (unsigned int unIndex = 0; unIndex < arPathsToSectors.size(); ++unIndex) + arResult[unIndex] = arPathsToSectors[unIndex].m_wsPath; + + return arResult; +} + +bool CHWPXFile_Private::GetFileHeader() +{ + CXMLNode oVersionXml{GetDocument(L"version.xml")}; + return m_oFileHeader.Parse(oVersionXml); +} + +const CHWPDocInfo* CHWPXFile_Private::GetDocInfo() const +{ + return &m_oDocInfo; +} + +bool CHWPXFile_Private::GetDocInfo(int nVersion) +{ + CXMLNode oContent{GetDocument(L"Contents/content.hpf")}; + if (m_oDocInfo.ReadContentHpf(oContent, nVersion)) + { + CXMLNode oHeader{GetDocument(L"Contents/header.xml")}; + return m_oDocInfo.Parse(oHeader, nVersion); + } + + return false; +} + +bool CHWPXFile_Private::ReadSection(const HWP_STRING& sName, int nVersion) +{ + CXMLNode oRootNode{GetDocument(sName)}; + + CHWPSection* pSection = new CHWPSection(); + const bool bResult = pSection->Parse(oRootNode, nVersion); + + if (bResult) + m_arSections.push_back(pSection); + else + delete pSection; + + return bResult; +} + +CXMLNode CHWPXFile_Private::GetDocument(const HWP_STRING& sEntryName) +{ + if (nullptr == m_pZipFolder) + return CXMLNode(); + + return CXMLNode(m_pZipFolder->getNodeFromFile(sEntryName)); +} +} diff --git a/HwpFile/HwpDoc/HWPXFile_Private.h b/HwpFile/HwpDoc/HWPXFile_Private.h new file mode 100644 index 0000000000..ea9ff7121d --- /dev/null +++ b/HwpFile/HwpDoc/HWPXFile_Private.h @@ -0,0 +1,38 @@ +#ifndef HWPXFILE_PRIVATE_H +#define HWPXFILE_PRIVATE_H + +#include "HWPSection.h" +#include "HwpFileHeader.h" + +#include "../../OfficeUtils/src/ZipFolder.h" + +namespace HWP +{ +class CHWPXFile_Private +{ + HWP_STRING m_sFileName; + CZipFolderMemory *m_pZipFolder; + CHwpFileHeader m_oFileHeader; + int m_nVersion; + CHWPDocInfo m_oDocInfo; + VECTOR m_arSections; +public: + CHWPXFile_Private(const HWP_STRING& sFileName); + ~CHWPXFile_Private(); + + VECTOR GetSections() const; + const CHWPDocInfo* GetDocInfo() const; + + bool Detect(); + bool Open(); + void Close(); +private: + VECTOR GetPathsToSections() const; + bool GetFileHeader(); + bool GetDocInfo(int nVersion); + bool ReadSection(const HWP_STRING& sName, int nVersion); + CXMLNode GetDocument(const HWP_STRING& sEntryName); +}; +} + +#endif // HWPXFILE_PRIVATE_H diff --git a/HwpFile/HwpDoc/HwpFileHeader.cpp b/HwpFile/HwpDoc/HwpFileHeader.cpp index 2e85fb4ab9..7a5655eeed 100644 --- a/HwpFile/HwpDoc/HwpFileHeader.cpp +++ b/HwpFile/HwpDoc/HwpFileHeader.cpp @@ -60,6 +60,19 @@ bool CHwpFileHeader::Parse(CHWPStream& oBuffer) return true; } +bool CHwpFileHeader::Parse(CXMLNode& oNode) +{ + if (!oNode.IsValid()) + return false; + + m_sVersion += oNode.GetAttribute(L"major"); + m_sVersion += oNode.GetAttribute(L"minor"); + m_sVersion += oNode.GetAttribute(L"micro"); + m_sVersion += oNode.GetAttribute(L"buildNumber"); + + return true; +} + bool CHwpFileHeader::Compressed() const { return m_bCompressed; diff --git a/HwpFile/HwpDoc/HwpFileHeader.h b/HwpFile/HwpDoc/HwpFileHeader.h index f2f2a4755e..54103ca9c8 100644 --- a/HwpFile/HwpDoc/HwpFileHeader.h +++ b/HwpFile/HwpDoc/HwpFileHeader.h @@ -2,6 +2,7 @@ #define HWPFILEHEADER_H #include "HWPStream.h" +#include "Common/XMLNode.h" namespace HWP { @@ -46,6 +47,7 @@ public: HWP_STRING GetVersion() const; bool Parse(CHWPStream& oBuffer); + bool Parse(CXMLNode& oNode); }; } diff --git a/HwpFile/HwpDoc/Paragraph/CtrlGeneralShape.cpp b/HwpFile/HwpDoc/Paragraph/CtrlGeneralShape.cpp index dec20b8197..2670627b2e 100644 --- a/HwpFile/HwpDoc/Paragraph/CtrlGeneralShape.cpp +++ b/HwpFile/HwpDoc/Paragraph/CtrlGeneralShape.cpp @@ -63,7 +63,7 @@ CCtrlGeneralShape::CCtrlGeneralShape(const HWP_STRING& sCtrlID, int nSize, CHWPS } CCtrlGeneralShape::CCtrlGeneralShape(const HWP_STRING& sCtrlID, CXMLNode& oNode, int nVersion) - : CCtrlObjElement(sCtrlID) + : CCtrlObjElement(sCtrlID, oNode, nVersion) { InitData(); diff --git a/HwpFile/HwpDoc/Paragraph/CtrlObjElement.cpp b/HwpFile/HwpDoc/Paragraph/CtrlObjElement.cpp index d5a16eb5e7..7b60cc6e36 100644 --- a/HwpFile/HwpDoc/Paragraph/CtrlObjElement.cpp +++ b/HwpFile/HwpDoc/Paragraph/CtrlObjElement.cpp @@ -41,7 +41,7 @@ CCtrlObjElement::CCtrlObjElement(const HWP_STRING& sCtrlID, int nSize, CHWPStrea {} CCtrlObjElement::CCtrlObjElement(const HWP_STRING& sCtrlID, CXMLNode& oNode, int nVersion) - : CCtrlCommon(sCtrlID) + : CCtrlCommon(sCtrlID, oNode, nVersion) { m_shNGrp = oNode.GetAttributeInt(L"groupLevel"); diff --git a/HwpFile/HwpDoc/Paragraph/HWPPargraph.cpp b/HwpFile/HwpDoc/Paragraph/HWPPargraph.cpp index 2193b0d5bf..6c97621279 100644 --- a/HwpFile/HwpDoc/Paragraph/HWPPargraph.cpp +++ b/HwpFile/HwpDoc/Paragraph/HWPPargraph.cpp @@ -47,7 +47,9 @@ CHWPPargraph::CHWPPargraph(CXMLNode& oNode, int nVersion) if (L"hp:run" == oChild.GetName()) { nCharShapeID = oChild.GetAttributeInt(L"charPrIDRef"); - ParseHWPParagraph(oChild, nCharShapeID, nVersion); + + for (CXMLNode& oGrandChild : oChild.GetChilds()) + ParseHWPParagraph(oGrandChild, nCharShapeID, nVersion); } else if (L"hp:linesegarray" == oChild.GetName()) { @@ -175,12 +177,7 @@ VECTOR& CHWPPargraph::GetCtrls() std::vector CHWPPargraph::GetCtrls() const { - std::vector arParagraphs(m_arP.size()); - - for (unsigned int unIndex = 0; unIndex < m_arP.size(); ++unIndex) - arParagraphs[unIndex] = dynamic_cast(m_arP[unIndex]); - - return arParagraphs; + RETURN_VECTOR_CONST_PTR(CCtrl, m_arP); } unsigned int CHWPPargraph::GetCountCtrls() const