Files
Yajbir Singh f1b860b25c
Some checks failed
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++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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)
{}
}