Files
core/HwpFile/HwpDoc/Conversion/Converter2OOXML.cpp
2025-01-21 02:49:10 +03:00

1710 lines
69 KiB
C++
Raw 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 "../../../DesktopEditor/common/File.h"
#include "../../../DesktopEditor/common/Directory.h"
#include "../../../DesktopEditor/common/SystemUtils.h"
#include "../../../DesktopEditor/raster/BgraFrame.h"
#include "../../../OfficeUtils/src/OfficeUtils.h"
#include "../../../DesktopEditor/graphics/pro/Graphics.h"
#include "../Paragraph/ParaText.h"
#include "../Paragraph/CtrlTable.h"
#include "../Paragraph/CtrlEqEdit.h"
#include "../HWPElements/HWPRecordParaShape.h"
#include "../HWPElements/HWPRecordCharShape.h"
#include "Transform.h"
#define DEFAULT_FONT_FAMILY std::wstring(L"Arial")
#define DEFAULT_FONT_SIZE 18
#define DEFAULT_LANGUAGE std::wstring(L"en")
#define PARA_SPACING_SCALE 0.85
#define SPACING_SCALE_MS_WORD 1.21
namespace HWP
{
enum class EShapeObjectType
{
Arc,
Curve,
Ellipse,
Line,
Ole,
Picture,
Polygon,
Rectangle,
Unknown
};
EShapeObjectType GetShapeObjectType(const std::wstring& wsID)
{
if (L"cra$" == wsID)
return EShapeObjectType::Arc;
if (L"ruc$" == wsID)
return EShapeObjectType::Curve;
if (L"lle$" == wsID)
return EShapeObjectType::Ellipse;
if (L"nil$" == wsID || L"loc$" == wsID)
return EShapeObjectType::Line;
if (L"elo$" == wsID)
return EShapeObjectType::Ole;
if (L"cip$" == wsID)
return EShapeObjectType::Picture;
if (L"lop$" == wsID)
return EShapeObjectType::Polygon;
if (L"cer$" == wsID)
return EShapeObjectType::Rectangle;
return EShapeObjectType::Unknown;
}
CConverter2OOXML::CConverter2OOXML()
: m_pContext(nullptr), m_ushShapeCount(0), m_ushPageCount(1), m_ushTableCount(0), m_ushEquationCount(0)
{}
CConverter2OOXML::~CConverter2OOXML()
{}
void CConverter2OOXML::SetContext(CWriterContext* pContext)
{
m_pContext = pContext;
}
void CConverter2OOXML::SetTempDirectory(const HWP_STRING& sTempDirectory)
{
m_sTempDirectory = sTempDirectory;
m_oOleConverter.SetTempDir(m_sTempDirectory);
}
void CConverter2OOXML::CreateEmptyFiles()
{
NSDirectory::CreateDirectory(m_sTempDirectory + L"/_rels");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/docProps");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/_rels");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/media");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/theme");
// theme1.xml
std::wstring wsTheme = L"<?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");
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/>");
m_oStylesXml.WriteString(L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><w:styles 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\">");
m_oStylesXml.WriteString(L"<w:rPrDefault><w:rPr>");
m_oStylesXml.WriteString(L"<w:rFonts w:ascii=\"" + DEFAULT_FONT_FAMILY + L"\" w:eastAsia=\"" + DEFAULT_FONT_FAMILY + L"\" w:hAnsi=\"" + DEFAULT_FONT_FAMILY + L"\" w:cs=\"" + DEFAULT_FONT_FAMILY + L"\"/>");
m_oStylesXml.WriteString(L"<w:sz w:val=\"" + std::to_wstring(DEFAULT_FONT_SIZE) + L"\"/><w:szCs w:val=\"" + std::to_wstring(DEFAULT_FONT_SIZE) + L"\"/>");
m_oStylesXml.WriteString(L"<w:lang w:val=\"" + DEFAULT_LANGUAGE + L"\" w:eastAsia=\"en-US\" w:bidi=\"ar-SA\"/>");
m_oStylesXml.WriteString(L"</w:rPr></w:rPrDefault><w:pPrDefault/>");
m_oStylesXml.WriteString(L"<w:style w:type=\"paragraph\" w:styleId=\"normal\" w:default=\"1\"><w:name w:val=\"Normal\"/><w:qFormat/><w:rPr><w:rFonts w:eastAsiaTheme=\"minorEastAsia\"/>");
m_oStylesXml.WriteString(L"<w:sz w:val=\"" + std::to_wstring(DEFAULT_FONT_SIZE) + L"\"/><w:szCs w:val=\"" + std::to_wstring(DEFAULT_FONT_SIZE) + L"\"/>");
m_oStylesXml.WriteString(L"</w:rPr></w:style>");
m_oStylesXml.WriteString(L"<w:style w:type=\"paragraph\" w:styleId=\"li\"><w:name w:val=\"List Paragraph\"/><w:basedOn w:val=\"normal\"/><w:qFormat/><w:uiPriority w:val=\"34\"/><w:pPr><w:contextualSpacing w:val=\"true\"/><w:ind w:left=\"720\"/></w:pPr></w:style>");
m_oStylesXml.WriteString(L"<w:style w:type=\"character\" w:styleId=\"a\"><w:name w:val=\"Hyperlink\"/><w:uiPriority w:val=\"99\"/><w:unhideWhenUsed/><w:rPr><w:color w:val=\"0000FF\" w:themeColor=\"hyperlink\"/><w:u w:val=\"single\"/></w:rPr></w:style>");
m_oStylesXml.WriteString(L"<w:style w:type=\"character\" w:styleId=\"footnote\"><w:name w:val=\"footnote reference\"/><w:uiPriority w:val=\"99\"/><w:unhideWhenUsed/><w:rPr><w:vertAlign w:val=\"superscript\"/></w:rPr></w:style><w:style w:type=\"paragraph\" w:styleId=\"footnote-p\"><w:name w:val=\"footnote text\"/><w:basedOn w:val=\"normal\"/><w:link w:val=\"footnote-c\"/><w:uiPriority w:val=\"99\"/><w:semiHidden/><w:unhideWhenUsed/><w:rPr><w:sz w:val=\"18\"/></w:rPr><w:pPr><w:spacing w:lineRule=\"auto\" w:line=\"240\" w:after=\"40\"/></w:pPr></w:style><w:style w:type=\"character\" w:styleId=\"footnote-c\" w:customStyle=\"1\"><w:name w:val=\"footnote text character\"/><w:link w:val=\"footnote-p\"/><w:uiPriority w:val=\"99\"/><w:rPr><w:sz w:val=\"18\"/></w:rPr></w:style>");
m_oStylesXml.WriteString(L"<w:style w:type=\"paragraph\" w:styleId=\"normal-web\"><w:name w:val=\"Normal (Web)\"/><w:basedOn w:val=\"normal\"/><w:uiPriority w:val=\"99\"/><w:semiHidden/><w:unhideWhenUsed/><w:pPr><w:spacing w:before=\"100\" w:beforeAutospacing=\"1\" w:after=\"100\" w:afterAutospacing=\"1\"/></w:pPr></w:style>");
m_oContentTypes.WriteString(L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
m_oContentTypes.WriteString(L"<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>");
m_oContentTypes.WriteString(L"<Default Extension=\"xml\" ContentType=\"application/xml\"/>");
m_oContentTypes.WriteString(L"<Default Extension=\"png\" ContentType=\"image/png\"/>");
m_oContentTypes.WriteString(L"<Default Extension=\"jpeg\" ContentType=\"image/jpeg\"/>");
m_oContentTypes.WriteString(L"<Override PartName=\"/word/document.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\"/>");
m_oContentTypes.WriteString(L"<Override PartName=\"/word/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml\"/>");
m_oContentTypes.WriteString(L"<Override PartName=\"/word/settings.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml\"/>");
m_oContentTypes.WriteString(L"<Override PartName=\"/word/webSettings.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml\"/>");
m_oContentTypes.WriteString(L"<Override PartName=\"/word/fontTable.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml\"/>");
m_oContentTypes.WriteString(L"<Override PartName=\"/word/theme/theme1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.theme+xml\"/>");
m_oContentTypes.WriteString(L"<Override PartName=\"/docProps/core.xml\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\"/>");
m_oContentTypes.WriteString(L"<Override PartName=\"/docProps/app.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\"/>");
}
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_oStylesXml.WriteString(L"</w:styles>");
NSFile::CFileBinary oStylesWriter;
if (oStylesWriter.CreateFileW(m_sTempDirectory + L"/word/styles.xml"))
{
oStylesWriter.WriteStringUTF8(m_oStylesXml.GetData());
oStylesWriter.CloseFile();
}
// numbering.xml
if (m_oNumberingConverter.SaveToFile(m_sTempDirectory + FILE_SEPARATOR_STR + L"word" + FILE_SEPARATOR_STR))
{
AddRelationship(L"numbering", L"numbering.xml");
AddContentType(L"numbering.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml");
}
// webSettings.xml
m_oWebSettings.WriteString(L"</w:webSettings>");
NSFile::CFileBinary oWebSettingsWriter;
if (oWebSettingsWriter.CreateFileW(m_sTempDirectory + L"/word/webSettings.xml"))
{
oWebSettingsWriter.WriteStringUTF8(m_oWebSettings.GetData());
oWebSettingsWriter.CloseFile();
}
// [Content_Types].xml
m_oContentTypes.WriteString(L"</Types>");
NSFile::CFileBinary oContentTypeWriter;
if (oContentTypeWriter.CreateFileW(m_sTempDirectory + L"/[Content_Types].xml"))
{
oContentTypeWriter.WriteStringUTF8(m_oContentTypes.GetData());
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"\"/>");
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;
}
}
bool CConverter2OOXML::IsRasterFormat(const HWP_STRING& sFormat)
{
return L"png" == sFormat || L"jpg" == sFormat || L"jpeg" == sFormat;
}
void CConverter2OOXML::WriteCharacter(const CCtrlCharacter* pCharacter, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pCharacter)
return;
switch (pCharacter->GetType())
{
case ECtrlCharType::PARAGRAPH_BREAK:
{
if (oState.m_bOpenedP)
{
oState.m_bOpenedP = false;
oBuilder.WriteString(L"</w:p>");
}
else
WriteText(L"", shParaShapeID, pCharacter->GetCharShapeId(), oBuilder, oState);
oState.m_bNeedLineBreak = false;
break;
}
case ECtrlCharType::LINE_BREAK:
{
oState.m_bNeedLineBreak = true;
break;
}
case ECtrlCharType::HARD_HYPHEN:
case ECtrlCharType::HARD_SPACE:
break;
}
}
void CConverter2OOXML::WriteShape(const CCtrlGeneralShape* pShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pShape)
return;
switch (pShape->GetShapeType())
{
case EShapeType::Arc:
case EShapeType::Ellipse:
case EShapeType::Rect:
case EShapeType::Line:
{
WriteGeometryShape(pShape, oBuilder, oState);
break;
}
case EShapeType::Pic:
{
WritePicture((const CCtrlShapePic*)pShape, oBuilder, oState);
break;
}
case EShapeType::EqEdit:
{
WriteEqEditShape((const CCtrlEqEdit*)pShape, oBuilder, oState);
break;
}
case EShapeType::Ole:
{
WriteOleShape((const CCtrlShapeOle*)pShape, oBuilder, oState);
break;
}
case EShapeType::Video:
{
WriteVideo((const CCtrlShapeVideo*)pShape, oBuilder, oState);
break;
}
case EShapeType::GeneralShape:
case EShapeType::ConnectLine:
case EShapeType::Container:
case EShapeType::Polygon:
case EShapeType::TextArt:
case EShapeType::Curve:
break;
}
}
void CConverter2OOXML::WriteParagraph(const CHWPPargraph* pParagraph, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pParagraph)
return;
if (0 < pParagraph->GetBreakType())
{
if ((0x01 == (pParagraph->GetBreakType() & 0x01) ||
0x02 == (pParagraph->GetBreakType() & 0x02)) &&
0 < oState.m_ushSecdIndex)
{
if (oState.m_bOpenedP)
oBuilder.WriteString(L"</w:p>");
oBuilder.WriteString(L"<w:p><w:r><w:br w:type=\"page\"/></w:r>");
oState.m_bOpenedP = true;
++m_ushPageCount;
}
else if (0x08 == (pParagraph->GetBreakType() & 0x08))
{
if (oState.m_bOpenedP)
oBuilder.WriteString(L"</w:p>");
oBuilder.WriteString(L"<w:p><w:r><w:br w:type=\"column\"/></w:r>");
oState.m_bOpenedP = true;
}
}
VECTOR<std::wstring> arNoteRef;
for (const CCtrl* pCtrl : pParagraph->GetCtrls())
{
switch (pCtrl->GetCtrlType())
{
case ECtrlObjectType::ParaText:
{
WriteText(((const CParaText*)pCtrl)->GetText(), pParagraph->GetShapeID(), ((const CParaText*)pCtrl)->GetCharShapeID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Character:
{
WriteCharacter((const CCtrlCharacter*)pCtrl, pParagraph->GetShapeID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Shape:
{
WriteShape((const CCtrlGeneralShape*)pCtrl, oBuilder, oState);
break;
}
case ECtrlObjectType::Table:
{
WriteTable((const CCtrlTable*)pCtrl, pParagraph->GetShapeID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Note:
{
arNoteRef.push_back(m_oFootnoteConverter.CreateNote((const CCtrlNote*)pCtrl, *this));
break;
}
case ECtrlObjectType::SectionDef:
{
oState.m_pSectionDef = (const CCtrlSectionDef*)pCtrl;
break;
}
case ECtrlObjectType::ColumnDef:
{
oState.m_pColumnDef = (const CCtrlColumnDef*)(pCtrl);
break;
}
case ECtrlObjectType::AutoNumber:
{
WriteAutoNumber((const CCtrlAutoNumber*)pCtrl, pParagraph->GetShapeID(), ((const CParaText*)pCtrl)->GetCharShapeID(), oBuilder, oState);
break;
}
default:
break;
}
if (!arNoteRef.empty() && ECtrlObjectType::Note != pCtrl->GetCtrlType() && oState.m_bOpenedP)
{
for (const std::wstring& wsNoteRef : arNoteRef)
oBuilder.WriteString(L"<w:r>" + wsNoteRef + L"</w:r>");
arNoteRef.clear();
}
}
if (oState.m_bOpenedP)
{
if (!arNoteRef.empty())
for (const std::wstring& wsNoteRef : arNoteRef)
oBuilder.WriteString(L"<w:r>" + wsNoteRef + L"</w:r>");
}
CloseParagraph(oBuilder, oState);
}
void CConverter2OOXML::WriteParagraphProperties(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
oBuilder.WriteString(L"<w:pPr>");
WriteParaShapeProperties(shParaShapeID, oBuilder, oState);
oBuilder.WriteString(L"</w:pPr>");
}
void CConverter2OOXML::WriteParaShapeProperties(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState)
{
if (nullptr == m_pContext)
return;
const CHWPRecordParaShape* pParaShape = dynamic_cast<const CHWPRecordParaShape*>(m_pContext->GetParaShape(shParaShapeID));
if (nullptr == pParaShape)
return;
oBuilder.WriteString(L"<w:keepNext w:val=\"" + HWP_STRING((pParaShape->KeepWithNext()) ? L"true" : L"false") + L"\"/>");
switch(pParaShape->GetHorizantalAlign())
{
case EHorizontalAlign::JUSTIFY: oBuilder.WriteString(L"<w:jc w:val=\"both\"/>"); break;
case EHorizontalAlign::LEFT: oBuilder.WriteString(L"<w:jc w:val=\"left\"/>"); break;
case EHorizontalAlign::RIGHT: oBuilder.WriteString(L"<w:jc w:val=\"right\"/>"); break;
case EHorizontalAlign::CENTER: oBuilder.WriteString(L"<w:jc w:val=\"center\"/>"); break;
case EHorizontalAlign::DISTRIBUTE:
case EHorizontalAlign::DISTRIBUTE_SPACE: oBuilder.WriteString(L"<w:jc w:val=\"distribute\"/>"); break;
}
switch(pParaShape->GetVerticalAlign())
{
case EVerticalAlign::BOTTOM: oBuilder.WriteString(L"<w:textAlignment w:val=\"bottom\"/>"); break;
case EVerticalAlign::TOP: oBuilder.WriteString(L"<w:textAlignment w:val=\"top\"/>"); break;
case EVerticalAlign::CENTER: oBuilder.WriteString(L"<w:textAlignment w:val=\"center\"/>"); break;
case EVerticalAlign::BASELINE:
break;
}
int nLineSpacing = 240;
HWP_STRING sType = L"auto";
switch(pParaShape->GetLineSpacingType())
{
case 0x0:
{
sType = L"auto";
nLineSpacing = static_cast<int>(240. * (double)pParaShape->GetLineSpacing() / 100. * 0.65); // TODO:: в hwp изначально межстрочный интервал меньше. Множитель 1 в hwp ≈ 0.65 MS
break;
}
case 0x01:
{
sType = L"exact";
nLineSpacing = static_cast<int>((double)pParaShape->GetLineSpacing() / 2. * 20)/*0.352778*/; //(1pt=0.352778mm) //TODO:: проверить, как найдется пример
break;
break;
}
case 0x02:
case 0x03:
default:
{
sType = L"atLeast";
nLineSpacing = static_cast<int>((double)pParaShape->GetLineSpacing()); //TODO:: проверить, как найдется пример
break;
}
}
oBuilder.WriteString(L"<w:spacing w:lineRule=\"" + sType + L"\" w:line=\"" + std::to_wstring(nLineSpacing) +
L"\" w:before=\"" + std::to_wstring(static_cast<int>((double)pParaShape->GetMarginPrev() / 10.)) +
L"\" w:after=\"" + std::to_wstring(static_cast<int>((double)pParaShape->GetMarginNext() / 10.)) + L"\"/>");
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());
if (0 == nNumId)
break;
oBuilder.WriteString(L"<w:numPr>");
oBuilder.WriteString(L"<w:ilvl w:val=\"0\"/>");
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;
}
}
void CConverter2OOXML::WriteTable(const CCtrlTable* pTable, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pTable || pTable->Empty())
return;
++m_ushTableCount;
oBuilder.WriteString(L"<w:tbl>");
WriteTableProperties(pTable, shParaShapeID, 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>");
}
void CConverter2OOXML::WriteTableProperties(const CCtrlTable* pTable, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pTable)
return;
oBuilder.WriteString(L"<w:tblPr>");
oBuilder.WriteString(L"<w:tblW w:w=\"0\" w:type=\"auto\"/>");
WriteParaShapeProperties(shParaShapeID, 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())
{
TConversionState oCellState;
// Так как даже в пустой ячейки нужен параграф, то открываем его заранее, чтобы он 100% был (закроется он автоматически в WriteParagraph)
OpenParagraph(pParagraph->GetShapeID(), oBuilder, oCellState);
WriteParagraph(pParagraph, oBuilder, oCellState);
}
}
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() && pBorderFill->GetFill()->ColorFill())
oBuilder.WriteString(L"<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"" + Transform::IntColorToHEX(pBorderFill->GetFill()->GetFaceColor()) + L"\"/>");
oBuilder.WriteString(L"<w:tcBorders>");
WriteCellBorder(pBorderFill->GetTopBorder(), L"top", oBuilder);
WriteCellBorder(pBorderFill->GetLeftBorder(), L"left", oBuilder);
WriteCellBorder(pBorderFill->GetBottomBorder(), L"bottom", oBuilder);
WriteCellBorder(pBorderFill->GetRightBorder(), L"right", oBuilder);
oBuilder.WriteString(L"</w:tcBorders>");
}
void CConverter2OOXML::WriteCellBorder(const TBorder& oBorder, const HWP_STRING& sBorderName, NSStringUtils::CStringBuilder& oBuilder)
{
if (0x00 == oBorder.m_chWidth || sBorderName.empty())
return;
HWP_STRING sType;
//TODO:: проверить стиль линий
switch(oBorder.m_eStyle)
{
case ELineStyle2::NONE: oBuilder.WriteString(L"<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"thickThinMediumGap"; break;
case ELineStyle2::SLIM_THICK: sType = L"thickThinMediumGap"; break;
case ELineStyle2::THICK_SLIM: sType = L"thickThinMediumGap"; break;
case ELineStyle2::SLIM_THICK_SLIM: sType = L"thickThinMediumGap"; break;
break;
}
oBuilder.WriteString(L"<w:" + sBorderName + L" w:val=\"" + sType + L"\" w:sz=\"" + std::to_wstring(Transform::LineWidth2Pt((short)oBorder.m_chWidth)) + L"\" w:space=\"0\" w:color=\"" + Transform::IntColorToHEX(oBorder.m_nColor) + L"\"/>");
}
void CConverter2OOXML::WriteGeometryShape(const CCtrlGeneralShape* pGeneralShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pGeneralShape)
return;
EShapeObjectType eShapeType = GetShapeObjectType(pGeneralShape->GetID());
if (EShapeObjectType::Unknown == eShapeType)
return;
const std::wstring wsWidth = std::to_wstring(Transform::HWPUINT2OOXML(pGeneralShape->GetWidth()));
const std::wstring wsHeight = std::to_wstring(Transform::HWPUINT2OOXML(pGeneralShape->GetHeight()));
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"<w:p>");
oBuilder.WriteString(L"<w:r><w:rPr><w:noProof/></w:rPr>");
oBuilder.WriteString(L"<mc:AlternateContent><mc:Choice Requires=\"wps\">");
OpenDrawingNode(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:
{
oBuilder.WriteString(L"<a:prstGeom prst=\"arc\"><a:avLst>");
oBuilder.WriteString(L"<a:gd name=\"adj1\" fmla=\"val 0\"/>");
oBuilder.WriteString(L"<a:gd name=\"adj2\" fmla=\"val 5400000\"/>");
oBuilder.WriteString(L"</a:avLst></a:prstGeom>");
break;
}
case EShapeObjectType::Ellipse:
{
oBuilder.WriteString(L"<a:prstGeom prst=\"ellipse\"><a:avLst/></a:prstGeom>");
break;
}
case EShapeObjectType::Line:
{
oBuilder.WriteString(L"<a:prstGeom prst=\"line\"><a:avLst/></a:prstGeom>");
break;
}
case EShapeObjectType::Rectangle:
{
oBuilder.WriteString(L"<a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom>");
break;
}
case EShapeObjectType::Curve:
case EShapeObjectType::Ole:
case EShapeObjectType::Picture:
case EShapeObjectType::Polygon:
case EShapeObjectType::Unknown:
break;
}
const CFill *pFill = pGeneralShape->GetFill();
if (nullptr == pFill || pFill->NoneFill())
oBuilder.WriteString(L"<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());
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;
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>");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"</w:p>");
}
void CConverter2OOXML::WriteEqEditShape(const CCtrlEqEdit* pEqEditShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
//TODO:: добавить конвертацию eqn формулы в ooxml
++m_ushEquationCount;
if (!oState.m_bOpenedP)
{
oBuilder.WriteString(L"<w:p>");
oState.m_bOpenedP = true;
}
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, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
//TODO:: добавить конвертацию hwp ole -> ooxml chart
//TODO:: необходимо добавить поддержку формата "Hwp Document File Formats - Charts" (для случаев, когда нет ooxml представления)
// Пока можем вытащить лишь ooxml представление данных
// Реализовать с использованием pole.h?
if (nullptr == m_pContext)
return;
CHWPStream oBuffer;
HWP_STRING sFileName;
if (!m_pContext->GetBinBytes(pOleShape->GetBinDataID(), oBuffer, sFileName))
return;
m_oOleConverter.CreateChart(oBuffer);
const unsigned int unChartIndex = m_oOleConverter.GetChartsCount();
if (0 == unChartIndex)
return;
const std::wstring wsWidth = std::to_wstring(Transform::HWPUINT2OOXML(pOleShape->GetWidth()));
const std::wstring wsHeight = std::to_wstring(Transform::HWPUINT2OOXML(pOleShape->GetHeight()));
const std::wstring wsRelID = AddRelationship(L"chart", L"charts/chart" + std::to_wstring(unChartIndex) + L".xml");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"<w:p>");
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>");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"</w:p>");
AddContentType(L"charts/chart" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.openxmlformats-officedocument.drawingml.chart+xml");
AddContentType(L"charts/style" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.ms-office.chartstyle+xml");
AddContentType(L"charts/colors" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.ms-office.chartcolorstyle+xml");
}
void CConverter2OOXML::WriteSectionSettings(TConversionState& oState)
{
m_oDocXml.WriteString(L"<w:sectPr>");
if (nullptr != oState.m_pSectionDef)
{
for (const CCtrlHeadFoot* pCtrlHeadFoot : oState.m_pSectionDef->GetHeaderFooters())
{
const std::wstring wsID = m_oFootnoteConverter.CreateHeadOrFoot((const CCtrlHeadFoot*)pCtrlHeadFoot, *this);
if (!wsID.empty() && wsID.length() > 6)
{
const std::wstring wsType = wsID.substr(0, 6);
AddContentType(wsID, L"application/vnd.openxmlformats-officedocument.wordprocessingml." + wsType + L"+xml");
m_oDocXml.WriteString(L"<w:" + wsType + L"Reference w:type=\"default\" r:id=\"" + AddRelationship(wsType, wsID) + 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\" w:equalWidth=\"true\"");
if (ELineStyle2::NONE != oState.m_pColumnDef->GetColLineStyle())
m_oDocXml.WriteString(L" w:sep=\"true\"");
m_oDocXml.WriteString(L"/>");
}
const CPage *pPage = (nullptr != oState.m_pSectionDef) ? oState.m_pSectionDef->GetPage() : nullptr;
if (nullptr == pPage)
{
//DEFAULT_VALUE
m_oDocXml.WriteString(L"<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())) + L"\" w:right=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginRight())) + L"\" w:bottom=\"" +
std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginBottom())) + L"\" w:left=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginRight())) + L"\" w:header=\"" +
std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginHeader())) + L"\" w:footer=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginFooter())) + L"\" w:gutter=\"" +
std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginGutter())) + L"\"/>");
}
m_oDocXml.WriteString(L"<w:cols w:space=\"708\"/>");
m_oDocXml.WriteString(L"<w:docGrid w:linePitch=\"360\"/>");
m_oDocXml.WriteString(L"</w:sectPr>");
}
void CConverter2OOXML::WritePicture(const CCtrlShapePic* pCtrlPic, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState)
{
if (nullptr == pCtrlPic)
return;
HWP_STRING sPictureID = SavePicture(pCtrlPic->GetBinDataID());
if (sPictureID.empty())
return;
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"<w:p>");
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\"><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlPic->GetFinalWidth())) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(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>");
oBuilder.WriteString(L"<wp14:sizeRelH relativeFrom=\"page\"><wp14:pctWidth>0</wp14:pctWidth></wp14:sizeRelH><wp14:sizeRelV relativeFrom=\"page\"><wp14:pctHeight>0</wp14:pctHeight></wp14:sizeRelV>");
CloseDrawingNode(pCtrlPic, oBuilder);
oBuilder.WriteString(L"</w:r>");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"</w:p>");
}
void CConverter2OOXML::WriteVideo(const CCtrlShapeVideo* pCtrlVideo, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState)
{
if (nullptr == pCtrlVideo)
return;
HWP_STRING sPictureID = SavePicture(pCtrlVideo->GetThumnailBinID());
if (sPictureID.empty())
return;
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"<w:p>");
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=\"" + pCtrlVideo->GetThumnailBinID() + L"\" name=\"Video " + pCtrlVideo->GetThumnailBinID() + 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\"><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>");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"</w:p>");
}
bool CConverter2OOXML::SaveSVGFile(const HWP_STRING& sSVG, HWP_STRING& sFileName)
{
if (sSVG.empty())
return false;
NSFonts::IApplicationFonts* pFonts = NSFonts::NSApplication::Create();
pFonts->Initialize();
MetaFile::IMetaFile* pSvgReader = MetaFile::Create(pFonts);
if (!pSvgReader->LoadFromString(sSVG))
{
RELEASEINTERFACE(pSvgReader);
RELEASEINTERFACE(pFonts);
return false;
}
NSGraphics::IGraphicsRenderer* pGrRenderer = NSGraphics::Create();
pGrRenderer->SetFontManager(pSvgReader->get_FontManager());
double dX, dY, dW, dH;
pSvgReader->GetBounds(&dX, &dY, &dW, &dH);
if (dW < 0) dW = -dW;
if (dH < 0) dH = -dH;
double dOneMaxSize = (double)1000.;
if (dW > dH && dW > dOneMaxSize)
{
dH *= (dOneMaxSize / dW);
dW = dOneMaxSize;
}
else if (dH > dW && dH > dOneMaxSize)
{
dW *= (dOneMaxSize / dH);
dH = dOneMaxSize;
}
int nWidth = static_cast<int>(dW + 0.5);
int nHeight = static_cast<int>(dH + 0.5);
double dWidth = 25.4 * nWidth / 96;
double dHeight = 25.4 * nHeight / 96;
unsigned char* pBgraData = (unsigned char*)malloc(nWidth * nHeight * 4);
if (!pBgraData)
{
double dKoef = 2000.0 / (nWidth > nHeight ? nWidth : nHeight);
nWidth = (int)(dKoef * nWidth);
nHeight = (int)(dKoef * nHeight);
dWidth = 25.4 * nWidth / 96;
dHeight = 25.4 * nHeight / 96;
pBgraData = (unsigned char*)malloc(nWidth * nHeight * 4);
}
if (!pBgraData)
return false;
unsigned int alfa = 0xffffff;
//дефолтный тон должен быть прозрачным, а не белым
//memset(pBgraData, 0xff, nWidth * nHeight * 4);
for (int i = 0; i < nWidth * nHeight; i++)
{
((unsigned int*)pBgraData)[i] = alfa;
}
CBgraFrame oFrame;
oFrame.put_Data(pBgraData);
oFrame.put_Width(nWidth);
oFrame.put_Height(nHeight);
oFrame.put_Stride(-4 * nWidth);
pGrRenderer->CreateFromBgraFrame(&oFrame);
pGrRenderer->SetSwapRGB(false);
pGrRenderer->put_Width(dWidth);
pGrRenderer->put_Height(dHeight);
pSvgReader->SetTempDirectory(m_sTempDirectory);
pSvgReader->DrawOnRenderer(pGrRenderer, 0, 0, dWidth, dHeight);
oFrame.SaveFile(m_sTempDirectory + L"/word/media/" + sFileName, 4);
oFrame.put_Data(NULL);
RELEASEINTERFACE(pGrRenderer);
if (pBgraData)
free(pBgraData);
RELEASEINTERFACE(pSvgReader);
RELEASEINTERFACE(pFonts);
return true;
}
HWP_STRING CConverter2OOXML::SavePicture(const HWP_STRING& sBinItemId)
{
if (nullptr == m_pContext)
return HWP_STRING();
//TODO:: добавить поддержку устновки размеров изображения из свойств шейпа
CHWPStream oBuffer;
HWP_STRING sFileName;
if (!m_pContext->GetBinBytes(sBinItemId, oBuffer, sFileName))
return HWP_STRING();
oBuffer.MoveToStart();
if (IsRasterFormat(NSFile::GetFileExtention(sFileName)))
{
NSFile::CFileBinary oFile;
oFile.CreateFileW(m_sTempDirectory + L"/word/media/" + sFileName);
if (!oFile.WriteFile((unsigned char*)oBuffer.GetCurPtr(), oBuffer.GetSize()))
{
oFile.CloseFile();
return HWP_STRING();
}
oFile.CloseFile();
}
else if (L"svg" == NSFile::GetFileExtention(sFileName))
{
std::string sSVG(oBuffer.GetCurPtr(), oBuffer.GetSize());
if (!SaveSVGFile(UTF8_TO_U(sSVG), sFileName))
return HWP_STRING();
}
AddContentType(L"media/" + sFileName, L"image/" + NSFile::GetFileExtention(sFileName));
return AddRelationship(L"image", L"media/" + sFileName);
}
void CConverter2OOXML::WriteRunnerStyle(short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState)
{
if (nullptr == m_pContext)
return;
const CHWPRecordCharShape* pCharShape = dynamic_cast<const CHWPRecordCharShape*>(m_pContext->GetCharShape(shCharShapeID));
if (nullptr == pCharShape)
return;
oBuilder.WriteString(L"<w:rPr>");
HWP_STRING sFontFamily = pCharShape->GetFontName(ELang::LATIN);
HWP_STRING sFontFamilyAsian = pCharShape->GetFontName(ELang::HANGUL);
if (sFontFamilyAsian.empty() && !sFontFamily.empty())
sFontFamilyAsian = sFontFamily;
else if (!sFontFamilyAsian.empty() && sFontFamily.empty())
sFontFamily = sFontFamilyAsian;
if (!sFontFamily.empty() && !sFontFamilyAsian.empty())
{
oBuilder.WriteString(L"<w:rFonts w:ascii=\"" + sFontFamily +
L"\" w:hAnsi=\"" + sFontFamily +
L"\" w:cs=\"" + sFontFamily +
L"\" w:eastAsia=\"" + sFontFamilyAsian + L"\"/>");
}
if (pCharShape->Bold())
oBuilder.WriteString(L"<w:b/><w:bCs/>");
if (pCharShape->Italic())
oBuilder.WriteString(L"<w:i/><w:iCs/>");
const int nHeight = static_cast<int>(((double)(std::abs)(pCharShape->GetHeight()) * ((double)pCharShape->GetRelSize(ELang::LATIN) / 100.) / 100.) * 2.);
oBuilder.WriteString(L"<w:sz w:val=\"" + std::to_wstring(nHeight) + L"\"/><w:szCs w:val=\"" + std::to_wstring(nHeight) + L"\"/>");
oBuilder.WriteString(L"<w:color w:val=\"" + Transform::IntColorToHEX(pCharShape->GetTextColor()) + L"\"/>");
bool bStrike = false;
if (pCharShape->Underline())
{
EUnderline eUnderlineType = pCharShape->GetUnderlineType();
ELineStyle1 eUnderlineStyle = pCharShape->GetUnderlineStyle();
if (EUnderline::BOTTOM == eUnderlineType)
{
oBuilder.WriteString(L"<w:u w:val=\"");
switch (eUnderlineStyle)
{
case ELineStyle1::SOLID: oBuilder.WriteString(L"single"); break;
case ELineStyle1::DASH: oBuilder.WriteString(L"dash"); break;
case ELineStyle1::DOT: oBuilder.WriteString(L"dotted"); break;
case ELineStyle1::DASH_DOT: oBuilder.WriteString(L"dotDash"); break;
case ELineStyle1::DASH_DOT_DOT: oBuilder.WriteString(L"dotDotDash"); break;
case ELineStyle1::LONG_DASH: oBuilder.WriteString(L"dotDash"); break;
case ELineStyle1::CIRCLE: oBuilder.WriteString(L"dotted"); break;
case ELineStyle1::DOUBLE_SLIM: oBuilder.WriteString(L"double"); break;
case ELineStyle1::SLIM_THICK: oBuilder.WriteString(L"double"); break;
case ELineStyle1::THICK_SLIM: oBuilder.WriteString(L"double"); break;
case ELineStyle1::SLIM_THICK_SLIM: oBuilder.WriteString(L"double"); break;
case ELineStyle1::WAVE: oBuilder.WriteString(L"wave"); break;
case ELineStyle1::DOUBLE_WAVE: oBuilder.WriteString(L"wavyDouble"); break;
case ELineStyle1::THICK_3D: oBuilder.WriteString(L"thick"); break;
case ELineStyle1::THICK_3D_REVERS_LI: oBuilder.WriteString(L"thick"); break;
case ELineStyle1::SOLID_3D: oBuilder.WriteString(L"thick"); break;
case ELineStyle1::SOLID_3D_REVERS_LI: oBuilder.WriteString(L"thick"); break;
}
oBuilder.WriteString(L"\" w:color=\"" + Transform::IntColorToHEX(pCharShape->GetUnderlineColor()) + L"\"/>");
}
else if (EUnderline::CENTER == eUnderlineType)
{
if (eUnderlineStyle == ELineStyle1::DOUBLE_SLIM ||
eUnderlineStyle == ELineStyle1::DOUBLE_WAVE)
oBuilder.WriteString(L"<w:dstrike/>");
else
oBuilder.WriteString(L"<w:strike/>");
bStrike = true;
}
}
if (!bStrike && pCharShape->StrikeOut())
oBuilder.WriteString(L"<w:strike/>");
double dSpacing = ((double)pCharShape->GetHeight() / 100.) * ((double)pCharShape->GetSpacing(ELang::HANGUL) / 100) * 0.8 + 0.4;
dSpacing *= 20; // pt to twips (20 = 1440 / 72)
oBuilder.WriteString(L"<w:spacing w:val=\"" + std::to_wstring((int)std::round(dSpacing)) + L"\"/>");
oBuilder.WriteString(L"</w:rPr>");
}
void CConverter2OOXML::OpenDrawingNode(const CCtrlCommon* 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->GetTopMargin() / 10)) +
L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomMargin() / 10)) +
L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftMargin() / 10)) +
L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightMargin() / 10)) +
L"\">");
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->GetTopMargin() / 10)) +
L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomMargin() / 10)) +
L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftMargin() / 10)) +
L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightMargin() / 10)) +
L"\" simplePos=\"0\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">");
WriteShapeProperty(pCtrlShape, oBuilder);
}
void CConverter2OOXML::CloseDrawingNode(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
if (pCtrlShape->GetTreatAsChar())
oBuilder.WriteString(L"</wp:inline>");
else
{
oBuilder.WriteString(L"<wp14:sizeRelH relativeFrom=\"page\"><wp14:pctWidth>0</wp14:pctWidth></wp14:sizeRelH><wp14:sizeRelV relativeFrom=\"page\"><wp14:pctHeight>0</wp14:pctHeight></wp14:sizeRelV>");
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"character";
}
}
void CConverter2OOXML::WriteShapeProperty(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
oBuilder.WriteString(L"<wp:simplePos x=\"0\" y=\"0\"/>");
oBuilder.WriteString(L"<wp:positionH relativeFrom=\"" + GetHRelativeFrom(pCtrlShape->GetHorzRelTo()) + L"\"><wp:posOffset>" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetHorzOffset())) + L"</wp:posOffset></wp:positionH>");
oBuilder.WriteString(L"<wp:positionV relativeFrom=\"" + GetVRelativeFrom(pCtrlShape->GetVertRelTo()) + L"\"><wp:posOffset>" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetVertOffset())) + L"</wp:posOffset></wp:positionV>");
oBuilder.WriteString(L"<wp:extent cx=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetWidth())) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetHeight())) + L"\"/>");
oBuilder.WriteString(L"<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>");
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:
{
oBuilder.WriteString(L"<wp:wrapNone/>");
break;
}
}
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::OpenParagraph(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (oState.m_bOpenedP)
return;
oBuilder.WriteString(L"<w:p>");
oState.m_bOpenedP = true;
WriteParagraphProperties(shParaShapeID, oBuilder, oState);
}
void CConverter2OOXML::CloseParagraph(NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (!oState.m_bOpenedP)
return;
oBuilder.WriteString(L"</w:p>");
oState.m_bOpenedP = false;
}
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 std::wstring& wsText, short shParaShapeID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
OpenParagraph(shParaShapeID, oBuilder, oState);
if (wsText.empty())
{
WriteRunnerStyle(shCharShapeID, oBuilder, oState);
return;
}
for (const std::wstring& wsTextElement : SplitText(wsText))
{
oBuilder.WriteString(L"<w:r>");
WriteRunnerStyle(shCharShapeID, oBuilder, oState);
if (oState.m_bNeedLineBreak)
{
oBuilder.WriteString(L"<w:br/>");
oState.m_bNeedLineBreak = false;
}
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, oBuilder);
}
void CConverter2OOXML::WriteLineSettings(ELineStyle2 eLineStyle, int nColor, int nThick, HWP_BYTE nCompoundLineType, NSStringUtils::CStringBuilder& oBuilder)
{
if (ELineStyle2::NONE == eLineStyle || 0 >= nThick)
{
oBuilder.WriteString(L"<a:ln><a:noFill/></a:ln>");
return;
}
oBuilder.WriteString(L"<a:ln");
oBuilder.WriteString(L" w=\"" + std::to_wstring(Transform::HWPUINT2OOXML(nThick)) + L"\" cap=\"sq\"");
switch (eLineStyle)
{
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(nColor) + L"\"/></a:solidFill>");
switch (eLineStyle)
{
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;
}
switch (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)
return;
WriteLineSettings(pCtrlPic->GetBorderLineStyle(), pCtrlPic->GetBorderColor(), pCtrlPic->GetBorderThick(), pCtrlPic->GetBorderCompoundLineType(), oBuilder);
}
void CConverter2OOXML::WriteAutoNumber(const CCtrlAutoNumber* pAutoNumber,short shParaShapeID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pAutoNumber)
return;
unsigned short ushValue = 0;
//TODO:: лучше перейти не на ручной подсчет, а на автоматический в word (но там есть свои проблемы)
switch (pAutoNumber->GetNumType())
{
case ENumType::PAGE:
case ENumType::TOTAL_PAGE:
ushValue = m_ushPageCount; break;
case ENumType::FOOTNOTE:
ushValue = m_oFootnoteConverter.GetFootnoteCount(); break;
case ENumType::ENDNOTE:
ushValue = m_oFootnoteConverter.GetEndnoteCount(); break;
case ENumType::FIGURE:
ushValue = m_ushShapeCount; break;
case ENumType::TABLE:
ushValue = m_ushTableCount; break;
case ENumType::EQUATION:
ushValue = m_ushEquationCount; break;
}
if (0 == ushValue)
return;
WriteText(std::to_wstring(ushValue), shParaShapeID, shCharShapeID, oBuilder, oState);
}
HWP_STRING CConverter2OOXML::AddRelationship(const HWP_STRING& wsType, const HWP_STRING& wsTarget)
{
if (wsType.empty() || wsTarget.empty())
return HWP_STRING();
m_arRelationships.push_back({L"rId" + std::to_wstring(m_arRelationships.size() + 1), wsType, wsTarget});
return m_arRelationships.back().m_wsID;
}
void CConverter2OOXML::AddContentType(const HWP_STRING& wsName, const HWP_STRING& wsType)
{
if (wsName.empty() || wsType.empty())
return;
m_oContentTypes.WriteString(L"<Override PartName=\"/word/" + wsName + L"\" ContentType=\"" + wsType + L"\"/>");
}
bool CConverter2OOXML::ConvertToFile(const HWP_STRING& sFilePath)
{
if (nullptr == m_pContext || sFilePath.empty())
return false;
CreateEmptyFiles();
Convert();
Close();
COfficeUtils oZip;
oZip.CompressFileOrDirectory(m_sTempDirectory, sFilePath);
return true;
}
bool CConverter2OOXML::ConvertToDir(const HWP_STRING& sDirectoryPath)
{
if (nullptr == m_pContext || sDirectoryPath.empty())
return false;
HWP_STRING sCurrentTempDir{m_sTempDirectory};
SetTempDirectory(sDirectoryPath);
CreateEmptyFiles();
Convert();
Close();
SetTempDirectory(sCurrentTempDir);
return true;
}
HWP_STRING CConverter2OOXML::GetTempDirectory() const
{
return m_sTempDirectory;
}
TConversionState::TConversionState()
: m_bOpenedP(false), m_bOpenedR(false), m_bNeedLineBreak(false), m_ushSecdIndex(0), m_pSectionDef(nullptr), m_pColumnDef(nullptr)
{}
}