Files
DocumentServer-v-9.2.0/core/HwpFile/HwpDoc/Conversion/Converter2OOXML.cpp
T
Yajbir Singh f1b860b25c
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

2319 lines
89 KiB
C++

#include "Converter2OOXML.h"
#include <cfloat>
#include "../../../DesktopEditor/common/File.h"
#include "../../../DesktopEditor/common/Directory.h"
#include "../../../DesktopEditor/common/SystemUtils.h"
#include "../../../OfficeUtils/src/OfficeUtils.h"
#include "../../../DesktopEditor/graphics/pro/Image.h"
#include "../Paragraph/ParaText.h"
#include "../Paragraph/CtrlTable.h"
#include "../Paragraph/CtrlEqEdit.h"
#include "../Paragraph/CtrlShapeArc.h"
#include "../Paragraph/CtrlShapePolygon.h"
#include "../Paragraph/CtrlShapeCurve.h"
#include "../Paragraph/CtrlShapeLine.h"
#include "../Paragraph/CtrlShapeRect.h"
#include "../HWPElements/HWPRecordParaShape.h"
#include "../HWPElements/HWPRecordCharShape.h"
#include "Transform.h"
#define PARA_SPACING_SCALE 0.85
namespace HWP
{
enum class EShapeObjectType
{
Arc,
Curve,
Ellipse,
Line,
Ole,
Picture,
Polygon,
Rectangle,
Unknown
};
EShapeObjectType GetShapeObjectType(const std::wstring& wsID)
{
if (L"cra$" == wsID)
return EShapeObjectType::Arc;
if (L"ruc$" == wsID)
return EShapeObjectType::Curve;
if (L"lle$" == wsID)
return EShapeObjectType::Ellipse;
if (L"nil$" == wsID || L"loc$" == wsID)
return EShapeObjectType::Line;
if (L"elo$" == wsID)
return EShapeObjectType::Ole;
if (L"cip$" == wsID)
return EShapeObjectType::Picture;
if (L"lop$" == wsID)
return EShapeObjectType::Polygon;
if (L"cer$" == wsID)
return EShapeObjectType::Rectangle;
return EShapeObjectType::Unknown;
}
CConverter2OOXML::CConverter2OOXML()
: m_pContext(nullptr), m_ushShapeCount(0), m_ushPageCount(1), m_ushTableCount(0),
m_ushEquationCount(0), m_ushBookmarkCount(0)
{}
CConverter2OOXML::~CConverter2OOXML()
{}
void CConverter2OOXML::SetContext(CWriterContext* pContext)
{
m_pContext = pContext;
}
void CConverter2OOXML::SetTempDirectory(const HWP_STRING& sTempDirectory)
{
m_sTempDirectory = sTempDirectory;
m_oOleConverter.SetTempDir(m_sTempDirectory);
}
void CConverter2OOXML::CreateEmptyFiles()
{
NSDirectory::CreateDirectory(m_sTempDirectory + L"/_rels");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/docProps");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/_rels");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/media");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/theme");
// theme1.xml
std::wstring wsTheme = L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:p=\"http://schemas.openxmlformats.org/presentationml/2006/main\" name=\"Office Theme\"><a:themeElements><a:clrScheme name=\"Office\"><a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1><a:lt1><a:sysClr val=\"window\" lastClr=\"FFFFFF\"/></a:lt1><a:dk2><a:srgbClr val=\"44546A\"/></a:dk2><a:lt2><a:srgbClr val=\"E7E6E6\"/></a:lt2><a:accent1><a:srgbClr val=\"5B9BD5\"/></a:accent1><a:accent2><a:srgbClr val=\"ED7D31\"/></a:accent2><a:accent3><a:srgbClr val=\"A5A5A5\"/></a:accent3><a:accent4><a:srgbClr val=\"FFC000\"/></a:accent4><a:accent5><a:srgbClr val=\"4472C4\"/></a:accent5><a:accent6><a:srgbClr val=\"70AD47\"/></a:accent6><a:hlink><a:srgbClr val=\"0563C1\"/></a:hlink><a:folHlink><a:srgbClr val=\"954F72\"/></a:folHlink></a:clrScheme><a:fontScheme name=\"Office Classic 2\"><a:majorFont><a:latin typeface=\"Times New Roman\"/><a:ea typeface=\"Times New Roman\"/><a:cs typeface=\"Times New Roman\"/></a:majorFont><a:minorFont><a:latin typeface=\"Times New Roman\"/><a:ea typeface=\"Times New Roman\"/><a:cs typeface=\"Times New Roman\"/></a:minorFont></a:fontScheme><a:fmtScheme name=\"Office\"><a:fillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:gradFill><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"50000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs><a:gs pos=\"35000\"><a:schemeClr val=\"phClr\"><a:tint val=\"37000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:tint val=\"15000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"16200000\" scaled=\"1\"/></a:gradFill><a:gradFill><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:shade val=\"51000\"/><a:satMod val=\"130000\"/></a:schemeClr></a:gs><a:gs pos=\"80000\"><a:schemeClr val=\"phClr\"><a:shade val=\"93000\"/><a:satMod val=\"130000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"94000\"/><a:satMod val=\"135000\"/></a:schemeClr></a:gs></a:gsLst><a:lin ang=\"16200000\" scaled=\"0\"/></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w=\"6350\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"><a:shade val=\"95000\"/><a:satMod val=\"105000\"/></a:schemeClr></a:solidFill></a:ln><a:ln w=\"12700\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill></a:ln><a:ln w=\"19050\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\"><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst><a:outerShdw blurRad=\"40000\" dist=\"20000\" dir=\"5400000\" rotWithShape=\"0\"><a:srgbClr val=\"000000\"><a:alpha val=\"38000\"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\"><a:srgbClr val=\"000000\"><a:alpha val=\"35000\"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\"><a:srgbClr val=\"000000\"><a:alpha val=\"35000\"/></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val=\"phClr\"/></a:solidFill><a:gradFill><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"40000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs><a:gs pos=\"40000\"><a:schemeClr val=\"phClr\"><a:tint val=\"45000\"/><a:shade val=\"99000\"/><a:satMod val=\"350000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"20000\"/><a:satMod val=\"255000\"/></a:schemeClr></a:gs></a:gsLst><a:path path=\"circle\"/></a:gradFill><a:gradFill><a:gsLst><a:gs pos=\"0\"><a:schemeClr val=\"phClr\"><a:tint val=\"80000\"/><a:satMod val=\"300000\"/></a:schemeClr></a:gs><a:gs pos=\"100000\"><a:schemeClr val=\"phClr\"><a:shade val=\"30000\"/><a:satMod val=\"200000\"/></a:schemeClr></a:gs></a:gsLst><a:path path=\"circle\"/></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults/></a:theme>";
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"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Properties xmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\" xmlns:vt=\"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes\"><Application>";
wsApp += wsApplication;
wsApp += L"</Application><DocSecurity>0</DocSecurity><HyperlinksChanged>false</HyperlinksChanged><LinksUpToDate>false</LinksUpToDate><ScaleCrop>false</ScaleCrop><SharedDoc>false</SharedDoc></Properties>";
NSFile::CFileBinary oAppWriter;
if (oAppWriter.CreateFileW(m_sTempDirectory + L"/docProps/app.xml"))
{
oAppWriter.WriteStringUTF8(wsApp);
oAppWriter.CloseFile();
}
// .rels
std::wstring wsRels = L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"word/document.xml\"/><Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\" Target=\"docProps/core.xml\"/><Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\" Target=\"docProps/app.xml\"/></Relationships>";
NSFile::CFileBinary oRelsWriter;
if (oRelsWriter.CreateFileW(m_sTempDirectory + L"/_rels/.rels"))
{
oRelsWriter.WriteStringUTF8(wsRels);
oRelsWriter.CloseFile();
}
// fontTable.xml
std::wstring wsFontTable = L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><w:fonts xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" mc:Ignorable=\"w14 w15\"><w:font w:name=\"Wingdings\"><w:panose1 w:val=\"05000000000000000000\"/></w:font><w:font w:name=\"Courier New\"><w:panose1 w:val=\"02070309020205020404\"/></w:font><w:font w:name=\"Symbol\"><w:panose1 w:val=\"05050102010706020507\"/></w:font><w:font w:name=\"Times New Roman\"><w:panose1 w:val=\"020B0604020202020204\"/></w:font><w:font w:name=\"Calibri\"><w:panose1 w:val=\"020F0502020204030204\"/></w:font><w:font w:name=\"Times New Roman\"><w:panose1 w:val=\"02020603050405020304\"/></w:font><w:font w:name=\"Cambria\"><w:panose1 w:val=\"02040503050406030204\"/></w:font></w:fonts>";
NSFile::CFileBinary oFontTableWriter;
if (oFontTableWriter.CreateFileW(m_sTempDirectory + L"/word/fontTable.xml"))
{
oFontTableWriter.WriteStringUTF8(wsFontTable);
oFontTableWriter.CloseFile();
}
// settings.xml
std::wstring wsSettings = L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><w:settings xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:v=\"urn:schemas-microsoft-com:vml\"><w:clrSchemeMapping w:accent1=\"accent1\" w:accent2=\"accent2\" w:accent3=\"accent3\" w:accent4=\"accent4\" w:accent5=\"accent5\" w:accent6=\"accent6\" w:bg1=\"light1\" w:bg2=\"light2\" w:followedHyperlink=\"followedHyperlink\" w:hyperlink=\"hyperlink\" w:t1=\"dark1\" w:t2=\"dark2\"/><w:defaultTabStop w:val=\"708\"/><m:mathPr/><w:trackRevisions w:val=\"false\"/><w:decimalSymbol w:val=\".\"/><w:listSeparator w:val=\",\"/><w:compat><w:compatSetting w:name=\"compatibilityMode\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"15\"/><w:compatSetting w:name=\"overrideTableStyleFontSizeAndJustification\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"1\"/><w:compatSetting w:name=\"enableOpenTypeFeatures\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"1\"/><w:compatSetting w:name=\"doNotFlipMirrorIndents\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"1\"/><w:compatSetting w:name=\"useWord2013TrackBottomHyphenation\" w:uri=\"http://schemas.microsoft.com/office/word\" w:val=\"0\"/></w:compat><w:zoom w:percent=\"100\"/><w:characterSpacingControl w:val=\"doNotCompress\"/><w:themeFontLang w:val=\"en-US\" w:eastAsia=\"zh-CN\"/><w:shapeDefaults><o:shapedefaults v:ext=\"edit\" spidmax=\"1026\"/><o:shapelayout v:ext=\"edit\"><o:idmap v:ext=\"edit\" data=\"1\"/></o:shapelayout></w:shapeDefaults></w:settings>";
NSFile::CFileBinary oSettingsWriter;
if (oSettingsWriter.CreateFileW(m_sTempDirectory + L"/word/settings.xml"))
{
oSettingsWriter.WriteStringUTF8(wsSettings);
oSettingsWriter.CloseFile();
}
// core.xml
std::wstring wsCore = L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><cp:coreProperties xmlns:cp=\"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:dcterms=\"http://purl.org/dc/terms/\" xmlns:dcmitype=\"http://purl.org/dc/dcmitype/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">";
wsCore += L"<cp:lastModifiedBy/></cp:coreProperties>";
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"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">");
m_oDocXml .WriteString(L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><w:document xmlns:wpc=\"http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:wp14=\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\" xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" xmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" xmlns:wpg=\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\" xmlns:wpi=\"http://schemas.microsoft.com/office/word/2010/wordprocessingInk\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\" xmlns:wps=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\" mc:Ignorable=\"w14 w15 wp14\"><w:body>");
m_oWebSettings.WriteString(L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><w:webSettings xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"><w:optimizeForBrowser/>");
}
void CConverter2OOXML::Close()
{
// Дописываем концы файлов
m_oDocXml.WriteString(L"</w:body></w:document>");
NSFile::CFileBinary oDocumentWriter;
if (oDocumentWriter.CreateFileW(m_sTempDirectory + L"/word/document.xml"))
{
oDocumentWriter.WriteStringUTF8(m_oDocXml.GetData());
oDocumentWriter.CloseFile();
}
if (m_oFootnoteConverter.SaveToFile(m_sTempDirectory + FILE_SEPARATOR_STR + L"word" + FILE_SEPARATOR_STR))
{
AddRelationship(L"footnotes", L"footnotes.xml");
AddRelationship(L"endnotes", L"endnotes.xml");
AddContentType(L"footnotes.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml");
AddContentType(L"endnotes.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml");
}
// styles.xml
m_oStyleConverter.SaveToFile(m_sTempDirectory + FILE_SEPARATOR_STR + L"word" + FILE_SEPARATOR_STR);
// numbering.xml
if (m_oNumberingConverter.SaveToFile(m_sTempDirectory + FILE_SEPARATOR_STR + L"word" + FILE_SEPARATOR_STR))
{
AddRelationship(L"numbering", L"numbering.xml");
AddContentType(L"numbering.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml");
}
// webSettings.xml
m_oWebSettings.WriteString(L"</w:webSettings>");
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"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
oContentTypeWriter.WriteStringUTF8(L"<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>");
for (const TContentType& oContentType : m_arDefaultContentType)
oContentTypeWriter.WriteStringUTF8(L"<Default Extension=\"" + oContentType.m_wsName + L"\" ContentType=\"" + oContentType.m_wsType + L"\"/>");
for (const TContentType& oContentType : m_arContentTypes)
oContentTypeWriter.WriteStringUTF8(L"<Override PartName=\"/word/" + oContentType.m_wsName + L"\" ContentType=\"" + oContentType.m_wsType + L"\"/>");
oContentTypeWriter.WriteStringUTF8(L"<Override PartName=\"/docProps/core.xml\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\"/>");
oContentTypeWriter.WriteStringUTF8(L"<Override PartName=\"/docProps/app.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\"/>");
oContentTypeWriter.WriteStringUTF8(L"</Types>");
oContentTypeWriter.CloseFile();
}
NSFile::CFileBinary oRelsWriter;
if (oRelsWriter.CreateFileW(m_sTempDirectory + L"/word/_rels/document.xml.rels"))
{
oRelsWriter.WriteStringUTF8(L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">");
for (const TRelationship& oRelationship : m_arRelationships)
{
oRelsWriter.WriteStringUTF8(L"<Relationship Id=\"" + oRelationship.m_wsID + L"\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/" + oRelationship.m_wsType + L"\" Target=\"" + oRelationship.m_wsTarget + L'\"');
if (L"hyperlink" == oRelationship.m_wsType)
oRelsWriter.WriteStringUTF8(L" TargetMode=\"External\"/>");
else
oRelsWriter.WriteStringUTF8(L"/>");
}
oRelsWriter.WriteStringUTF8(L"</Relationships>");
oRelsWriter.CloseFile();
}
}
void CConverter2OOXML::Convert()
{
if (nullptr == m_pContext)
return;
TConversionState oState;
std::vector<const CHWPSection*> 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"<w:p><w:pPr>");
WriteSectionSettings(oState);
if (!bIsLastSection)
m_oDocXml.WriteString(L"</w:pPr></w:p>");
++oState.m_ushSecdIndex;
oState.m_oLastNode.Clear();
}
}
bool CConverter2OOXML::IsRasterFormat(const HWP_STRING& sFormat)
{
return L"png" == sFormat || L"jpg" == sFormat || L"jpeg" == sFormat || L"bmp" == sFormat;
}
void CConverter2OOXML::WriteCharacter(const CCtrlCharacter* pCharacter, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pCharacter)
return;
switch (pCharacter->GetType())
{
case ECtrlCharType::PARAGRAPH_BREAK:
{
// Таблицы пишутся без тега <w:p>, поэтому для них не открывается параграф
if (TConversionState::TLastNode::ELastNodeType::Table == oState.m_oLastNode.m_eType &&
oState.m_unParaIndex == oState.m_oLastNode.m_unParaIndex && !oState.m_bInTable)
{
oState.m_oLastNode.m_eType = TConversionState::TLastNode::ELastNodeType::Table;
break;
}
if (!oState.m_bOpenedP)
WriteEmptyParagraph(shParaShapeID, shParaStyleID, pCharacter->GetCharShapeId(), oBuilder, oState);
else
CloseParagraph(oBuilder, oState);
break;
}
case ECtrlCharType::LINE_BREAK:
{
oState.m_eBreakType = TConversionState::EBreakType::TextWrapping;
break;
}
case ECtrlCharType::TABULATION:
{
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:r><w:tab/></w:r>");
break;
}
case ECtrlCharType::HARD_HYPHEN:
case ECtrlCharType::HARD_SPACE:
break;
}
}
void CConverter2OOXML::WriteShape(const CCtrlGeneralShape* pShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const CCtrlContainer *pContainer)
{
if (nullptr == pShape || oState.m_bInTextBox)
return;
switch (pShape->GetShapeType())
{
case EShapeType::Arc:
case EShapeType::Ellipse:
case EShapeType::Rect:
case EShapeType::Line:
case EShapeType::Polygon:
case EShapeType::Curve:
{
WriteGeometryShape(pShape, shParaShapeID, shParaStyleID, oBuilder, oState, pContainer);
break;
}
case EShapeType::Pic:
{
WritePicture((const CCtrlShapePic*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState);
break;
}
case EShapeType::EqEdit:
{
WriteEqEditShape((const CCtrlEqEdit*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState);
break;
}
case EShapeType::Ole:
{
WriteOleShape((const CCtrlShapeOle*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState);
break;
}
case EShapeType::Video:
{
WriteVideo((const CCtrlShapeVideo*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState);
break;
}
case EShapeType::Container:
{
WriteContainer((const CCtrlContainer*)pShape, shParaShapeID, shParaStyleID, oBuilder, oState);
break;
}
case EShapeType::GeneralShape:
case EShapeType::ConnectLine:
case EShapeType::TextArt:
break;
}
}
void CConverter2OOXML::WriteNote(const CCtrlNote* pNote, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pNote)
return;
oBuilder.WriteString(L"<w:r>");
CRunnerStyle oRunnerStyle;
oRunnerStyle.SetVerticalAlign(EVerticalAlignRun::Superscript);
WriteRunnerStyle(oState.m_ushLastCharShapeId, oBuilder, oState, oRunnerStyle);
oBuilder.WriteString(m_oFootnoteConverter.CreateNote((const CCtrlNote*)pNote, *this));
oBuilder.WriteString(L"</w:r>");
}
void CConverter2OOXML::WriteField(const CCtrlField* pShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pShape)
return;
switch (pShape->GetType())
{
case EFieldType::Hyperlink:
{
HWP_STRING wsHref = pShape->GetStringParam(L"Path");
if(wsHref.empty())
{
HWP_STRING sCommand = pShape->GetStringParam(L"Command");
if (sCommand.empty())
sCommand = pShape->GetCommand();
sCommand = sCommand.substr(0, sCommand.find(L';'));
size_t unFound = sCommand.find(L'\\');
while (HWP_STRING::npos != unFound)
{
sCommand.erase(unFound, 1);
unFound = sCommand.find(L'\\', unFound);
}
wsHref = sCommand;
}
if (wsHref.empty())
break;
const HWP_STRING wsID = AddRelationship(L"hyperlink", wsHref, &oState);
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:hyperlink r:id=\"" + wsID + L"\">");
oState.m_mOpenField.insert(std::make_pair(pShape->GetInstanceID(), pShape));
break;
}
case EFieldType::HyperlinkClosing:
{
oBuilder.WriteString(L"</w:hyperlink>");
break;
}
case EFieldType::Bookmark:
{
oBuilder.WriteString(L"<w:bookmarkStart w:id=\"" + std::to_wstring(m_ushBookmarkCount) + L"\" w:name=\"");
oBuilder.WriteEncodeXmlString(pShape->GetStringParam(L"bookmarkname"));
oBuilder.WriteString(L"\"/>");
oState.m_arOpenedBookmarks.push(m_ushBookmarkCount++);
oState.m_mOpenField.insert(std::make_pair(pShape->GetInstanceID(), pShape));
break;
}
case EFieldType::BookmarkClosing:
{
if (oState.m_arOpenedBookmarks.empty())
break;
oBuilder.WriteString(L"<w:bookmarkEnd w:id=\"" + std::to_wstring(oState.m_arOpenedBookmarks.top()) + L"\"/>");
oState.m_arOpenedBookmarks.pop();
break;
}
//TODO:: как-будто хочется определить тип закрывающей field на этапе парса hwpx
case EFieldType::Unknown:
{
std::map<unsigned int, const CCtrlField*>::const_iterator itFound = oState.m_mOpenField.find(pShape->GetInstanceID());
if (oState.m_mOpenField.cend() != itFound)
{
switch (itFound->second->GetType())
{
case EFieldType::Hyperlink:
{
oBuilder.WriteString(L"</w:hyperlink>");
break;
}
case EFieldType::Bookmark:
{
if (oState.m_arOpenedBookmarks.empty())
break;
oBuilder.WriteString(L"<w:bookmarkEnd w:id=\"" + std::to_wstring(oState.m_arOpenedBookmarks.top()) + L"\"/>");
oState.m_arOpenedBookmarks.pop();
break;
}
default:
break;
}
}
break;
}
}
}
void CConverter2OOXML::WriteCaption(const CCtrlCommon* pCtrlCommon, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pCtrlCommon || !pCtrlCommon->HaveCaption())
return;
for (const CCapParagraph* pCapParagraph : pCtrlCommon->GetCaptionParas())
WriteParagraph(pCapParagraph, oBuilder, oState);
}
void CConverter2OOXML::WriteEmptyParagraph(short shParaShapeID, short shParaStyleID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (oState.m_bOpenedP)
return;
oBuilder.WriteString(L"<w:p>");
oBuilder.WriteString(L"<w:pPr>");
WriteParaShapeProperties(shParaShapeID, shParaStyleID, oBuilder, oState);
WriteRunnerStyle(shCharShapeID, oBuilder, oState);
oBuilder.WriteString(L"</w:pPr>");
oBuilder.WriteString(L"</w:p>");
}
void CConverter2OOXML::WriteParagraph(const CHWPPargraph* pParagraph, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pParagraph)
return;
CloseParagraph(oBuilder, oState);
if (0 < pParagraph->GetBreakType())
{
if ((0x04 == (pParagraph->GetBreakType() & 0x04)) && (0 < oState.m_unParaIndex))
{
oState.m_eBreakType = TConversionState::EBreakType::Page;
// oBuilder.WriteString(L"<w:r><w:br w:type=\"page\"/></w:r>");
++m_ushPageCount;
}
else if (0x08 == (pParagraph->GetBreakType() & 0x08))
oState.m_eBreakType = TConversionState::EBreakType::Column;
// oBuilder.WriteString(L"<w:r><w:br w:type=\"column\"/></w:r>");
}
++oState.m_unParaIndex;
for (const CCtrl* pCtrl : pParagraph->GetCtrls())
{
switch (pCtrl->GetCtrlType())
{
case ECtrlObjectType::ParaText:
{
WriteText((const CParaText*)pCtrl, pParagraph->GetRangeTags(), pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Character:
{
WriteCharacter((const CCtrlCharacter*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Shape:
{
WriteShape((const CCtrlGeneralShape*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Table:
{
WriteTable((const CCtrlTable*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Note:
{
WriteNote((const CCtrlNote*)pCtrl, pParagraph->GetShapeID(), oBuilder, oState);
break;
}
case ECtrlObjectType::SectionDef:
{
oState.m_pSectionDef = (const CCtrlSectionDef*)pCtrl;
break;
}
case ECtrlObjectType::ColumnDef:
{
oState.m_pColumnDef = (const CCtrlColumnDef*)(pCtrl);
break;
}
case ECtrlObjectType::AutoNumber:
{
WriteAutoNumber((const CCtrlAutoNumber*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oState.m_ushLastCharShapeId, oBuilder, oState);
break;
}
case ECtrlObjectType::Field:
{
WriteField((const CCtrlField*)pCtrl, pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oState);
break;
}
case ECtrlObjectType::HeadFoot:
{
if (EHanType::HWPX == m_pContext->GetType() ||
EHanType::HWPML == m_pContext->GetType())
oState.m_arCtrlsHeadFoot.push_back((const CCtrlHeadFoot*)pCtrl);
break;
}
case ECtrlObjectType::PageNumPos:
{
oState.m_pPageNum = dynamic_cast<const CCtrlPageNumPos*>(pCtrl);
break;
}
case ECtrlObjectType::NewNumber:
{
oState.m_pNewNumber = dynamic_cast<const CCtrlNewNumber*>(pCtrl);
break;
}
default:
break;
}
}
CloseParagraph(oBuilder, oState);
}
void CConverter2OOXML::WriteParagraphProperties(short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
oBuilder.WriteString(L"<w:pPr>");
WriteParaShapeProperties(shParaShapeID, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"</w:pPr>");
}
void CConverter2OOXML::WriteParaShapeProperties(short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == m_pContext)
return;
const std::wstring wsStyleId = m_oStyleConverter.CreateStyle(shParaShapeID, shParaStyleID, *m_pContext, oState);
if (!wsStyleId.empty())
{
oBuilder.WriteString(L"<w:pStyle w:val=\"");
oBuilder.WriteEncodeXmlString(wsStyleId);
oBuilder.WriteString(L"\"/>");
}
if (oState.m_bInTable)
oBuilder.WriteString(L"<w:wordWrap w:val=\"1\"/>");
if (m_oStyleConverter.GetLastParaShapeId() != shParaShapeID)
m_oStyleConverter.WriteDifferenceParagraphStyles(m_oStyleConverter.GetLastParaShapeId(), shParaShapeID, *m_pContext, oBuilder);
const CHWPRecordParaShape* pParaShape= dynamic_cast<const CHWPRecordParaShape*>(m_pContext->GetParaShape(shParaShapeID));
if (nullptr == pParaShape)
return;
switch (pParaShape->GetHeadingType())
{
case EHeadingType::NUMBER:
case EHeadingType::BULLET:
{
const int nNumId = m_oNumberingConverter.CreateNumbering(dynamic_cast<const CHWPRecordNumbering*>(m_pContext->GetNumbering(pParaShape->GetHeadingIdRef())), pParaShape->GetHeadingType(), *this);
if (0 == nNumId)
break;
oBuilder.WriteString(L"<w:numPr>");
oBuilder.WriteString(L"<w:ilvl w:val=\"" + std::to_wstring((int)pParaShape->GetHeadingLevel()) + L"\"/>");
oBuilder.WriteString(L"<w:numId w:val=\"" + std::to_wstring(nNumId) + L"\"/>");
oBuilder.WriteString(L"</w:numPr>");
break;
}
case EHeadingType::OUTLINE:
case EHeadingType::NONE:
break;
}
if (oState.m_bInTable)
return;
const CHwpRecordTabDef* pTabDef = m_pContext->GetTabDef(pParaShape->GetTabDef());
if (nullptr != pTabDef && 0 != pTabDef->GetCount())
{
oBuilder.WriteString(L"<w:tabs>");
const TTab *pTab = nullptr;
for (unsigned int unIndex = 0; unIndex < pTabDef->GetCount(); ++unIndex)
{
pTab = pTabDef->GetTab(unIndex);
if (nullptr == pTab)
continue;
oBuilder.WriteString(L"<w:tab w:val=\"");
switch (pTab->m_eType)
{
case TTab::EType::LEFT: oBuilder.WriteString(L"start"); break;
case TTab::EType::RIGHT: oBuilder.WriteString(L"end"); break;
case TTab::EType::CENTER: oBuilder.WriteString(L"center"); break;
case TTab::EType::DECIMAL: oBuilder.WriteString(L"decimal"); break;
}
oBuilder.WriteString(L"\" w:leader=\"");
switch (pTab->m_eLeader)
{
case ELineStyle2::NONE: oBuilder.WriteString(L"none"); break;
case ELineStyle2::SOLID:
case ELineStyle2::DOUBLE_SLIM:
case ELineStyle2::SLIM_THICK:
case ELineStyle2::THICK_SLIM:
case ELineStyle2::SLIM_THICK_SLIM:
oBuilder.WriteString(L"heavy"); break;
case ELineStyle2::DASH:
case ELineStyle2::LONG_DASH:
case ELineStyle2::DASH_DOT:
case ELineStyle2::DASH_DOT_DOT:
oBuilder.WriteString(L"hyphen"); break;
case ELineStyle2::DOT:
case ELineStyle2::CIRCLE:
oBuilder.WriteString(L"dot"); break;
}
oBuilder.WriteString(L"\" w:pos=\"" + std::to_wstring(pTab->m_nPos / 10) + L"\"/>");
}
oBuilder.WriteString(L"</w:tabs>");
}
}
void CConverter2OOXML::WriteTable(const CCtrlTable* pTable, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pTable || pTable->Empty())
return;
if (TConversionState::TLastNode::ELastNodeType::Table == oState.m_oLastNode.m_eType)
oBuilder.WriteString(L"<w:p><w:r><w:rPr><w:vanish/></w:rPr></w:r></w:p>");
CloseParagraph(oBuilder, oState);
++m_ushTableCount;
oBuilder.WriteString(L"<w:tbl>");
const bool bTableInTable = oState.m_bInTable;
oState.m_bInTable = true;
WriteTableProperties(pTable, shParaShapeID, shParaStyleID, oBuilder, oState);
std::vector<std::vector<std::pair<ECellCreator, const CTblCell*>>> 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<ECellCreator, const CTblCell*> 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"<w:tr>");
int nHeight = 0;
for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex)
{
std::pair<ECellCreator, const CTblCell*> oValue = m_arrCells[unRowIndex][unColIndex];
if (ECellCreator::FILE == oValue.first && 1 == oValue.second->GetRowSpan())
nHeight = (std::max)(nHeight, oValue.second->GetHeight());
}
oBuilder.WriteString(L"<w:trPr>");
oBuilder.WriteString(L"<w:trHeight w:val=\"" + std::to_wstring(Transform::HWPUINT2Twips(nHeight)) + L"\"/>");
oBuilder.WriteString(L"</w:trPr>");
for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex)
{
std::pair<ECellCreator, const CTblCell*> oValue = m_arrCells[unRowIndex][unColIndex];
WriteCell(oValue.second, oBuilder, oState, oValue.first);
}
oBuilder.WriteString(L"</w:tr>");
}
oBuilder.WriteString(L"</w:tbl>");
oState.m_oLastNode.m_eType = TConversionState::TLastNode::ELastNodeType::Table;
oState.m_oLastNode.m_unParaIndex = oState.m_unParaIndex;
oState.m_bInTable = bTableInTable;
}
void CConverter2OOXML::WriteTableProperties(const CCtrlTable* pTable, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pTable)
return;
oBuilder.WriteString(L"<w:tblPr>");
// TODO:: сделать вычисление
oBuilder.WriteString(L"<w:tblW w:w=\"0\" w:type=\"auto\"/>");
if (0 != pTable->GetInLSpace() || 0 != pTable->GetInTSpace() ||
0 != pTable->GetInRSpace() || 0 != pTable->GetInBSpace())
{
oBuilder.WriteString(L"<w:tblCellMar>");
oBuilder.WriteString(L"<w:top w:w=\"" + std::to_wstring(Transform::HWPUINT2Twips(pTable->GetInTSpace())) + L"\" w:type=\"dxa\"/>");
oBuilder.WriteString(L"<w:left w:w=\"" + std::to_wstring(Transform::HWPUINT2Twips(pTable->GetInLSpace())) + L"\" w:type=\"dxa\"/>");
oBuilder.WriteString(L"<w:bottom w:w=\"" + std::to_wstring(Transform::HWPUINT2Twips(pTable->GetInBSpace())) + L"\" w:type=\"dxa\"/>");
oBuilder.WriteString(L"<w:right w:w=\"" + std::to_wstring(Transform::HWPUINT2Twips(pTable->GetInRSpace())) + L"\" w:type=\"dxa\"/>");
oBuilder.WriteString(L"</w:tblCellMar>");
}
WriteParaShapeProperties(shParaShapeID, shParaStyleID, oBuilder, oState);
// const CHWPRecordBorderFill* pBorderFill = nullptr;
// if (nullptr != m_pContext)
// pBorderFill = dynamic_cast<const CHWPRecordBorderFill*>(m_pContext->GetBorderFill(pTable->GetBorderFillID()));
// if (nullptr == pBorderFill)
// {
// oBuilder.WriteString(L"</w:tblPr>");
// return;
// }
oBuilder.WriteString(L"</w:tblPr>");
}
void CConverter2OOXML::WriteCell(const CTblCell* pCell, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, ECellCreator eCellCreator)
{
if (nullptr == pCell)
return;
oBuilder.WriteString(L"<w:tc>");
oBuilder.WriteString(L"<w:tcPr>");
oBuilder.WriteString(L"<w:tcW w:w=\"" + std::to_wstring(Transform::HWPUINT2Twips(pCell->GetWidth())) + L"\" w:type=\"dxa\"/>");
if (1 != pCell->GetColSpan())
oBuilder.WriteString(L"<w:gridSpan w:val=\"" + std::to_wstring(pCell->GetColSpan()) + L"\"/>");
if (1 != pCell->GetRowSpan())
oBuilder.WriteString(L"<w:vMerge w:val=\"" + HWP_STRING(((ECellCreator::FILE == eCellCreator) ? L"restart" : L"continue")) + L"\"/>");
WriteCellProperties(pCell->GetBorderFillID(), oBuilder);
switch(pCell->GetVertAlign())
{
case EVertAlign::TOP: oBuilder.WriteString(L"<w:vAlign w:val=\"top\"/>"); break;
case EVertAlign::CENTER: oBuilder.WriteString(L"<w:vAlign w:val=\"center\"/>"); break;
case EVertAlign::BOTTOM: oBuilder.WriteString(L"<w:vAlign w:val=\"bottom\"/>"); break;
case EVertAlign::INSIDE:
case EVertAlign::OUTSIDE:
break;
}
oBuilder.WriteString(L"</w:tcPr>");
if (ECellCreator::FILE == eCellCreator && !pCell->GetParagraphs().empty())
{
for (const CHWPPargraph* pParagraph : pCell->GetParagraphs())
{
NSStringUtils::CStringBuilder oCellBuilder;
TConversionState oCellState;
oCellState.m_pRelationships = oState.m_pRelationships;
oCellState.m_bInTable = oState.m_bInTable;
WriteParagraph(pParagraph, oCellBuilder, oCellState);
if (0 == oCellBuilder.GetCurSize())
{
OpenParagraph(pParagraph->GetShapeID(), pParagraph->GetStyleID(), oBuilder, oCellState);
CloseParagraph(oBuilder, oCellState);
}
else
oBuilder.Write(oCellBuilder);
}
}
else
oBuilder.WriteString(L"<w:p><w:r></w:r></w:p>");
oBuilder.WriteString(L"</w:tc>");
}
void CConverter2OOXML::WriteCellProperties(short shBorderFillID, NSStringUtils::CStringBuilder& oBuilder)
{
const CHWPRecordBorderFill* pBorderFill = nullptr;
if (nullptr != m_pContext)
pBorderFill = dynamic_cast<const CHWPRecordBorderFill*>(m_pContext->GetBorderFill(shBorderFillID));
if (nullptr == pBorderFill)
return;
if(nullptr != pBorderFill->GetFill())
{
const CFill* pFill{pBorderFill->GetFill()};
if (pFill->ColorFill())
oBuilder.WriteString(L"<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"" + Transform::IntColorToHEX(pFill->GetFaceColor()) + L"\"/>");
// In OOXML, there is no gradient support for cell fills, so we fill in the first color of the gradient.
else if (pFill->GradFill() && 0 != pFill->GetGradColorNum())
oBuilder.WriteString(L"<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"" + Transform::IntColorToHEX(pFill->GetGradColors().front()) + L"\"/>");
}
oBuilder.WriteString(L"<w:tcBorders>");
WriteBorder(pBorderFill->GetTopBorder(), L"top", oBuilder);
WriteBorder(pBorderFill->GetLeftBorder(), L"left", oBuilder);
WriteBorder(pBorderFill->GetBottomBorder(), L"bottom", oBuilder);
WriteBorder(pBorderFill->GetRightBorder(), L"right", oBuilder);
oBuilder.WriteString(L"</w:tcBorders>");
}
void CConverter2OOXML::WriteBorder(const TBorder& oBorder, const HWP_STRING& sBorderName, NSStringUtils::CStringBuilder& oBuilder)
{
if (sBorderName.empty())
return;
HWP_STRING sType;
//TODO:: проверить стиль линий
switch(oBorder.m_eStyle)
{
case ELineStyle2::NONE: oBuilder.WriteString(L"<w:" + sBorderName + L" w:val=\"none\"/>"); return;
case ELineStyle2::SOLID: sType = L"single"; break;
case ELineStyle2::DASH: sType = L"dashed"; break;
case ELineStyle2::DOT: sType = L"dotted"; break;
case ELineStyle2::DASH_DOT: sType = L"dotDash"; break;
case ELineStyle2::DASH_DOT_DOT: sType = L"dotDotDash"; break;
case ELineStyle2::LONG_DASH: sType = L"dashed"; break;
case ELineStyle2::CIRCLE: sType = L"dashed"; break;
case ELineStyle2::DOUBLE_SLIM: sType = L"double"; break;
case ELineStyle2::SLIM_THICK: sType = L"thinThickSmallGap"; break;
case ELineStyle2::THICK_SLIM: sType = L"thickThinSmallGap"; break;
case ELineStyle2::SLIM_THICK_SLIM: sType = L"thinThickThinSmallGap"; break;
}
oBuilder.WriteString(L"<w:" + sBorderName + L" w:val=\"" + sType + L"\" w:sz=\"" + std::to_wstring(Transform::LineWidth2Pt((short)oBorder.m_chWidth)) + L"\" w:color=\"" + Transform::IntColorToHEX(oBorder.m_nColor) + L"\"/>");
}
VECTOR<TPoint> ArcToBezier(const TPoint& oStart, const TPoint& oEnd, const TPoint& oCenter)
{
const double dRadiusX = std::abs(oStart.m_nX - oCenter.m_nX);
const double dRadiusY = std::abs(oStart.m_nY - oCenter.m_nY);
// Вычисление углов
double dStartAngle = std::atan2(oStart.m_nY - oCenter.m_nY, oStart.m_nX - oCenter.m_nX);
double dEndAngle = std::atan2(oEnd.m_nY - oCenter.m_nY, oEnd.m_nX - oCenter.m_nX);
if (dEndAngle < dStartAngle)
std::swap(dStartAngle, dEndAngle);
TPoint oControl1{static_cast<int>(oStart.m_nX + dRadiusX * std::cos(dStartAngle)), static_cast<int>(oStart.m_nY + dRadiusY * std::sin(dStartAngle))};
TPoint oControl2{static_cast<int>(oEnd.m_nX - dRadiusX * std::cos(dEndAngle )), static_cast<int>(oEnd.m_nY + dRadiusY * std::sin(dEndAngle ))};
return {oStart, oControl1, oControl2, oEnd};
}
void CConverter2OOXML::WriteGeometryShape(const CCtrlGeneralShape* pGeneralShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const CCtrlContainer* pContainer)
{
if (nullptr == pGeneralShape)
return;
EShapeObjectType eShapeType = GetShapeObjectType(pGeneralShape->GetID());
if (EShapeObjectType::Unknown == eShapeType)
return;
++m_ushShapeCount;
WriteCaption((const CCtrlCommon*)pGeneralShape, oBuilder, oState);
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
const int nWidth = Transform::HWPUINT2OOXML(pGeneralShape->GetFinalWidth());
const int nHeight = Transform::HWPUINT2OOXML(pGeneralShape->GetFinalHeight());
const std::wstring wsWidth = std::to_wstring(nWidth);
const std::wstring wsHeight = std::to_wstring(nHeight);
oBuilder.WriteString(L"<w:r><w:rPr><w:noProof/></w:rPr>");
oBuilder.WriteString(L"<mc:AlternateContent><mc:Choice Requires=\"wps\">");
OpenDrawingNode((nullptr != pContainer) ? pContainer : pGeneralShape, oBuilder);
oBuilder.WriteString(L"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">");
oBuilder.WriteString(L"<a:graphicData uri=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\">");
oBuilder.WriteString(L"<wps:wsp><wps:cNvSpPr/><wps:spPr><a:xfrm>");
oBuilder.WriteString(L"<a:off x=\"0\" y=\"0\"/>");
oBuilder.WriteString(L"<a:ext cx=\"" + wsWidth + L"\" cy=\"" + wsHeight + L"\"/>");
oBuilder.WriteString(L"</a:xfrm>");
switch (eShapeType)
{
case EShapeObjectType::Arc:
{
const CCtrlShapeArc *pShapeArc = (const CCtrlShapeArc*)pGeneralShape;
TPoint oStartPoint {pShapeArc->GetFirstPoint()},
oEndPoint {pShapeArc->GetSecondPoint()},
oCenterPoint{pShapeArc->GetCenterPoint()};
const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()};
oMatrix.ApplyToPoint(oStartPoint .m_nX, oStartPoint .m_nY);
oMatrix.ApplyToPoint(oEndPoint .m_nX, oEndPoint .m_nY);
oMatrix.ApplyToPoint(oCenterPoint.m_nX, oCenterPoint.m_nY);
VECTOR<TPoint> arBezierPoints{ArcToBezier({Transform::HWPUINT2OOXML(oStartPoint .m_nX), Transform::HWPUINT2OOXML(oStartPoint .m_nY)},
{Transform::HWPUINT2OOXML(oEndPoint .m_nX), Transform::HWPUINT2OOXML(oEndPoint .m_nY)},
{Transform::HWPUINT2OOXML(oCenterPoint.m_nX), Transform::HWPUINT2OOXML(oCenterPoint.m_nY)})};
oBuilder.WriteString(L"<a:custGeom><a:pathLst><a:path>");
oBuilder.WriteString(L"<a:moveTo><a:pt x=\"" + std::to_wstring(arBezierPoints[0].m_nX) + L"\" y=\"" + std::to_wstring(arBezierPoints[0].m_nY) + L"\"/></a:moveTo>");
oBuilder.WriteString(L"<a:cubicBezTo>");
oBuilder.WriteString(L"<a:pt x=\"" + std::to_wstring(arBezierPoints[1].m_nX) + L"\" y=\"" + std::to_wstring(arBezierPoints[1].m_nY) + L"\"/>");
oBuilder.WriteString(L"<a:pt x=\"" + std::to_wstring(arBezierPoints[2].m_nX) + L"\" y=\"" + std::to_wstring(arBezierPoints[2].m_nY) + L"\"/>");
oBuilder.WriteString(L"<a:pt x=\"" + std::to_wstring(arBezierPoints[3].m_nX) + L"\" y=\"" + std::to_wstring(arBezierPoints[3].m_nY) + L"\"/>");
oBuilder.WriteString(L"</a:cubicBezTo>");
oBuilder.WriteString(L"</a:path></a:pathLst></a:custGeom>");
break;
}
case EShapeObjectType::Ellipse:
{
oBuilder.WriteString(L"<a:prstGeom prst=\"ellipse\"><a:avLst/></a:prstGeom>");
break;
}
case EShapeObjectType::Line:
{
const CCtrlShapeLine *pShapeLine = (const CCtrlShapeLine*)pGeneralShape;
TPoint oStartPoint{pShapeLine->GetStartX(), pShapeLine->GetStartY()},
oEndPoint {pShapeLine->GetEndX(), pShapeLine->GetEndY() };
const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()};
oMatrix.ApplyToPoint(oStartPoint .m_nX, oStartPoint .m_nY);
oMatrix.ApplyToPoint(oEndPoint .m_nX, oEndPoint .m_nY);
oBuilder.WriteString(L"<a:custGeom><a:pathLst><a:path>");
oBuilder.WriteString(L"<a:moveTo><a:pt x=\"" + std::to_wstring(Transform::HWPUINT2OOXML(oStartPoint.m_nX)) + L"\" y=\"" + std::to_wstring(Transform::HWPUINT2OOXML(oStartPoint.m_nY)) + L"\"/></a:moveTo>");
oBuilder.WriteString(L"<a:lnTo><a:pt x=\"" + std::to_wstring(Transform::HWPUINT2OOXML(oEndPoint.m_nX)) + L"\" y=\"" + std::to_wstring(Transform::HWPUINT2OOXML(oEndPoint.m_nY)) + L"\"/></a:lnTo>");
oBuilder.WriteString(L"</a:path></a:pathLst></a:custGeom>");
// oBuilder.WriteString(L"<a:prstGeom prst=\"line\"><a:avLst/></a:prstGeom>");
break;
}
case EShapeObjectType::Rectangle:
{
const CCtrlShapeRect* pShapeRect = (const CCtrlShapeRect*)pGeneralShape;
TPoint arPoints[4];
pShapeRect->GetPoints(arPoints);
const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()};
for (TPoint& oPoint : arPoints)
{
oMatrix.ApplyToPoint(oPoint.m_nX, oPoint.m_nY);
oPoint.m_nX = Transform::HWPUINT2OOXML(oPoint.m_nX);
oPoint.m_nY = Transform::HWPUINT2OOXML(oPoint.m_nY);
}
oBuilder.WriteString(L"<a:custGeom><a:pathLst><a:path>");
oBuilder.WriteString(L"<a:moveTo><a:pt x=\"" + std::to_wstring(arPoints[0].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[0].m_nY) + L"\"/></a:moveTo>");
for (unsigned short ushIndex = 1; ushIndex < 4; ++ushIndex)
oBuilder.WriteString(L"<a:lnTo><a:pt x=\"" + std::to_wstring(arPoints[ushIndex].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[ushIndex].m_nY) + L"\"/></a:lnTo>");
oBuilder.WriteString(L"<a:lnTo><a:pt x=\"" + std::to_wstring(arPoints[0].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[0].m_nY) + L"\"/></a:lnTo>");
oBuilder.WriteString(L"</a:path></a:pathLst></a:custGeom>");
// oBuilder.WriteString(L"<a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom>");
break;
}
case EShapeObjectType::Polygon:
{
VECTOR<TPoint> arPoints{((const CCtrlShapePolygon*)pGeneralShape)->GetPoints()};
if (2 > arPoints.size())
break;
const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()};
for (TPoint& oPoint : arPoints)
{
oMatrix.ApplyToPoint(oPoint.m_nX, oPoint.m_nY);
oPoint.m_nX = Transform::HWPUINT2OOXML(oPoint.m_nX);
oPoint.m_nY = Transform::HWPUINT2OOXML(oPoint.m_nY);
}
oBuilder.WriteString(L"<a:custGeom><a:pathLst><a:path>");
oBuilder.WriteString(L"<a:moveTo><a:pt x=\"" + std::to_wstring(arPoints[0].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[0].m_nY) + L"\"/></a:moveTo>");
for (unsigned short ushIndex = 1; ushIndex < arPoints.size(); ++ushIndex)
oBuilder.WriteString(L"<a:lnTo><a:pt x=\"" + std::to_wstring(arPoints[ushIndex].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[ushIndex].m_nY) + L"\"/></a:lnTo>");
oBuilder.WriteString(L"</a:path></a:pathLst></a:custGeom>");
break;
}
case EShapeObjectType::Curve:
{
VECTOR<TPoint> arPoints{((const CCtrlShapeCurve*)pGeneralShape)->GetPoints()};
if (2 > arPoints.size())
break;
const TMatrix oMatrix{pGeneralShape->GetFinalMatrix()};
for (TPoint& oPoint : arPoints)
{
oPoint.m_nX = Transform::HWPUINT2OOXML(oPoint.m_nX);
oPoint.m_nY = Transform::HWPUINT2OOXML(oPoint.m_nY);
oMatrix.ApplyToPoint(oPoint.m_nX, oPoint.m_nY);
}
VECTOR<HWP_BYTE> arSegmentType{((const CCtrlShapeCurve*)pGeneralShape)->GetSegmentsType()};
oBuilder.WriteString(L"<a:custGeom><a:pathLst><a:path>");
oBuilder.WriteString(L"<a:moveTo><a:pt x=\"" + std::to_wstring(arPoints[0].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[0].m_nY) + L"\"/></a:moveTo>");
for (unsigned short ushIndex = 0; ushIndex < arSegmentType.size(); ++ushIndex)
{
if (0x01 == arSegmentType[ushIndex])
{
oBuilder.WriteString(L"<a:cubicBezTo>");
oBuilder.WriteString(L"<a:pt x=\"" + std::to_wstring(arPoints[ushIndex + 1].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[ushIndex + 1].m_nY) + L"\"/>");
oBuilder.WriteString(L"<a:pt x=\"" + std::to_wstring(arPoints[ushIndex + 2].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[ushIndex + 2].m_nY) + L"\"/>");
oBuilder.WriteString(L"<a:pt x=\"" + std::to_wstring(arPoints[ushIndex + 3].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[ushIndex + 3].m_nY) + L"\"/>");
oBuilder.WriteString(L"</a:cubicBezTo>");
ushIndex += 2;
}
else
oBuilder.WriteString(L"<a:lnTo><a:pt x=\"" + std::to_wstring(arPoints[ushIndex + 1].m_nX) + L"\" y=\"" + std::to_wstring(arPoints[ushIndex + 1].m_nY) + L"\"/></a:lnTo>");
}
oBuilder.WriteString(L"</a:path></a:pathLst></a:custGeom>");
break;
}
case EShapeObjectType::Ole:
case EShapeObjectType::Picture:
case EShapeObjectType::Unknown:
break;
}
const CFill *pFill = pGeneralShape->GetFill();
if (nullptr == pFill || pFill->NoneFill())
oBuilder.WriteString(L"<a:noFill/>");
else if (pFill->ColorFill())
oBuilder.WriteString(L"<a:solidFill><a:srgbClr val=\"" + Transform::IntColorToHEX(pFill->GetFaceColor()) + L"\"/></a:solidFill>");
else if (pFill->ImageFill())
{
const HWP_STRING sPictureId = SavePicture(pFill->GetBinItemID(), oState);
if (!sPictureId.empty())
oBuilder.WriteString(L"<a:blipFill><a:blip r:embed=\"" + sPictureId + L"\"><a:extLst><a:ext uri=\"{28A0092B-C50C-407E-A947-70E740481C1C}\"><a14:useLocalDpi xmlns:a14=\"http://schemas.microsoft.com/office/drawing/2010/main\" val=\"0\"/></a:ext></a:extLst></a:blip><a:srcRect/><a:stretch><a:fillRect/></a:stretch></a:blipFill>");
else
oBuilder.WriteString(L"<a:noFill/>");
}
WriteLineSettings(pGeneralShape, oBuilder);
oBuilder.WriteString(L"</wps:spPr>");
unsigned int nCountParagraphs = pGeneralShape->GetCountParagraphs();
if (0 < nCountParagraphs)
{
oBuilder.WriteString(L"<wps:txbx><w:txbxContent>");
TConversionState oShapeState;
oShapeState.m_bInTextBox = true;
for (unsigned int unParaIndex = 0; unParaIndex < nCountParagraphs; ++unParaIndex)
WriteParagraph(pGeneralShape->GetParagraphs(unParaIndex), oBuilder, oShapeState);
oBuilder.WriteString(L"</w:txbxContent></wps:txbx>");
}
oBuilder.WriteString(L"<wps:bodyPr/>");
oBuilder.WriteString(L"</wps:wsp></a:graphicData></a:graphic>");
CloseDrawingNode(pGeneralShape, oBuilder);
oBuilder.WriteString(L"</mc:Choice></mc:AlternateContent></w:r>");
}
void CConverter2OOXML::WriteEqEditShape(const CCtrlEqEdit* pEqEditShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
//TODO:: добавить конвертацию eqn формулы в ooxml
++m_ushEquationCount;
WriteCaption((const CCtrlCommon*)pEqEditShape, oBuilder, oState);
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:r>");
oBuilder.WriteString(L"<w:t xml:space=\"preserve\">");
oBuilder.WriteEncodeXmlString(pEqEditShape->GetEqn());
oBuilder.WriteString(L"</w:t></w:r>");
}
void CConverter2OOXML::WriteOleShape(const CCtrlShapeOle* pOleShape, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
//TODO:: добавить конвертацию hwp ole -> ooxml chart
//TODO:: необходимо добавить поддержку формата "Hwp Document File Formats - Charts" (для случаев, когда нет ooxml представления)
// Пока можем вытащить лишь ooxml представление данных
// Реализовать с использованием pole.h?
if (nullptr == m_pContext)
return;
CHWPStream oBuffer;
HWP_STRING sFileName;
if (!m_pContext->GetBinBytes(pOleShape->GetBinDataID(), oBuffer, sFileName))
return;
m_oOleConverter.CreateChart(oBuffer);
const unsigned int unChartIndex = m_oOleConverter.GetChartsCount();
if (0 == unChartIndex)
return;
++m_ushShapeCount;
WriteCaption((const CCtrlCommon*)pOleShape, oBuilder, oState);
const std::wstring wsWidth = std::to_wstring(Transform::HWPUINT2OOXML(pOleShape->GetWidth()));
const std::wstring wsHeight = std::to_wstring(Transform::HWPUINT2OOXML(pOleShape->GetHeight()));
const std::wstring wsRelID = AddRelationship(L"chart", L"charts/chart" + std::to_wstring(unChartIndex) + L".xml", &oState);
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:r><w:rPr><w:noProof/></w:rPr>");
OpenDrawingNode(pOleShape, oBuilder);
oBuilder.WriteString(L"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">");
oBuilder.WriteString(L"<a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/chart\">");
oBuilder.WriteString(L"<c:chart xmlns:c=\"http://schemas.openxmlformats.org/drawingml/2006/chart\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"" + wsRelID + L"\"/>");
oBuilder.WriteString(L"</a:graphicData></a:graphic>");
CloseDrawingNode(pOleShape, oBuilder);
oBuilder.WriteString(L"</w:r>");
AddContentType(L"charts/chart" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.openxmlformats-officedocument.drawingml.chart+xml");
AddContentType(L"charts/style" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.ms-office.chartstyle+xml");
AddContentType(L"charts/colors" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.ms-office.chartcolorstyle+xml");
}
void CConverter2OOXML::WriteContainer(const CCtrlContainer* pContainer, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
for (const CCtrlGeneralShape* pGeneralShape : pContainer->GetShapes())
WriteShape(pGeneralShape, shParaShapeID, shParaStyleID, oBuilder, oState, pContainer);
}
void CConverter2OOXML::WriteSectionSettings(TConversionState& oState)
{
m_oDocXml.WriteString(L"<w:sectPr>");
if (nullptr != oState.m_pSectionDef)
{
std::vector<const CCtrlHeadFoot*> arCtrlsHeadFoot;
switch (m_pContext->GetType())
{
case EHanType::HWP:
{
arCtrlsHeadFoot = oState.m_pSectionDef->GetHeaderFooters();
break;
}
case EHanType::HWPX:
case EHanType::HWPML:
{
arCtrlsHeadFoot = oState.m_arCtrlsHeadFoot;
oState.m_arCtrlsHeadFoot.clear();
break;
}
default:
return;
}
#define WRITE_ID(id)\
if (!id.empty() && id.length() > 6)\
{\
const std::wstring wsType = id.substr(0, 6);\
AddContentType(id, L"application/vnd.openxmlformats-officedocument.wordprocessingml." + wsType + L"+xml");\
m_oDocXml.WriteString(L"<w:" + wsType + L"Reference w:type=\"default\" r:id=\"" + AddRelationship(wsType, id, &oState) + L"\"/>");\
}
if (nullptr != oState.m_pPageNum)
{
const std::wstring wsID = m_oFootnoteConverter.CreatePageNum(oState.m_pPageNum, *this);
WRITE_ID(wsID);
oState.m_pPageNum = nullptr;
}
for (const CCtrlHeadFoot* pCtrlHeadFoot : arCtrlsHeadFoot)
{
const std::wstring wsID = m_oFootnoteConverter.CreateHeadOrFoot((const CCtrlHeadFoot*)pCtrlHeadFoot, *this);
WRITE_ID(wsID);
}
}
if (nullptr != oState.m_pNewNumber && ENumType::PAGE == oState.m_pNewNumber->GetNumType())
m_oDocXml.WriteString(L"<w:pgNumType w:start=\"" + std::to_wstring(oState.m_pNewNumber->GetNum()) + L"\"/>");
const CPage *pPage = (nullptr != oState.m_pSectionDef) ? oState.m_pSectionDef->GetPage() : nullptr;
if (nullptr == pPage)
{
//DEFAULT_VALUE
m_oDocXml.WriteString(L"<w:pgSz w:w=\"11906\" w:h=\"16838\"/>");
m_oDocXml.WriteString(L"<w:pgMar w:top=\"1134\" w:right=\"850\" w:bottom=\"1134\" w:left=\"1701\" w:header=\"708\" w:footer=\"708\" w:gutter=\"0\"/>");
}
else
{
m_oDocXml.WriteString(L"<w:pgSz w:w=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetWidth())) + L"\" w:h=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetHeight())) + L"\"/>");
m_oDocXml.WriteString(L"<w:pgMar w:top=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginTop() + pPage->GetMarginHeader())) + L"\" w:right=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginRight())) + L"\" w:bottom=\"" +
std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginBottom() + pPage->GetMarginFooter())) + L"\" w:left=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginRight())) + L"\" w:header=\"" +
std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginHeader())) + L"\" w:footer=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginFooter())) + L"\" w:gutter=\"" +
std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginGutter())) + L"\"/>");
}
if (nullptr != oState.m_pColumnDef && 1 < oState.m_pColumnDef->GetColCount())
{
//TODO:: Добавить поддержку остальный свойств
m_oDocXml.WriteString(L"<w:cols w:num=\"" + std::to_wstring(oState.m_pColumnDef->GetColCount()) + L"\" w:space=\"454\"");
if (ELineStyle2::NONE != oState.m_pColumnDef->GetColLineStyle())
m_oDocXml.WriteString(L" w:sep=\"true\"");
m_oDocXml.WriteString(L"/>");
}
else
m_oDocXml.WriteString(L"<w:cols w:space=\"708\"/>");
m_oDocXml.WriteString(L"</w:sectPr>");
}
void CConverter2OOXML::WritePicture(const CCtrlShapePic* pCtrlPic, short shParaShapeId, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pCtrlPic)
return;
HWP_STRING sPictureID = SavePicture(pCtrlPic->GetBinDataID(), oState);
if (sPictureID.empty())
return;
++m_ushShapeCount;
WriteCaption((const CCtrlCommon*)pCtrlPic, oBuilder, oState);
OpenParagraph(shParaShapeId, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:r><w:rPr><w:noProof/></w:rPr>");
OpenDrawingNode(pCtrlPic, oBuilder);
oBuilder.WriteString(L"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">");
oBuilder.WriteString(L"<a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">");
oBuilder.WriteString(L"<pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">");
oBuilder.WriteString(L"<pic:nvPicPr><pic:cNvPr id=\"" + std::to_wstring(m_ushShapeCount) + L"\" name=\"Shape " + std::to_wstring(m_ushShapeCount) + L"\"/>");
oBuilder.WriteString(L"<pic:cNvPicPr/></pic:nvPicPr>");
oBuilder.WriteString(L"<pic:blipFill><a:blip r:embed=\"" + sPictureID + L"\"><a:extLst><a:ext uri=\"{28A0092B-C50C-407E-A947-70E740481C1C}\"><a14:useLocalDpi xmlns:a14=\"http://schemas.microsoft.com/office/drawing/2010/main\" val=\"0\"/></a:ext></a:extLst></a:blip><a:srcRect/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>");
oBuilder.WriteString(L"<pic:spPr bwMode=\"auto\">");
oBuilder.WriteString(L"<a:xfrm");
if (pCtrlPic->HorzFlip())
oBuilder.WriteString(L" flipH=\"1\"");
if (pCtrlPic->VertFlip())
oBuilder.WriteString(L" flipV=\"1\"");
oBuilder.WriteString(L"><a:off x=\"0\" y=\"0\"/><a:ext cx=\"" + std::to_wstring(pCtrlPic->GetFinalWidth()) + L"\" cy=\"" + std::to_wstring(pCtrlPic->GetFinalHeight()) + L"\"/></a:xfrm>");
oBuilder.WriteString(L"<a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom><a:noFill/>");
WriteBorderSettings(pCtrlPic, oBuilder);
oBuilder.WriteString(L"</pic:spPr></pic:pic></a:graphicData></a:graphic>");
CloseDrawingNode(pCtrlPic, oBuilder);
oBuilder.WriteString(L"</w:r>");
}
void CConverter2OOXML::WriteVideo(const CCtrlShapeVideo* pCtrlVideo, short shParaShapeId, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pCtrlVideo || 1 != pCtrlVideo->GetVideoType())
return;
HWP_STRING sPictureID = SavePicture(pCtrlVideo->GetThumnailBinID(), oState);
if (sPictureID.empty())
return;
++m_ushShapeCount;
WriteCaption((const CCtrlCommon*)pCtrlVideo, oBuilder, oState);
OpenParagraph(shParaShapeId, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:r><w:rPr><w:noProof/></w:rPr>");
OpenDrawingNode(pCtrlVideo, oBuilder);
oBuilder.WriteString(L"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">");
oBuilder.WriteString(L"<a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">");
oBuilder.WriteString(L"<pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">");
oBuilder.WriteString(L"<pic:nvPicPr><pic:cNvPr id=\"" + std::to_wstring(m_ushShapeCount) + L"\" name=\"Video " + std::to_wstring(m_ushShapeCount) + L"\" descr=\"" + pCtrlVideo->GetDesc() + L"\">");
oBuilder.WriteString(L"<a:hlinkClick r:id=\"" + AddRelationship(L"hyperlink", pCtrlVideo->GetWebUrl(), &oState) + L"\"/></pic:cNvPr>");
oBuilder.WriteString(L"<pic:cNvPicPr/></pic:nvPicPr>");
oBuilder.WriteString(L"<pic:blipFill><a:blip r:embed=\"" + sPictureID + L"\"><a:extLst>");
oBuilder.WriteString(L"<a:ext uri=\"{28A0092B-C50C-407E-A947-70E740481C1C}\"><a14:useLocalDpi xmlns:a14=\"http://schemas.microsoft.com/office/drawing/2010/main\" val=\"0\"/></a:ext>");
const int nIFrameWidth = (int)((double)Transform::HWPUINT2OOXML(pCtrlVideo->GetWidth()) / 22860.);
const int nIFrameHeight = (int)((double)Transform::HWPUINT2OOXML(pCtrlVideo->GetHeight()) / 22860.);
oBuilder.WriteString(L"<a:ext uri=\"{C809E66F-F1BF-436E-b5F7-EEA9579F0CBA}\">");
oBuilder.WriteString(L"<wp15:webVideoPr xmlns:wp15=\"http://schemas.microsoft.com/office/word/2012/wordprocessingDrawing\" embeddedHtml=\"");
oBuilder.WriteEncodeXmlString(L"<iframe width=\"" + std::to_wstring(nIFrameWidth) + L"\" height=\"" + std::to_wstring(nIFrameHeight) + L"\"");
oBuilder.WriteEncodeXmlString(L"src=\"" + pCtrlVideo->GetWebUrl() + L"\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen=\"\" title=\"\" sandbox=\"allow-scripts allow-same-origin allow-popups\"></iframe>");
oBuilder.WriteString(L"\" h=\"" + std::to_wstring(nIFrameWidth) + L"\" w=\"" + std::to_wstring(nIFrameHeight) + L"\"/></a:ext>");
oBuilder.WriteString(L"</a:extLst></a:blip><a:srcRect/><a:stretch><a:fillRect/></a:stretch></pic:blipFill>");
oBuilder.WriteString(L"<pic:spPr bwMode=\"auto\"><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlVideo->GetFinalWidth())) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlVideo->GetFinalHeight())) + L"\"/></a:xfrm>");
oBuilder.WriteString(L"<a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln></pic:spPr></pic:pic></a:graphicData></a:graphic>");
CloseDrawingNode(pCtrlVideo, oBuilder);
oBuilder.WriteString(L"</w:r>");
}
bool CConverter2OOXML::SaveSVGFile(const HWP_STRING& sSVG, HWP_STRING& sFileName)
{
if (sSVG.empty())
return false;
NSFonts::IApplicationFonts* pFonts = NSFonts::NSApplication::Create();
pFonts->Initialize();
MetaFile::IMetaFile* pSvgReader = MetaFile::Create(pFonts);
if (!pSvgReader->LoadFromString(sSVG))
{
RELEASEINTERFACE(pSvgReader);
RELEASEINTERFACE(pFonts);
return false;
}
double dX, dY, dW, dH;
pSvgReader->GetBounds(&dX, &dY, &dW, &dH);
if (dW < 0) dW = -dW;
if (dH < 0) dH = -dH;
sFileName = sFileName.substr(0, sFileName.find(L'.'));
sFileName += L".png";
const std::wstring wsImagePath{m_sTempDirectory + L"/word/media/" + sFileName};
pSvgReader->ConvertToRaster(wsImagePath.c_str(), 4, dW, dH);
RELEASEINTERFACE(pSvgReader);
RELEASEINTERFACE(pFonts);
return true;
}
HWP_STRING CConverter2OOXML::SavePicture(const HWP_STRING& sBinItemId, TConversionState& oState)
{
if (nullptr == m_pContext || sBinItemId.empty())
return HWP_STRING();
//TODO:: добавить поддержку устновки размеров изображения из свойств шейпа
CHWPStream oBuffer;
HWP_STRING sFileName;
if (!m_pContext->GetBinBytes(sBinItemId, oBuffer, sFileName))
return HWP_STRING();
oBuffer.MoveToStart();
if (IsRasterFormat(NSFile::GetFileExtention(sFileName)))
{
NSFile::CFileBinary oFile;
oFile.CreateFileW(m_sTempDirectory + L"/word/media/" + sFileName);
if (!oFile.WriteFile((unsigned char*)oBuffer.GetCurPtr(), oBuffer.GetSize()))
{
oFile.CloseFile();
return HWP_STRING();
}
oFile.CloseFile();
}
else if (L"svg" == NSFile::GetFileExtention(sFileName))
{
std::string sSVG(oBuffer.GetCurPtr(), oBuffer.GetSize());
if (!SaveSVGFile(UTF8_TO_U(sSVG), sFileName))
return HWP_STRING();
}
AddContentType(L"media/" + sFileName, L"image/" + NSFile::GetFileExtention(sFileName));
return AddRelationship(L"image", L"media/" + sFileName, &oState);
}
void CConverter2OOXML::WriteRunnerStyle(short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const CRunnerStyle& sExternStyles)
{
if (nullptr == m_pContext)
return;
oBuilder.WriteString(L"<w:rPr>");
if (m_oStyleConverter.GetLastCharShapeId() != shCharShapeID)
m_oStyleConverter.WriteDifferenceRunnerStyles(m_oStyleConverter.GetLastCharShapeId(), shCharShapeID, *m_pContext, oBuilder);
const CHWPRecordCharShape* pCharShape = dynamic_cast<const CHWPRecordCharShape*>(m_pContext->GetCharShape(shCharShapeID));
if (nullptr != pCharShape)
{
WriteTextBorderStyle(pCharShape->GetBorderFillID(), oBuilder, oState);
oState.m_ushLastCharShapeId = shCharShapeID;
}
m_oStyleConverter.WriteRunnerProperties(sExternStyles, oBuilder);
oBuilder.WriteString(L"</w:rPr>");
switch(oState.m_eBreakType)
{
case TConversionState::EBreakType::Page:
oBuilder.WriteString(L"<w:br w:type=\"page\"/>"); break;
case TConversionState::EBreakType::Column:
oBuilder.WriteString(L"<w:br w:type=\"column\"/>"); break;
case TConversionState::EBreakType::TextWrapping:
oBuilder.WriteString(L"<w:br/>"); break;
case TConversionState::EBreakType::None:
break;
}
oState.m_eBreakType = TConversionState::EBreakType::None;
}
void CConverter2OOXML::WriteTextBorderStyle(short shBorderFillId, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
const CHWPRecordBorderFill* pBorderFill = dynamic_cast<const CHWPRecordBorderFill*>(m_pContext->GetBorderFill(shBorderFillId));
if (nullptr == pBorderFill)
return;
TBorder oBorder{pBorderFill->GetLeftBorder()};
if (ELineStyle2::NONE == oBorder.m_eStyle)
return;
WriteBorder(pBorderFill->GetLeftBorder(), L"bdr", oBuilder);
}
void CConverter2OOXML::OpenDrawingNode(const CCtrlObjElement* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
oBuilder.WriteString(L"<w:drawing>");
if (pCtrlShape->GetTreatAsChar())
{
oBuilder.WriteString(L"<wp:inline distT=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetTopOutMargin() / 10)) +
L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomOutMargin() / 10)) +
L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftOutMargin() / 10)) +
L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightOutMargin() / 10)) +
L"\">");
WriteShapeExtent(pCtrlShape, oBuilder);
}
else
{
oBuilder.WriteString(L"<wp:anchor behindDoc=\"" + std::wstring((ETextWrap::BEHIND_TEXT == pCtrlShape->GetTextWrap() ? L"1" : L"0")) +
L"\" relativeHeight=\"" + std::to_wstring(pCtrlShape->GetZOrder()) +
L"\" distT=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetTopOutMargin() / 10)) +
L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomOutMargin() / 10)) +
L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftOutMargin() / 10)) +
L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightOutMargin() / 10)) +
L"\" simplePos=\"0\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">");
WriteShapePosition(pCtrlShape, oBuilder);
WriteShapeExtent(pCtrlShape, oBuilder);
WriteShapeWrapMode(pCtrlShape, oBuilder);
}
WriteShapeProperty(pCtrlShape, oBuilder);
}
void CConverter2OOXML::CloseDrawingNode(const CCtrlObjElement* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
if (pCtrlShape->GetTreatAsChar())
oBuilder.WriteString(L"</wp:inline>");
else
oBuilder.WriteString(L"</wp:anchor>");
oBuilder.WriteString(L"</w:drawing>");
}
HWP_STRING GetVRelativeFrom(EVRelTo eRelTo)
{
switch (eRelTo)
{
case EVRelTo::PARA:
return L"paragraph";
case EVRelTo::PAPER:
case EVRelTo::PAGE:
return L"page";
}
}
HWP_STRING GetHRelativeFrom(EHRelTo eRelTo)
{
switch (eRelTo)
{
case EHRelTo::PAPER:
case EHRelTo::PAGE:
return L"page";
case EHRelTo::COLUMN:
return L"column";
case EHRelTo::PARA:
return L"margin";
}
}
void CConverter2OOXML::WriteShapeProperty(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
oBuilder.WriteString(L"<wp:docPr id=\"" + std::to_wstring(m_ushShapeCount) + L"\" name=\"Shape " + std::to_wstring(m_ushShapeCount) + L"\" descr=\"");
oBuilder.WriteEncodeXmlString(pCtrlShape->GetDesc());
oBuilder.WriteString(L"\"/>");
oBuilder.WriteString(L"<wp:cNvGraphicFramePr/>");
}
void CConverter2OOXML::WriteShapePosition(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
oBuilder.WriteString(L"<wp:simplePos x=\"0\" y=\"0\"/>");
const int nHorzOffset = pCtrlShape->GetHorzOffset();
const int nVertOffset = pCtrlShape->GetVertOffset();
oBuilder.WriteString(L"<wp:positionH relativeFrom=\"" + GetHRelativeFrom(pCtrlShape->GetHorzRelTo()) + L"\"><wp:posOffset>" + std::to_wstring(Transform::HWPUINT2OOXML(nHorzOffset)) + L"</wp:posOffset></wp:positionH>");
oBuilder.WriteString(L"<wp:positionV relativeFrom=\"" + GetVRelativeFrom(pCtrlShape->GetVertRelTo()) + L"\"><wp:posOffset>" + std::to_wstring(Transform::HWPUINT2OOXML(nVertOffset)) + L"</wp:posOffset></wp:positionV>");
}
void CConverter2OOXML::WriteShapeExtent(const CCtrlObjElement* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
const int nFinalWidth = std::abs(pCtrlShape->GetFinalWidth());
const int nFinalHeight = std::abs(pCtrlShape->GetFinalHeight());
oBuilder.WriteString(L"<wp:extent cx=\"" + std::to_wstring(Transform::HWPUINT2OOXML(nFinalWidth)) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(nFinalHeight)) + L"\"/>");
oBuilder.WriteString(L"<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>");
}
void CConverter2OOXML::WriteShapeWrapMode(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
switch (pCtrlShape->GetTextWrap())
{
case ETextWrap::SQUARE:
{
oBuilder.WriteString(L"<wp:wrapSquare wrapText=\"");
switch (pCtrlShape->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"<wp:wrapTopAndBottom/>");
break;
}
case ETextWrap::BEHIND_TEXT:
case ETextWrap::IN_FRONT_OF_TEXT:
default:
{
oBuilder.WriteString(L"<wp:wrapNone/>");
break;
}
}
}
void CConverter2OOXML::OpenParagraph(short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (oState.m_bOpenedP)
return;
oBuilder.WriteString(L"<w:p>");
oState.m_bOpenedP = true;
WriteParagraphProperties(shParaShapeID, shParaStyleID, oBuilder, oState);
}
void CConverter2OOXML::CloseParagraph(NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (!oState.m_bOpenedP)
return;
oBuilder.WriteString(L"</w:p>");
oState.m_bOpenedP = false;
oState.m_oLastNode.m_unParaIndex = oState.m_unParaIndex;
oState.m_oLastNode.m_eType = TConversionState::TLastNode::ELastNodeType::Paragraph;
}
void CConverter2OOXML::WriteText(const CParaText* pParaText, const std::vector<TRangeTag>& arRangeTags, short shParaShapeID, short shParaStyleID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pParaText)
return;
if (arRangeTags.empty())
{
WriteText(pParaText->GetText(), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState);
return;
}
HWP_STRING wsText = pParaText->GetText();
int nParaTextPosition = pParaText->GetStartIDx();
int unStartText = 0;
TColor *pHighlightColor = nullptr;
for (size_t unTextPosition = 0; unTextPosition < wsText.length(); ++unTextPosition)
{
for (const TRangeTag& oRangeTag : arRangeTags)
{
if (unTextPosition + nParaTextPosition == oRangeTag.m_nStartPos)
{
WriteText(wsText.substr(unStartText, unTextPosition - unStartText), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState);
unStartText = unTextPosition;
switch (oRangeTag.m_chType)
{
case 0x02: //highlight
{
pHighlightColor = new TColor{(unsigned char)oRangeTag.m_arData[0], (unsigned char)oRangeTag.m_arData[1], (unsigned char)oRangeTag.m_arData[2]};
break;
}
default:
break;
}
}
else if (unTextPosition + nParaTextPosition == oRangeTag.m_nEndPos)
{
if (nullptr == pHighlightColor)
{
WriteText(wsText.substr(unStartText, unTextPosition - unStartText), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState);
unStartText = unTextPosition;
continue;
}
CRunnerStyle oRunnerStyle;
oRunnerStyle.SetHighlight(NormalizeHighlightColor(*pHighlightColor));
WriteText(wsText.substr(unStartText, unTextPosition - unStartText), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState, oRunnerStyle);
unStartText = unTextPosition;
switch (oRangeTag.m_chType)
{
case 0x02: //highlight
{
if (nullptr != pHighlightColor)
{
delete pHighlightColor;
pHighlightColor = nullptr;
}
break;
}
default:
break;
}
}
}
}
if (unStartText < wsText.length())
WriteText(wsText.substr(unStartText), shParaShapeID, shParaStyleID, pParaText->GetCharShapeID(), oBuilder, oState);
}
std::vector<std::wstring> SplitText(const std::wstring& wsText)
{
if (wsText.empty())
return std::vector<std::wstring>{L""};
std::vector<std::wstring> arTexts;
std::wstring wsCurrentText;
bool bWasLetter = iswalpha(wsText[0]);
wsCurrentText.push_back(wsText[0]);
for (unsigned int unIndex = 1; unIndex < wsText.length(); ++unIndex)
{
bool bCurrentIsLetter = iswalnum(wsText[unIndex]);
if (bCurrentIsLetter != bWasLetter)
{
arTexts.push_back(wsCurrentText);
wsCurrentText.clear();
bWasLetter = bCurrentIsLetter;
}
wsCurrentText.push_back(wsText[unIndex]);
}
if (!wsCurrentText.empty())
arTexts.push_back(wsCurrentText);
return arTexts;
}
void CConverter2OOXML::WriteText(const HWP_STRING& wsText, short shParaShapeID, short shParaStyleID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const CRunnerStyle& oExternalStyle)
{
if (!oState.m_bOpenedP && wsText.empty())
return;
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
if (wsText.empty())
{
oBuilder.WriteString(L"<w:r>");
WriteRunnerStyle(shCharShapeID, oBuilder, oState, oExternalStyle);
oBuilder.WriteString(L"</w:r>");
return;
}
oBuilder.WriteString(L"<w:r>");
WriteRunnerStyle(shCharShapeID, oBuilder, oState, oExternalStyle);
oBuilder.WriteString(L"<w:t");
bool bNeedPreserve = (wsText.cend() != std::find_if(wsText.cbegin(), wsText.cend(), [](wchar_t wChar){ return iswspace(wChar); }));
bool bNeedAddSpace = false;
if (oState.m_bIsNote && !iswspace(wsText[0]))
bNeedAddSpace = true;
if (bNeedPreserve || bNeedAddSpace)
oBuilder.WriteString(L" xml:space=\"preserve\">");
else
oBuilder.WriteString(L">");
if (bNeedAddSpace)
oBuilder.WriteString(L" ");
oBuilder.WriteEncodeXmlString(wsText);
oBuilder.WriteString(L"</w:t></w:r>");
return;
for (const std::wstring& wsTextElement : SplitText(wsText))
{
oBuilder.WriteString(L"<w:r>");
WriteRunnerStyle(shCharShapeID, oBuilder, oState, oExternalStyle);
if (!wsTextElement.empty())
{
oBuilder.WriteString(L"<w:t");
if (!iswalnum(wsTextElement.front()))
oBuilder.WriteString(L" xml:space=\"preserve\"");
oBuilder.WriteString(L">");
oBuilder.WriteEncodeXmlString(wsTextElement);
oBuilder.WriteString(L"</w:t>");
}
oBuilder.WriteString(L"</w:r>");
}
}
void CConverter2OOXML::WriteLineSettings(const CCtrlGeneralShape* pCtrlGeneralShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlGeneralShape)
return;
WriteLineSettings({pCtrlGeneralShape->GetLineStyle(), pCtrlGeneralShape->GetLineColor(),
pCtrlGeneralShape->GetLineThick(), 1,
pCtrlGeneralShape->GetLineHeadStyle(), pCtrlGeneralShape->GetLineHeadSize(),
pCtrlGeneralShape->GetLineTailStyle(), pCtrlGeneralShape->GetLineTailSize()}, oBuilder);
}
void WriteLineArrowStyles(ELineArrowStyle eArrowStyle, ELineArrowSize eArrowSize, NSStringUtils::CStringBuilder& oBuilder)
{
switch (eArrowStyle)
{
case ELineArrowStyle::ARROW: oBuilder.WriteString(L" type=\"triangle\""); break;
case ELineArrowStyle::SPEAR: oBuilder.WriteString(L" type=\"arrow\""); break;
case ELineArrowStyle::CONCAVE_ARROW: oBuilder.WriteString(L" type=\"stealth\""); break;
case ELineArrowStyle::DIAMOND:
case ELineArrowStyle::EMPTY_DIAMOND:
case ELineArrowStyle::BOX:
case ELineArrowStyle::EMPTY_BOX: oBuilder.WriteString(L" type=\"diamond\""); break;
case ELineArrowStyle::CIRCLE:
case ELineArrowStyle::EMPTY_CIRCLE: oBuilder.WriteString(L" type=\"oval\""); break;
case ELineArrowStyle::NORMAL:
break;
}
switch (eArrowSize)
{
case ELineArrowSize::SMALL_SMALL: oBuilder.WriteString(L" w=\"sm\" len=\"sm\""); break;
case ELineArrowSize::SMALL_MEDIUM: oBuilder.WriteString(L" w=\"sm\" len=\"med\""); break;
case ELineArrowSize::SMALL_LARGE: oBuilder.WriteString(L" w=\"sm\" len=\"lg\""); break;
case ELineArrowSize::MEDIUM_SMALL: oBuilder.WriteString(L" w=\"med\" len=\"sm\""); break;
case ELineArrowSize::MEDIUM_MEDIUM: oBuilder.WriteString(L" w=\"med\" len=\"med\""); break;
case ELineArrowSize::MEDIUM_LARGE: oBuilder.WriteString(L" w=\"med\" len=\"lg\""); break;
case ELineArrowSize::LARGE_SMALL: oBuilder.WriteString(L" w=\"lg\" len=\"sm\""); break;
case ELineArrowSize::LARGE_MEDIUM: oBuilder.WriteString(L" w=\"lg\" len=\"med\""); break;
case ELineArrowSize::LARGE_LARGE: oBuilder.WriteString(L" w=\"lg\" len=\"lg\""); break;
break;
}
}
void CConverter2OOXML::WriteLineSettings(const TLineData& oLineData, NSStringUtils::CStringBuilder& oBuilder)
{
if (ELineStyle2::NONE == oLineData.m_eStyle)
{
oBuilder.WriteString(L"<a:ln><a:noFill/></a:ln>");
return;
}
int nThick{oLineData.m_nThick};
if (0 == oLineData.m_nThick)
nThick = 100;
oBuilder.WriteString(L"<a:ln");
oBuilder.WriteString(L" w=\"" + std::to_wstring(Transform::HWPUINT2OOXML(nThick)) + L"\" cap=\"sq\"");
switch (oLineData.m_eStyle)
{
case ELineStyle2::DOUBLE_SLIM:
{
oBuilder.WriteString(L" cmpd=\"dbl\"");
break;
}
case ELineStyle2::SLIM_THICK:
{
oBuilder.WriteString(L" cmpd=\"thickThin\"");
break;
}
case ELineStyle2::THICK_SLIM:
{
oBuilder.WriteString(L" cmpd=\"thinThick\"");
break;
}
case ELineStyle2::SLIM_THICK_SLIM:
{
oBuilder.WriteString(L" cmpd=\"tri\"");
break;
}
default:
break;
}
oBuilder.WriteString(L">");
oBuilder.WriteString(L"<a:solidFill><a:srgbClr val=\"" + Transform::IntColorToHEX(oLineData.m_nColor) + L"\"/></a:solidFill>");
switch (oLineData.m_eStyle)
{
case ELineStyle2::DASH:
{
oBuilder.WriteString(L"<a:prstDash val=\"dash\"/>");
break;
}
case ELineStyle2::DOT:
{
oBuilder.WriteString(L"<a:prstDash val=\"dot\"/>");
break;
}
case ELineStyle2::DASH_DOT:
{
oBuilder.WriteString(L"<a:prstDash val=\"dashDot\"/>");
break;
}
case ELineStyle2::DASH_DOT_DOT:
{
oBuilder.WriteString(L"<a:prstDash val=\"sysDashDot\"/>");
break;
}
case ELineStyle2::LONG_DASH:
{
oBuilder.WriteString(L"<a:prstDash val=\"lgDash\"/>");
break;
}
case ELineStyle2::CIRCLE:
{
oBuilder.WriteString(L"<a:prstDash val=\"dot\"/>");
break;
}
default:
break;
}
if (ELineArrowStyle::NORMAL != oLineData.m_eHeadStyle)
{
oBuilder.WriteString(L"<a:headEnd");
WriteLineArrowStyles(oLineData.m_eHeadStyle, oLineData.m_eHeadSize, oBuilder);
oBuilder.WriteString(L"/>");
}
if (ELineArrowStyle::NORMAL != oLineData.m_eTailStyle)
{
oBuilder.WriteString(L"<a:tailEnd ");
WriteLineArrowStyles(oLineData.m_eTailStyle, oLineData.m_eTailSize, oBuilder);
oBuilder.WriteString(L"/>");
}
switch (oLineData.m_nCompoundLineType)
{
case 0x00:
{
oBuilder.WriteString(L"<a:round/>");
break;
}
case 0x01:
{
oBuilder.WriteString(L"<a:miter lim=\"800000\"/>");
break;
}
}
oBuilder.WriteString(L"</a:ln>");
}
void CConverter2OOXML::WriteBorderSettings(const CCtrlShapePic* pCtrlPic, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlPic || nullptr == m_pContext)
return;
if (EHanType::HWP == m_pContext->GetType())
WriteLineSettings({pCtrlPic->GetBorderLineStyle(), pCtrlPic->GetBorderColor(),
pCtrlPic->GetBorderThick(), pCtrlPic->GetBorderCompoundLineType()},
oBuilder);
else if (EHanType::HWPX == m_pContext->GetType() ||
EHanType::HWPML == m_pContext->GetType())
WriteLineSettings({pCtrlPic->GetLineStyle(), pCtrlPic->GetLineColor(),
pCtrlPic->GetLineThick(), 1}, oBuilder);
}
void CConverter2OOXML::WriteAutoNumber(const CCtrlAutoNumber* pAutoNumber, short shParaShapeID, short shParaStyleID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pAutoNumber)
return;
unsigned short ushValue = 0;
HWP_STRING wsType;
//TODO:: лучше перейти не на ручной подсчет, а на автоматический в word (но там есть свои проблемы)
switch (pAutoNumber->GetNumType())
{
case ENumType::PAGE:
{
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:fldSimple w:instr=\"PAGE \\* ARABIC\"><w:r><w:t>1</w:t></w:r></w:fldSimple>");
return;
}
case ENumType::TOTAL_PAGE:
{
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:fldSimple w:instr=\"NUMPAGES \\* ARABIC\"><w:r><w:t>1</w:t></w:r></w:fldSimple>");
return;
}
case ENumType::FOOTNOTE:
{
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:r>");
CRunnerStyle oRunnerStyle;
oRunnerStyle.SetVerticalAlign(EVerticalAlignRun::Superscript);
WriteRunnerStyle(shCharShapeID, oBuilder, oState, oRunnerStyle);
oBuilder.WriteString(L"<w:footnoteRef/></w:r>");
return;
}
case ENumType::ENDNOTE:
{
OpenParagraph(shParaShapeID, shParaStyleID, oBuilder, oState);
oBuilder.WriteString(L"<w:r>");
CRunnerStyle oRunnerStyle;
oRunnerStyle.SetVerticalAlign(EVerticalAlignRun::Superscript);
WriteRunnerStyle(shCharShapeID, oBuilder, oState, oRunnerStyle);
oBuilder.WriteString(L"<w:endnoteRef/></w:r>");
return;
}
case ENumType::FIGURE:
{
wsType = L"Figure";
ushValue = m_ushShapeCount; break;
}
case ENumType::TABLE:
{
wsType = L"Table";
ushValue = m_ushTableCount; break;
}
case ENumType::EQUATION:
{
wsType = L"Equation";
ushValue = m_ushEquationCount; break;
}
}
if (0 == ushValue)
return;
if (!wsType.empty())
oBuilder.WriteString(L"<w:fldSimple w:instr=\" SEQ " + wsType + L" \\* ARABIC \">");
WriteText(std::to_wstring(ushValue), shParaShapeID, shParaStyleID, shCharShapeID, oBuilder, oState);
if (!wsType.empty())
oBuilder.WriteString(L"</w:fldSimple>");
}
HWP_STRING CConverter2OOXML::AddRelationship(const HWP_STRING& wsType, const HWP_STRING& wsTarget, TConversionState* pState)
{
if (wsType.empty() || wsTarget.empty())
return HWP_STRING();
VECTOR<TRelationship> *pRelationships = nullptr;
if (nullptr != pState && nullptr != pState->m_pRelationships)
pRelationships = pState->m_pRelationships;
else
pRelationships = &m_arRelationships;
VECTOR<TRelationship>::const_iterator itFound = std::find_if(pRelationships->cbegin(), pRelationships->cend(), [wsTarget](const TRelationship& oRelationship){ return wsTarget == oRelationship.m_wsTarget; });
if (pRelationships->cend() != itFound)
return itFound->m_wsID;
if (L"hyperlink" == wsType)
{
NSStringUtils::CStringBuilder oBuilder;
oBuilder.WriteEncodeXmlString(wsTarget);
pRelationships->push_back({L"rId" + std::to_wstring(pRelationships->size() + 1), wsType, oBuilder.GetData()});
}
else
pRelationships->push_back({L"rId" + std::to_wstring(pRelationships->size() + 1), wsType, wsTarget});
return pRelationships->back().m_wsID;
}
void CConverter2OOXML::AddContentType(const HWP_STRING& wsName, const HWP_STRING& wsType)
{
if (wsName.empty() || wsType.empty())
return;
VECTOR<TContentType>::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<TContentType>::const_iterator itFound = std::find_if(m_arDefaultContentType.cbegin(), m_arDefaultContentType.cend(), [wsName](const TContentType& oContentType){ return wsName == oContentType.m_wsName; });
if (m_arDefaultContentType.cend() != itFound)
return;
if (IsRasterFormat(wsName))
m_arDefaultContentType.push_back({wsName, L"image/" + wsName});
else if (L"xml" == wsName)
m_arDefaultContentType.push_back({wsName, L"application/xml"});
}
bool CConverter2OOXML::ConvertToFile(const HWP_STRING& sFilePath)
{
if (nullptr == m_pContext || sFilePath.empty())
return false;
CreateEmptyFiles();
Convert();
Close();
COfficeUtils oZip;
oZip.CompressFileOrDirectory(m_sTempDirectory, sFilePath);
return true;
}
bool CConverter2OOXML::ConvertToDir(const HWP_STRING& sDirectoryPath)
{
if (nullptr == m_pContext || sDirectoryPath.empty())
return false;
HWP_STRING sCurrentTempDir{m_sTempDirectory};
SetTempDirectory(sDirectoryPath);
CreateEmptyFiles();
Convert();
Close();
SetTempDirectory(sCurrentTempDir);
return true;
}
HWP_STRING CConverter2OOXML::GetTempDirectory() const
{
return m_sTempDirectory;
}
TLineData::TLineData(ELineStyle2 eStyle, int nColor,
int nThick, HWP_BYTE nCompoundLineType,
ELineArrowStyle eHeadStyle, ELineArrowSize eHeadSize,
ELineArrowStyle eTailStyle, ELineArrowSize eTailSize)
:m_eStyle(eStyle), m_nColor(nColor),
m_nThick(nThick), m_nCompoundLineType(nCompoundLineType),
m_eHeadStyle(eHeadStyle), m_eHeadSize(eHeadSize),
m_eTailStyle(eTailStyle), m_eTailSize(eTailSize)
{}
TLineData::TLineData(ELineStyle2 eStyle, int nColor,
int nThick, HWP_BYTE nCompoundLineType)
:m_eStyle(eStyle), m_nColor(nColor),
m_nThick(nThick), m_nCompoundLineType(nCompoundLineType),
m_eHeadStyle(ELineArrowStyle::NORMAL), m_eHeadSize(ELineArrowSize::SMALL_SMALL),
m_eTailStyle(ELineArrowStyle::NORMAL), m_eTailSize(ELineArrowSize::SMALL_SMALL)
{}
}