5170 lines
177 KiB
C++
5170 lines
177 KiB
C++
#include "htmlfile2.h"
|
||
|
||
#include <string>
|
||
#include <cwctype>
|
||
#include <map>
|
||
#include <vector>
|
||
#include <algorithm>
|
||
#include <iostream>
|
||
|
||
#include "../Common/3dParty/html/htmltoxhtml.h"
|
||
#include "../Common/3dParty/html/css/src/CCssCalculator.h"
|
||
#include "../Common/3dParty/html/css/src/xhtml/CDocumentStyle.h"
|
||
#include "../Common/Network/FileTransporter/include/FileTransporter.h"
|
||
#include "../DesktopEditor/common/Types.h"
|
||
#include "../DesktopEditor/common/Base64.h"
|
||
#include "../DesktopEditor/common/SystemUtils.h"
|
||
#include "../DesktopEditor/common/StringBuilder.h"
|
||
#include "../DesktopEditor/common/File.h"
|
||
#include "../DesktopEditor/common/Directory.h"
|
||
#include "../DesktopEditor/common/Path.h"
|
||
#include "../DesktopEditor/common/ProcessEnv.h"
|
||
#include "../DesktopEditor/xml/include/xmlutils.h"
|
||
#include "../DesktopEditor/raster/BgraFrame.h"
|
||
#include "../DesktopEditor/graphics/pro/Graphics.h"
|
||
|
||
#include "htmlfile2.h"
|
||
#include "src/Languages.h"
|
||
|
||
#include <boost/regex.hpp>
|
||
|
||
#ifndef VALUE2STR
|
||
#define VALUE_TO_STRING(x) #x
|
||
#define VALUE2STR(x) VALUE_TO_STRING(x)
|
||
#endif
|
||
|
||
#define MAXCOLUMNSINTABLE 63
|
||
#define MAXROWSINTABLE 32767
|
||
|
||
#define DEFAULT_PAGE_WIDTH 12240 // Значение в Twips
|
||
#define DEFAULT_PAGE_HEIGHT 15840 // Значение в Twips
|
||
|
||
#define DEFAULT_LANGUAGE std::wstring(L"en-US")
|
||
#define DEFAULT_FONT_FAMILY std::wstring(L"Times New Roman")
|
||
#define DEFAULT_FONT_SIZE 24
|
||
|
||
#define DEFAULT_IMAGE_WIDTH 304800
|
||
#define DEFAULT_IMAGE_HEIGHT 304800
|
||
|
||
#define SAVE_NORMALIZED_HTML 0
|
||
|
||
#define RELEASE_VECTOR_PTR(vector_object, object_type) \
|
||
for (object_type* pElement : vector_object) \
|
||
RELEASEOBJECT(pElement) \
|
||
|
||
const static double HTML_FONTS[7] = {7.5, 10, 12, 13.5, 18, 24, 36};
|
||
|
||
#define HTML_TAG(tag) GUMBO_TAG_##tag
|
||
#define ADD_TAG(strName, enumName) {strName, HTML_TAG(enumName)}
|
||
#define SKIP_TAG SCRIPT
|
||
#define UNKNOWN_TAG GumboTag::GUMBO_TAG_UNKNOWN
|
||
|
||
#define HtmlTag GumboTag
|
||
|
||
#define MAX_STRING_BLOCK_SIZE (size_t)10485760
|
||
|
||
const std::map<std::wstring, HtmlTag> m_HTML_TAGS
|
||
{
|
||
ADD_TAG(L"a", A),
|
||
ADD_TAG(L"abbr", ABBR),
|
||
ADD_TAG(L"acronym", ACRONYM),
|
||
ADD_TAG(L"address", ADDRESS),
|
||
ADD_TAG(L"applet", APPLET),
|
||
ADD_TAG(L"area", AREA),
|
||
ADD_TAG(L"article", ARTICLE),
|
||
ADD_TAG(L"aside", ASIDE),
|
||
ADD_TAG(L"audio", AUDIO),
|
||
ADD_TAG(L"b", B),
|
||
ADD_TAG(L"base", BASE),
|
||
ADD_TAG(L"basefont", BASEFONT),
|
||
ADD_TAG(L"bdi", BDI),
|
||
ADD_TAG(L"bdo", BDO),
|
||
ADD_TAG(L"bgsound", BGSOUND),
|
||
ADD_TAG(L"blockquote", BLOCKQUOTE),
|
||
ADD_TAG(L"big", BIG),
|
||
ADD_TAG(L"body", BODY),
|
||
ADD_TAG(L"blink", BLINK),
|
||
ADD_TAG(L"br", BR),
|
||
ADD_TAG(L"button", BUTTON),
|
||
ADD_TAG(L"canvas", CANVAS),
|
||
ADD_TAG(L"caption", CAPTION),
|
||
ADD_TAG(L"center", CENTER),
|
||
ADD_TAG(L"cite", CITE),
|
||
ADD_TAG(L"code", CODE),
|
||
ADD_TAG(L"col", COL),
|
||
ADD_TAG(L"colgroup", COLGROUP),
|
||
ADD_TAG(L"command", SKIP_TAG), // Данного обозначения нет, но т.к.мы всё равно пропускаем, то делаем script
|
||
ADD_TAG(L"comment", SKIP_TAG), // Данного обозначения нет, но т.к.мы всё равно пропускаем, то делаем script
|
||
ADD_TAG(L"datalist", DATALIST),
|
||
ADD_TAG(L"dd", DD),
|
||
ADD_TAG(L"del", DEL),
|
||
ADD_TAG(L"details", DETAILS),
|
||
ADD_TAG(L"dfn", DFN),
|
||
ADD_TAG(L"dir", DIR),
|
||
ADD_TAG(L"div", DIV),
|
||
ADD_TAG(L"dl", DL),
|
||
ADD_TAG(L"dt", DT),
|
||
ADD_TAG(L"em", EM),
|
||
ADD_TAG(L"embed", EMBED),
|
||
ADD_TAG(L"fieldset", FIELDSET),
|
||
ADD_TAG(L"figcaption", FIGCAPTION),
|
||
ADD_TAG(L"figure", FIGURE),
|
||
ADD_TAG(L"font", FONT),
|
||
ADD_TAG(L"form", FORM),
|
||
ADD_TAG(L"footer", FOOTER),
|
||
ADD_TAG(L"frame", FRAME),
|
||
ADD_TAG(L"frameset", FRAMESET),
|
||
ADD_TAG(L"h1", H1),
|
||
ADD_TAG(L"h2", H2),
|
||
ADD_TAG(L"h3", H3),
|
||
ADD_TAG(L"h4", H4),
|
||
ADD_TAG(L"h5", H5),
|
||
ADD_TAG(L"h6", H6),
|
||
ADD_TAG(L"head", HEAD),
|
||
ADD_TAG(L"header", HEADER),
|
||
ADD_TAG(L"hgroup", HGROUP),
|
||
ADD_TAG(L"hr", HR),
|
||
ADD_TAG(L"html", HTML),
|
||
ADD_TAG(L"i", I),
|
||
ADD_TAG(L"iframe", IFRAME),
|
||
ADD_TAG(L"img", IMG),
|
||
ADD_TAG(L"input", INPUT),
|
||
ADD_TAG(L"ins", INS),
|
||
ADD_TAG(L"isindex", ISINDEX),
|
||
ADD_TAG(L"kbd", KBD),
|
||
ADD_TAG(L"keygen", KEYGEN),
|
||
ADD_TAG(L"label", LABEL),
|
||
ADD_TAG(L"legend", LEGEND),
|
||
ADD_TAG(L"li", LI),
|
||
ADD_TAG(L"link", LINK),
|
||
ADD_TAG(L"main", MAIN),
|
||
ADD_TAG(L"map", MAP),
|
||
ADD_TAG(L"marquee", MARQUEE),
|
||
ADD_TAG(L"mark", MARK),
|
||
ADD_TAG(L"menu", MENU),
|
||
ADD_TAG(L"meta", META),
|
||
ADD_TAG(L"meter", METER),
|
||
ADD_TAG(L"nav", NAV),
|
||
ADD_TAG(L"nobr", NOBR),
|
||
ADD_TAG(L"noembed", NOEMBED),
|
||
ADD_TAG(L"noframes", NOFRAMES),
|
||
ADD_TAG(L"noscript", NOSCRIPT),
|
||
ADD_TAG(L"object", OBJECT),
|
||
ADD_TAG(L"ol", OL),
|
||
ADD_TAG(L"optgroup", OPTGROUP),
|
||
ADD_TAG(L"option", OPTION),
|
||
ADD_TAG(L"output", OUTPUT),
|
||
ADD_TAG(L"p", P),
|
||
ADD_TAG(L"param", PARAM),
|
||
ADD_TAG(L"plaintext", PLAINTEXT),
|
||
ADD_TAG(L"pre", PRE),
|
||
ADD_TAG(L"progress", PROGRESS),
|
||
ADD_TAG(L"q", Q),
|
||
ADD_TAG(L"rp", RP),
|
||
ADD_TAG(L"rt", RT),
|
||
ADD_TAG(L"ruby", RUBY),
|
||
ADD_TAG(L"s", S),
|
||
ADD_TAG(L"samp", SAMP),
|
||
ADD_TAG(L"script", SCRIPT),
|
||
ADD_TAG(L"section", SECTION),
|
||
ADD_TAG(L"select", SELECT),
|
||
ADD_TAG(L"small", SMALL),
|
||
ADD_TAG(L"span", SPAN),
|
||
ADD_TAG(L"source", SOURCE),
|
||
ADD_TAG(L"strike", STRIKE),
|
||
ADD_TAG(L"strong", STRONG),
|
||
ADD_TAG(L"style", STYLE),
|
||
ADD_TAG(L"sub", SUB),
|
||
ADD_TAG(L"summary", SUMMARY),
|
||
ADD_TAG(L"sup", SUP),
|
||
ADD_TAG(L"table", TABLE),
|
||
ADD_TAG(L"tbody", TBODY),
|
||
ADD_TAG(L"td", TD),
|
||
ADD_TAG(L"textarea", TEXTAREA),
|
||
ADD_TAG(L"tfoot", TFOOT),
|
||
ADD_TAG(L"th", TH),
|
||
ADD_TAG(L"thead", THEAD),
|
||
ADD_TAG(L"time", TIME),
|
||
ADD_TAG(L"title", TITLE),
|
||
ADD_TAG(L"tr", TR),
|
||
ADD_TAG(L"tt", TT),
|
||
ADD_TAG(L"u", U),
|
||
ADD_TAG(L"ul", UL),
|
||
ADD_TAG(L"var", VAR),
|
||
ADD_TAG(L"video", VIDEO),
|
||
ADD_TAG(L"wbr", WBR),
|
||
ADD_TAG(L"xmp", XMP),
|
||
|
||
ADD_TAG(L"svg", SVG)
|
||
};
|
||
|
||
bool TagIsUnprocessed(const std::wstring& wsTagName)
|
||
{
|
||
return L"xml" == wsTagName;
|
||
}
|
||
|
||
bool IsSVG(const std::wstring& wsExtention)
|
||
{
|
||
return L"svg" == wsExtention || L"svg+xml" == wsExtention;
|
||
}
|
||
|
||
static inline HtmlTag GetHtmlTag(const std::wstring& wsStrTag)
|
||
{
|
||
std::map<std::wstring, HtmlTag>::const_iterator oFound = m_HTML_TAGS.find(wsStrTag);
|
||
|
||
if (oFound == m_HTML_TAGS.cend())
|
||
{
|
||
if (wsStrTag.length() > 3 && wsStrTag.compare(wsStrTag.length() - 3, 3, L"svg") == 0)
|
||
return HTML_TAG(SVG);
|
||
return UNKNOWN_TAG;
|
||
}
|
||
|
||
return oFound->second;
|
||
}
|
||
|
||
static inline void WriteToStringBuilder(NSStringUtils::CStringBuilder& oSrcStringBuilder, NSStringUtils::CStringBuilder& oDstStringBuilder)
|
||
{
|
||
if (oSrcStringBuilder.GetCurSize() < MAX_STRING_BLOCK_SIZE)
|
||
{
|
||
oDstStringBuilder.Write(oSrcStringBuilder);
|
||
return;
|
||
}
|
||
|
||
size_t ulSize = oSrcStringBuilder.GetCurSize();
|
||
size_t ulCurrentBlockSize = 0, ulPosition = 0;
|
||
|
||
while (ulSize > 0)
|
||
{
|
||
ulCurrentBlockSize = std::min(ulSize, MAX_STRING_BLOCK_SIZE);
|
||
oDstStringBuilder.WriteString(oSrcStringBuilder.GetSubData(ulPosition, ulCurrentBlockSize));
|
||
|
||
ulSize -= ulCurrentBlockSize;
|
||
ulPosition += ulCurrentBlockSize;
|
||
}
|
||
}
|
||
|
||
// Ячейка таблицы
|
||
struct CTc
|
||
{
|
||
int i;
|
||
int j;
|
||
std::wstring sGridSpan = L"1";
|
||
std::wstring sPr = L"";
|
||
|
||
CTc(int _i, int _j, const std::wstring& sColspan, const std::wstring& sTcPr = L"")
|
||
: i(_i), j(_j), sGridSpan(sColspan), sPr(sTcPr) {}
|
||
|
||
bool operator==(const CTc& c2)
|
||
{
|
||
return (i == c2.i && j == c2.j && sGridSpan == c2.sGridSpan);
|
||
}
|
||
};
|
||
|
||
// Настройки текста
|
||
struct CTextSettings
|
||
{
|
||
bool bBdo; // Реверс текста
|
||
bool bPre; // Сохранение форматирования (Сохранение пробелов, табуляций, переносов строк)
|
||
bool bQ; // Цитата
|
||
bool bAddSpaces; // Добавлять пробелы перед текстом?
|
||
bool bMergeText; // Объединять подяр идущий текст в 1?
|
||
int nLi; // Уровень списка
|
||
bool bNumberingLi; // Является ли список нумерованным
|
||
|
||
std::wstring sPStyle;
|
||
|
||
enum ETextMode
|
||
{
|
||
Normal,
|
||
Superscript,
|
||
Subscript
|
||
} eTextMode;
|
||
|
||
NSCSS::CCompiledStyle oAdditionalStyle;
|
||
|
||
CTextSettings()
|
||
: bBdo(false), bPre(false), bQ(false), bAddSpaces(true), bMergeText(false), nLi(-1), bNumberingLi(false), eTextMode(Normal)
|
||
{}
|
||
|
||
CTextSettings(const CTextSettings& oTS) :
|
||
bBdo(oTS.bBdo), bPre(oTS.bPre), bQ(oTS.bQ), bAddSpaces(oTS.bAddSpaces), bMergeText(oTS.bMergeText),
|
||
nLi(oTS.nLi), bNumberingLi(oTS.bNumberingLi), sPStyle(oTS.sPStyle), eTextMode(oTS.eTextMode)
|
||
{}
|
||
|
||
void AddPStyle(const std::wstring& wsStyle)
|
||
{
|
||
if (std::wstring::npos == sPStyle.find(wsStyle))
|
||
sPStyle += wsStyle;
|
||
}
|
||
};
|
||
|
||
struct TImageData
|
||
{
|
||
UINT m_unWidth;
|
||
UINT m_unHeight;
|
||
|
||
int m_nHSpace;
|
||
int m_nVSpace;
|
||
|
||
std::wstring m_wsAlign;
|
||
|
||
TImageData()
|
||
: m_unWidth(0), m_unHeight(0), m_nHSpace(0), m_nVSpace(0), m_wsAlign(L"left")
|
||
{}
|
||
|
||
bool ZeroSize() const
|
||
{
|
||
return 0 == m_unWidth || 0 == m_unHeight;
|
||
}
|
||
|
||
bool ZeroSpaces() const
|
||
{
|
||
return 0 == m_nHSpace && 0 == m_nVSpace;
|
||
}
|
||
};
|
||
|
||
void WriteEmptyParagraph(NSStringUtils::CStringBuilder* pXml, bool bVahish = false, bool bInP = false)
|
||
{
|
||
if (NULL == pXml)
|
||
return;
|
||
|
||
if (!bInP)
|
||
pXml->WriteString(L"<w:p><w:pPr>");
|
||
|
||
pXml->WriteString(L"<w:r><w:rPr><w:rFonts w:eastAsia=\"Times New Roman\"/>");
|
||
|
||
if (bVahish)
|
||
pXml->WriteString(L"<w:vanish/>");
|
||
|
||
pXml->WriteString(L"</w:rPr></w:r>");
|
||
|
||
if (!bInP)
|
||
pXml->WriteString(L"</w:pPr></w:p>");
|
||
}
|
||
|
||
bool ElementInTable(const std::vector<NSCSS::CNode>& arSelectors)
|
||
{
|
||
return arSelectors.crend() != std::find_if(arSelectors.crbegin(), arSelectors.crend(), [](const NSCSS::CNode& oNode) { return L"table" == oNode.m_wsName; });
|
||
}
|
||
|
||
UINT GetFontSizeLevel(UINT unFontSize)
|
||
{
|
||
if (unFontSize <= 18)
|
||
return 1;
|
||
else if (unFontSize <= 22)
|
||
return 2;
|
||
else if (unFontSize <= 26)
|
||
return 3;
|
||
else if (unFontSize <= 30)
|
||
return 4;
|
||
else if (unFontSize <= 40)
|
||
return 5;
|
||
else if (unFontSize <= 59)
|
||
return 6;
|
||
else
|
||
return 7;
|
||
}
|
||
|
||
UINT GetFontSizeByLevel(UINT unLevel)
|
||
{
|
||
if (0 == unLevel)
|
||
return 15;
|
||
else if (unLevel > 7)
|
||
return 72;
|
||
|
||
switch (unLevel)
|
||
{
|
||
case 1: return 15;
|
||
case 2: return 20;
|
||
case 3: return 24;
|
||
case 4: return 27;
|
||
case 5: return 36;
|
||
case 6: return 48;
|
||
case 7: return 72;
|
||
}
|
||
return 24;
|
||
}
|
||
|
||
int CalculateFontChange(const std::vector<NSCSS::CNode>& arSelectors)
|
||
{
|
||
int nFontChange = 0;
|
||
|
||
for (const NSCSS::CNode& oNode : arSelectors)
|
||
{
|
||
if (L"big" == oNode.m_wsName)
|
||
++nFontChange;
|
||
else if (L"small" == oNode.m_wsName)
|
||
--nFontChange;
|
||
}
|
||
|
||
return nFontChange;
|
||
}
|
||
|
||
#define FIRST_ELEMENT 0x00000001
|
||
#define LAST_ELEMENT 0x00000002
|
||
#define MID_ELEMENT 0x00000004
|
||
|
||
#define PARSE_MODE_HEADER 0x00000100
|
||
#define PARSE_MODE_BODY 0x00000200
|
||
#define PARSE_MODE_FOOTHER 0x00000400
|
||
|
||
#define COL_POSITION_MASK 0x0000000F
|
||
#define ROW_POSITION_MASK 0x000000F0
|
||
#define PARSE_MODE_MASK 0x00000F00
|
||
|
||
typedef enum
|
||
{
|
||
ParseModeHeader,
|
||
ParseModeBody,
|
||
ParseModeFoother
|
||
} ERowParseMode;
|
||
|
||
//Необходимые стили таблицы
|
||
struct TTableStyles
|
||
{
|
||
NSCSS::NSProperties::CIndent m_oPadding;
|
||
NSCSS::NSProperties::CIndent m_oMargin;
|
||
NSCSS::NSProperties::CBorder m_oBorder;
|
||
NSCSS::NSProperties::CDigit m_oWidth;
|
||
|
||
int m_nCellSpacing;
|
||
|
||
std::wstring m_wsAlign;
|
||
|
||
enum ETableRules
|
||
{
|
||
All,
|
||
Groups,
|
||
Cols,
|
||
None,
|
||
Rows
|
||
} m_enRules;
|
||
|
||
TTableStyles()
|
||
: m_nCellSpacing(-1), m_enRules(None)
|
||
{}
|
||
|
||
bool Empty() const
|
||
{
|
||
return m_oPadding.Empty() && m_oMargin.Empty() && m_oBorder.Empty() && m_oWidth.Empty() && -1 == m_nCellSpacing && m_wsAlign.empty();
|
||
}
|
||
};
|
||
|
||
std::wstring CreateBorders(const NSCSS::NSProperties::CBorder& oBorder, const NSCSS::NSProperties::CIndent* pPadding = NULL, bool bAddIntermediateLines = false, TTableStyles::ETableRules enTableRule = TTableStyles::ETableRules::None)
|
||
{
|
||
std::wstring wsTable;
|
||
|
||
if (oBorder.EqualSides() && (NULL == pPadding || pPadding->Equals()))
|
||
{
|
||
const std::wstring wsBorderStyle = NSCSS::CDocumentStyle::CalculateBorderStyle(oBorder.GetLeftBorder(), ((NULL == pPadding) ? NULL : (&(pPadding->GetLeft()))));
|
||
|
||
wsTable = L"<w:top " + wsBorderStyle + L"/>" + L"<w:left " + wsBorderStyle + L"/>" +
|
||
L"<w:bottom " + wsBorderStyle + L"/>" + L"<w:right " + wsBorderStyle + L"/>";
|
||
}
|
||
else
|
||
{
|
||
if (oBorder.GetTopBorder().Valid())
|
||
wsTable += L"<w:top " + NSCSS::CDocumentStyle::CalculateBorderStyle(oBorder.GetTopBorder(), ((NULL == pPadding) ? NULL : (&(pPadding->GetTop())))) + L"/>";
|
||
|
||
if (oBorder.GetLeftBorder().Valid())
|
||
wsTable += L"<w:left " + NSCSS::CDocumentStyle::CalculateBorderStyle(oBorder.GetLeftBorder(), ((NULL == pPadding) ? NULL : (&(pPadding->GetLeft())))) + L"/>";
|
||
|
||
if (oBorder.GetBottomBorder().Valid())
|
||
wsTable += L"<w:bottom " + NSCSS::CDocumentStyle::CalculateBorderStyle(oBorder.GetBottomBorder(), ((NULL == pPadding) ? NULL : (&(pPadding->GetBottom())))) + L"/>";
|
||
|
||
if (oBorder.GetRightBorder().Valid())
|
||
wsTable += L"<w:right " + NSCSS::CDocumentStyle::CalculateBorderStyle(oBorder.GetRightBorder(), ((NULL == pPadding) ? NULL : (&(pPadding->GetRight())))) + L"/>";
|
||
}
|
||
|
||
if (!bAddIntermediateLines)
|
||
return wsTable;
|
||
|
||
if (TTableStyles::ETableRules::Rows == enTableRule || TTableStyles::ETableRules::All == enTableRule)
|
||
{
|
||
NSCSS::NSProperties::CBorderSide oNewSide(oBorder.GetBottomBorder());
|
||
oNewSide.SetWidth(L"1pt", 0, true);
|
||
|
||
wsTable += L"<w:insideH " + NSCSS::CDocumentStyle::CalculateBorderStyle(oNewSide) + L"/>";
|
||
}
|
||
|
||
if (TTableStyles::ETableRules::Cols == enTableRule || TTableStyles::ETableRules::All == enTableRule)
|
||
{
|
||
NSCSS::NSProperties::CBorderSide oNewSide(oBorder.GetRightBorder());
|
||
oNewSide.SetWidth(L"1pt", 0, true);
|
||
|
||
wsTable += L"<w:insideV " + NSCSS::CDocumentStyle::CalculateBorderStyle(oNewSide) + L"/>";
|
||
}
|
||
|
||
return wsTable;
|
||
}
|
||
|
||
std::wstring CreateBorders(const std::wstring& wsStyle, UINT unSize, UINT unSpace, const std::wstring& wsAuto)
|
||
{
|
||
const std::wstring wsBodyBorder{L"w:val=\"" + wsStyle + L"\" w:sz=\"" + std::to_wstring(unSize) + L"\" w:space=\"" + std::to_wstring(unSpace) + L"\" w:color=\"" + wsAuto + L"\""};
|
||
|
||
return L"<w:top " + wsBodyBorder + L"/>" +
|
||
L"<w:left " + wsBodyBorder + L"/>" +
|
||
L"<w:bottom " + wsBodyBorder + L"/>" +
|
||
L"<w:right " + wsBodyBorder + L"/>";
|
||
}
|
||
|
||
#define CreateOutsetBorders(enType) CreateBorders(L"outset", 6, 0, L"auto", enType)
|
||
|
||
std::wstring CreateDefaultBorder(std::wstring wsSideName)
|
||
{
|
||
std::transform(wsSideName.begin(), wsSideName.end(), wsSideName.begin(), std::towlower);
|
||
return L"<w:" + wsSideName + L" w:val=\"single\" w:sz=\"1\" w:space=\"0\" w:color=\"auto\"/>";
|
||
}
|
||
|
||
struct TTableRowStyle
|
||
{
|
||
UINT m_unMaxIndex;
|
||
UINT m_unMaxHeight;
|
||
bool m_bIsHeader;
|
||
|
||
TTableRowStyle()
|
||
: m_unMaxIndex(0), m_unMaxHeight(0), m_bIsHeader(false)
|
||
{}
|
||
|
||
bool Empty() const
|
||
{
|
||
return 0 == m_unMaxHeight && false == m_bIsHeader;
|
||
}
|
||
};
|
||
|
||
struct TTableCellStyle
|
||
{
|
||
NSCSS::NSProperties::CDigit m_oWidth;
|
||
NSCSS::NSProperties::CDigit m_oHeight;
|
||
NSCSS::NSProperties::CBorder m_oBorder;
|
||
NSCSS::NSProperties::CIndent m_oPadding;
|
||
NSCSS::NSProperties::CColor m_oBackground;
|
||
|
||
std::wstring m_wsHAlign;
|
||
std::wstring m_wsVAlign;
|
||
|
||
TTableCellStyle(){}
|
||
|
||
bool Empty()
|
||
{
|
||
return m_oWidth.Empty() && m_oHeight.Empty() && m_oBorder.Empty() && m_oPadding.Empty() && m_wsVAlign.empty() && m_wsVAlign.empty();
|
||
}
|
||
|
||
void Copy(const TTableCellStyle* pTableCellStyle)
|
||
{
|
||
if (NULL == pTableCellStyle)
|
||
return;
|
||
|
||
m_oWidth = pTableCellStyle->m_oWidth;
|
||
m_oHeight = pTableCellStyle->m_oHeight;
|
||
m_oBorder = pTableCellStyle->m_oBorder;
|
||
m_oPadding = pTableCellStyle->m_oPadding;
|
||
m_oBackground = pTableCellStyle->m_oBackground;
|
||
|
||
m_wsHAlign = pTableCellStyle->m_wsHAlign;
|
||
m_wsVAlign = pTableCellStyle->m_wsVAlign;
|
||
}
|
||
|
||
TTableCellStyle& operator+=(const TTableCellStyle* pCellStyle)
|
||
{
|
||
if (NULL == pCellStyle)
|
||
return *this;
|
||
|
||
m_oWidth += pCellStyle->m_oWidth;
|
||
m_oHeight += pCellStyle->m_oHeight;
|
||
m_oBorder += pCellStyle->m_oBorder;
|
||
m_oPadding += pCellStyle->m_oPadding;
|
||
m_oBackground += pCellStyle->m_oBackground;
|
||
|
||
if (m_wsHAlign.empty())
|
||
m_wsHAlign = pCellStyle->m_wsHAlign;
|
||
|
||
if (m_wsVAlign.empty())
|
||
m_wsVAlign = pCellStyle->m_wsVAlign;
|
||
|
||
return *this;
|
||
}
|
||
};
|
||
|
||
class CTable;
|
||
|
||
class CTableCell
|
||
{
|
||
public:
|
||
CTableCell()
|
||
: m_unColspan(1), m_unRowSpan(1), m_bIsMerged(false), m_bIsEmpty(false)
|
||
{}
|
||
|
||
CTableCell(UINT unColspan, UINT unRowspan, bool bIsMerged, bool bIsEmpty)
|
||
: m_unColspan(unColspan), m_unRowSpan(unRowspan), m_bIsMerged(bIsMerged), m_bIsEmpty(bIsEmpty)
|
||
{}
|
||
|
||
CTableCell(CTableCell& oCell)
|
||
: m_unColspan(oCell.m_unColspan), m_unRowSpan(oCell.m_unRowSpan), m_bIsMerged(oCell.m_bIsMerged),
|
||
m_bIsEmpty(oCell.m_bIsEmpty), m_oStyles(oCell.m_oStyles)
|
||
{
|
||
WriteToStringBuilder(oCell.m_oData, m_oData);
|
||
}
|
||
|
||
bool Empty()
|
||
{
|
||
return m_bIsEmpty;
|
||
}
|
||
|
||
bool Merged()
|
||
{
|
||
return m_bIsMerged;
|
||
}
|
||
|
||
CTableCell* Copy()
|
||
{
|
||
return new CTableCell(*this);
|
||
}
|
||
|
||
static CTableCell* CreateEmpty(UINT unColspan = 1, bool m_bIsMerged = false, const TTableCellStyle* pStyle = NULL)
|
||
{
|
||
CTableCell *pCell = new CTableCell(unColspan, 1, m_bIsMerged, true);
|
||
|
||
pCell->m_oStyles.Copy(pStyle);
|
||
|
||
return pCell;
|
||
}
|
||
|
||
static CTableCell* CreateEmpty(const TTableCellStyle* pStyle)
|
||
{
|
||
CTableCell *pCell = new CTableCell(1, 1, false, true);
|
||
|
||
pCell->m_oStyles.Copy(pStyle);
|
||
|
||
return pCell;
|
||
}
|
||
|
||
void SetColspan(UINT unColspan, UINT unCurrentIndex)
|
||
{
|
||
if (MAXCOLUMNSINTABLE - 1 != unCurrentIndex)
|
||
m_unColspan = std::min(MAXCOLUMNSINTABLE - 1 - unCurrentIndex, unColspan);
|
||
else
|
||
m_unColspan = 1;
|
||
}
|
||
|
||
UINT GetColspan() const
|
||
{
|
||
return m_unColspan;
|
||
}
|
||
|
||
void SetRowspan(UINT unRowspan)
|
||
{
|
||
m_unRowSpan = unRowspan;
|
||
}
|
||
|
||
UINT GetRowspan() const
|
||
{
|
||
return m_unRowSpan;
|
||
}
|
||
|
||
NSStringUtils::CStringBuilder* GetData()
|
||
{
|
||
return &m_oData;
|
||
}
|
||
|
||
const TTableCellStyle* GetStyles() const
|
||
{
|
||
return &m_oStyles;
|
||
}
|
||
|
||
TTableCellStyle* GetStyles()
|
||
{
|
||
return &m_oStyles;
|
||
}
|
||
|
||
void SetWidth(const NSCSS::NSProperties::CDigit& oWidth)
|
||
{
|
||
m_oStyles.m_oWidth = oWidth;
|
||
}
|
||
|
||
void SetHeight(const NSCSS::NSProperties::CDigit& oHeight)
|
||
{
|
||
m_oStyles.m_oHeight = oHeight;
|
||
}
|
||
|
||
UINT GetHeight() const
|
||
{
|
||
return m_oStyles.m_oHeight.ToInt(NSCSS::Twips, DEFAULT_PAGE_HEIGHT);
|
||
}
|
||
|
||
void SetBorder(const NSCSS::NSProperties::CBorder& oBorder)
|
||
{
|
||
m_oStyles.m_oBorder = oBorder;
|
||
}
|
||
|
||
void ClearTopBorder()
|
||
{
|
||
m_oStyles.m_oBorder.SetTopSide(L"none", 0, true);
|
||
}
|
||
|
||
void ClearLeftBorder()
|
||
{
|
||
m_oStyles.m_oBorder.SetLeftSide(L"none", 0, true);
|
||
}
|
||
|
||
void ClearBottomBorder()
|
||
{
|
||
m_oStyles.m_oBorder.SetBottomSide(L"none", 0, true);
|
||
}
|
||
|
||
void ClearRightBorder()
|
||
{
|
||
m_oStyles.m_oBorder.SetRightSide(L"none", 0, true);
|
||
}
|
||
|
||
void SetPadding(const NSCSS::NSProperties::CIndent& oPadding)
|
||
{
|
||
m_oStyles.m_oPadding = oPadding;
|
||
}
|
||
|
||
void SetHAlign(const std::wstring& wsAlign)
|
||
{
|
||
m_oStyles.m_wsHAlign = wsAlign;
|
||
}
|
||
|
||
void SetVAlign(const std::wstring& wsAlign)
|
||
{
|
||
m_oStyles.m_wsVAlign = wsAlign;
|
||
}
|
||
|
||
void SetBackground(const NSCSS::NSProperties::CColor& oColor)
|
||
{
|
||
m_oStyles.m_oBackground = oColor;
|
||
}
|
||
|
||
std::wstring ConvertToOOXML(const CTable& oTable, UINT unColumnNumber, int nInstruction);
|
||
private:
|
||
UINT m_unColspan;
|
||
UINT m_unRowSpan;
|
||
|
||
bool m_bIsMerged;
|
||
bool m_bIsEmpty;
|
||
|
||
TTableCellStyle m_oStyles;
|
||
NSStringUtils::CStringBuilder m_oData;
|
||
};
|
||
|
||
class CTableRow
|
||
{
|
||
public:
|
||
CTableRow()
|
||
{}
|
||
|
||
~CTableRow()
|
||
{
|
||
for (CTableCell* pCell : m_arCells)
|
||
RELEASEOBJECT(pCell);
|
||
}
|
||
|
||
void AddCell(CTableCell* pCell)
|
||
{
|
||
InsertCell(pCell, -1);
|
||
}
|
||
|
||
void InsertCell(CTableCell *pCell, int nPosition)
|
||
{
|
||
if (NULL == pCell)
|
||
return;
|
||
|
||
if (nPosition < 0)
|
||
{
|
||
std::vector<CTableCell*>::iterator itFoundEmpty = std::find_if(m_arCells.begin(), m_arCells.end(), [](CTableCell* pCell) { return pCell->Empty() && !pCell->Merged(); });
|
||
|
||
if (m_arCells.end() != itFoundEmpty)
|
||
{
|
||
--m_oStyles.m_unMaxIndex;
|
||
delete *itFoundEmpty;
|
||
*itFoundEmpty = pCell;
|
||
|
||
if (1 != pCell->GetColspan())
|
||
{
|
||
++itFoundEmpty;
|
||
UINT unColspan = pCell->GetColspan() - 1;
|
||
|
||
while (m_arCells.end() != itFoundEmpty && (*itFoundEmpty)->Empty() && unColspan > 0)
|
||
{
|
||
--m_oStyles.m_unMaxIndex;
|
||
--unColspan;
|
||
delete (*itFoundEmpty);
|
||
itFoundEmpty = m_arCells.erase(itFoundEmpty);
|
||
}
|
||
|
||
if (unColspan != 0)
|
||
pCell->SetColspan(pCell->GetColspan() - unColspan, MAXCOLUMNSINTABLE);
|
||
}
|
||
}
|
||
else
|
||
m_arCells.push_back(pCell);
|
||
}
|
||
else if (nPosition >= m_arCells.size())
|
||
{
|
||
const UINT unMissingCount = nPosition - m_arCells.size();
|
||
|
||
for (UINT unIndex = 0; unIndex < unMissingCount; ++unIndex)
|
||
m_arCells.push_back(CTableCell::CreateEmpty());
|
||
|
||
m_oStyles.m_unMaxIndex += unMissingCount;
|
||
|
||
m_arCells.push_back(pCell);
|
||
}
|
||
else if (m_arCells[nPosition]->Empty())
|
||
{
|
||
delete m_arCells[nPosition];
|
||
--m_oStyles.m_unMaxIndex;
|
||
m_arCells[nPosition] = pCell;
|
||
|
||
if (1 != pCell->GetColspan())
|
||
{
|
||
++nPosition;
|
||
UINT unDeleteCount = pCell->GetColspan() - 1;
|
||
while (nPosition < m_arCells.size() && m_arCells[nPosition]->Empty() && !m_arCells[nPosition]->Merged() && unDeleteCount > 0)
|
||
{
|
||
delete m_arCells[nPosition];
|
||
--m_oStyles.m_unMaxIndex;
|
||
m_arCells.erase(m_arCells.begin() + nPosition);
|
||
--unDeleteCount;
|
||
}
|
||
|
||
if (0 != unDeleteCount)
|
||
pCell->SetColspan(pCell->GetColspan() - unDeleteCount, MAXCOLUMNSINTABLE);
|
||
}
|
||
}
|
||
else
|
||
m_arCells.insert(m_arCells.begin() + nPosition, pCell);
|
||
|
||
m_oStyles.m_unMaxIndex += pCell->GetColspan();
|
||
|
||
if (1 == pCell->GetColspan() && 1 == pCell->GetRowspan())
|
||
m_oStyles.m_unMaxHeight = std::max(m_oStyles.m_unMaxHeight, pCell->GetHeight());
|
||
}
|
||
|
||
UINT GetIndex() const
|
||
{
|
||
return m_oStyles.m_unMaxIndex;
|
||
}
|
||
|
||
UINT GetCount() const
|
||
{
|
||
return m_arCells.size();
|
||
}
|
||
|
||
std::wstring ConvertToOOXML(const CTable& oTable, int nInstruction);
|
||
|
||
CTableCell* operator[](UINT unIndex)
|
||
{
|
||
if (unIndex >= m_arCells.size())
|
||
return NULL;
|
||
|
||
return m_arCells[unIndex];
|
||
}
|
||
private:
|
||
TTableRowStyle m_oStyles;
|
||
std::vector<CTableCell*> m_arCells;
|
||
};
|
||
|
||
class CTableCol
|
||
{
|
||
public:
|
||
CTableCol(UINT unSpan)
|
||
: m_unSpan(unSpan)
|
||
{}
|
||
|
||
CTableCol(XmlUtils::CXmlLiteReader& oLiteReader)
|
||
: m_unSpan(1)
|
||
{
|
||
while (oLiteReader.MoveToNextAttribute())
|
||
{
|
||
if (L"span" == oLiteReader.GetName())
|
||
m_unSpan = NSStringFinder::ToInt(oLiteReader.GetText(), 1);
|
||
}
|
||
|
||
oLiteReader.MoveToElement();
|
||
}
|
||
|
||
UINT GetSpan() const
|
||
{
|
||
return m_unSpan;
|
||
}
|
||
|
||
TTableCellStyle* GetStyle()
|
||
{
|
||
return &m_oStyle;
|
||
}
|
||
|
||
const TTableCellStyle* GetStyle() const
|
||
{
|
||
return &m_oStyle;
|
||
}
|
||
private:
|
||
UINT m_unSpan;
|
||
TTableCellStyle m_oStyle;
|
||
};
|
||
|
||
class CTableColgroup
|
||
{
|
||
public:
|
||
CTableColgroup(XmlUtils::CXmlLiteReader& oLiteReader)
|
||
: m_unWidth(0)
|
||
{
|
||
while (oLiteReader.MoveToNextAttribute())
|
||
{
|
||
if (L"width" == oLiteReader.GetName())
|
||
m_unWidth = NSStringFinder::ToInt(oLiteReader.GetText());
|
||
}
|
||
|
||
oLiteReader.MoveToElement();
|
||
}
|
||
|
||
~CTableColgroup()
|
||
{
|
||
RELEASE_VECTOR_PTR(m_arCols, CTableCol)
|
||
}
|
||
|
||
bool Empty() const
|
||
{
|
||
return m_arCols.empty();
|
||
}
|
||
|
||
void AddCol(CTableCol* pCol)
|
||
{
|
||
if (NULL != pCol)
|
||
m_arCols.push_back(pCol);
|
||
}
|
||
|
||
const std::vector<CTableCol*>& GetCols() const
|
||
{
|
||
return m_arCols;
|
||
}
|
||
private:
|
||
std::vector<CTableCol*> m_arCols;
|
||
UINT m_unWidth;
|
||
};
|
||
|
||
class CTable
|
||
{
|
||
public:
|
||
CTable()
|
||
: m_unMaxColumns(0)
|
||
{}
|
||
|
||
~CTable()
|
||
{
|
||
for (std::vector<CTableRow*>& arHeaders : m_arHeaders)
|
||
RELEASE_VECTOR_PTR(arHeaders, CTableRow)
|
||
|
||
RELEASE_VECTOR_PTR(m_arFoother, CTableRow)
|
||
RELEASE_VECTOR_PTR(m_arRows, CTableRow)
|
||
RELEASE_VECTOR_PTR(m_arColgroups, CTableColgroup)
|
||
}
|
||
|
||
CTableRow* operator[](UINT unIndex)
|
||
{
|
||
if (unIndex < m_arRows.size())
|
||
return m_arRows[unIndex];
|
||
|
||
return NULL;
|
||
}
|
||
|
||
bool Empty() const
|
||
{
|
||
return m_arRows.empty();
|
||
}
|
||
|
||
bool HaveCaption()
|
||
{
|
||
return 0 != m_oCaption.GetCurSize();
|
||
}
|
||
|
||
bool HaveColgroups() const
|
||
{
|
||
return !m_arColgroups.empty();
|
||
}
|
||
|
||
UINT GetRowCount() const
|
||
{
|
||
return m_arRows.size();
|
||
}
|
||
|
||
TTableStyles GetTableStyles() const
|
||
{
|
||
return m_oStyles;
|
||
}
|
||
|
||
const TTableCellStyle* GetColStyle(UINT unColumnNumber) const
|
||
{
|
||
if (m_arColgroups.empty())
|
||
return NULL;
|
||
|
||
UINT unCurrentNumber = 0;
|
||
|
||
for (const CTableColgroup* pColgroup : m_arColgroups)
|
||
{
|
||
for (const CTableCol* pCol : pColgroup->GetCols())
|
||
{
|
||
unCurrentNumber += pCol->GetSpan();
|
||
|
||
if (unCurrentNumber >= unColumnNumber)
|
||
return pCol->GetStyle();
|
||
}
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
std::wstring CalculateSidesToClean(UINT unColumnNumber) const
|
||
{
|
||
if (m_arColgroups.empty())
|
||
return std::wstring();
|
||
|
||
UINT unCurrentNumber = 0;
|
||
|
||
for (const CTableColgroup* pColgroup : m_arColgroups)
|
||
{
|
||
for (const CTableCol* pCol : pColgroup->GetCols())
|
||
{
|
||
if (unCurrentNumber + 1 == unCurrentNumber)
|
||
return (1 != pCol->GetSpan()) ? L"<w:right w:val=\"nil\"/>" : std::wstring();
|
||
|
||
unCurrentNumber += pCol->GetSpan();
|
||
|
||
if (unColumnNumber == unCurrentNumber)
|
||
return (1 != pCol->GetSpan()) ? L"<w:left w:val=\"nil\"/>" : std::wstring();
|
||
else if (unColumnNumber < unCurrentNumber)
|
||
return std::wstring((1 != unColumnNumber) ? L"<w:left w:val=\"nil\"/>" : L"") + std::wstring((m_unMaxColumns != unColumnNumber) ? L"<w:right w:val=\"nil\"/>" : L"");
|
||
}
|
||
}
|
||
|
||
return std::wstring();
|
||
}
|
||
|
||
void AddRows(std::vector<CTableRow*>& m_arRows, ERowParseMode eParseMode = ERowParseMode::ParseModeBody)
|
||
{
|
||
if (m_arRows.empty())
|
||
return;
|
||
|
||
if (ERowParseMode::ParseModeFoother == eParseMode && !m_arFoother.empty())
|
||
eParseMode = ERowParseMode::ParseModeHeader;
|
||
|
||
if (ERowParseMode::ParseModeHeader == eParseMode)
|
||
m_arHeaders.push_back({});
|
||
|
||
for (CTableRow* pRow : m_arRows)
|
||
AddRow(pRow, eParseMode);
|
||
}
|
||
|
||
void AddRow(CTableRow* pRow, ERowParseMode eParseMode = ERowParseMode::ParseModeBody)
|
||
{
|
||
if (NULL == pRow)
|
||
return;
|
||
|
||
for (UINT unIndex = 0; unIndex < pRow->GetCount(); ++unIndex)
|
||
{
|
||
if (unIndex >= m_arMinColspan.size())
|
||
m_arMinColspan.push_back((*pRow)[unIndex]->GetColspan());
|
||
else if ((*pRow)[unIndex]->GetColspan() < m_arMinColspan[unIndex])
|
||
m_arMinColspan[unIndex] = (*pRow)[unIndex]->GetColspan();
|
||
}
|
||
|
||
switch (eParseMode)
|
||
{
|
||
default:
|
||
case ERowParseMode::ParseModeBody:
|
||
{
|
||
m_arRows.push_back(pRow);
|
||
break;
|
||
}
|
||
case ERowParseMode::ParseModeHeader:
|
||
{
|
||
if (m_arHeaders.empty())
|
||
m_arHeaders.push_back({});
|
||
|
||
m_arHeaders.back().push_back(pRow);
|
||
break;
|
||
}
|
||
case ERowParseMode::ParseModeFoother:
|
||
{
|
||
m_arFoother.push_back(pRow);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void AddCaption(NSStringUtils::CStringBuilder& oCaption)
|
||
{
|
||
WriteToStringBuilder(oCaption, m_oCaption);
|
||
}
|
||
|
||
void SetPadding(const NSCSS::NSProperties::CIndent& oPadding)
|
||
{
|
||
m_oStyles.m_oPadding = oPadding;
|
||
}
|
||
|
||
void SetMargin(const NSCSS::NSProperties::CIndent& oMargin)
|
||
{
|
||
m_oStyles.m_oMargin = oMargin;
|
||
}
|
||
|
||
const NSCSS::NSProperties::CIndent& GetPadding() const
|
||
{
|
||
return m_oStyles.m_oPadding;
|
||
}
|
||
|
||
void SetBorder(const NSCSS::NSProperties::CBorder& oBorder)
|
||
{
|
||
m_oStyles.m_oBorder = oBorder;
|
||
}
|
||
|
||
void SetWidth(const NSCSS::NSProperties::CDigit& oWidth)
|
||
{
|
||
m_oStyles.m_oWidth = oWidth;
|
||
}
|
||
|
||
void SetCellSpacing(int nCellSpacing)
|
||
{
|
||
m_oStyles.m_nCellSpacing = nCellSpacing;
|
||
}
|
||
|
||
void SetAlign(const std::wstring& wsValue)
|
||
{
|
||
m_oStyles.m_wsAlign = wsValue;
|
||
}
|
||
|
||
void SetRules(const std::wstring& wsValue)
|
||
{
|
||
if (wsValue.empty())
|
||
return;
|
||
|
||
if (NSStringFinder::Equals(wsValue, L"all"))
|
||
m_oStyles.m_enRules = TTableStyles::ETableRules::All;
|
||
else if (NSStringFinder::Equals(wsValue, L"groups"))
|
||
m_oStyles.m_enRules = TTableStyles::ETableRules::Groups;
|
||
else if (NSStringFinder::Equals(wsValue, L"cols"))
|
||
m_oStyles.m_enRules = TTableStyles::ETableRules::Cols;
|
||
else if (NSStringFinder::Equals(wsValue, L"none"))
|
||
m_oStyles.m_enRules = TTableStyles::ETableRules::None;
|
||
else if (NSStringFinder::Equals(wsValue, L"rows"))
|
||
m_oStyles.m_enRules = TTableStyles::ETableRules::Rows;
|
||
}
|
||
|
||
void AddColgroup(CTableColgroup* pElement)
|
||
{
|
||
if (NULL != pElement)
|
||
m_arColgroups.push_back(pElement);
|
||
}
|
||
|
||
void RecalculateMaxColumns()
|
||
{
|
||
for (const CTableRow* pRow : m_arRows)
|
||
m_unMaxColumns = std::max(m_unMaxColumns, pRow->GetIndex());
|
||
}
|
||
|
||
void Shorten()
|
||
{
|
||
UINT unIndex = 0;
|
||
CTableCell* pCell = NULL;
|
||
|
||
UINT unMaxIndex = 0; //Максимальный индекс без учета строк, где имеется только 1 ячейка
|
||
|
||
for (const CTableRow* pRow : m_arRows)
|
||
{
|
||
if (1 < pRow->GetCount())
|
||
unMaxIndex = std::max(unMaxIndex, pRow->GetIndex());
|
||
}
|
||
|
||
while (unIndex < m_arMinColspan.size())
|
||
{
|
||
for (CTableRow* pRow : m_arRows)
|
||
{
|
||
if (0 != unMaxIndex && 1 == pRow->GetCount() && pRow->GetIndex() > unMaxIndex)
|
||
{
|
||
pCell = (*pRow)[unIndex];
|
||
|
||
if (NULL == pCell)
|
||
continue;
|
||
|
||
pCell->SetColspan(unMaxIndex, MAXCOLUMNSINTABLE);
|
||
continue;
|
||
}
|
||
|
||
if (1 == m_arMinColspan[unIndex])
|
||
break;
|
||
|
||
pCell = (*pRow)[unIndex];
|
||
|
||
if (NULL == pCell)
|
||
continue;
|
||
|
||
if (1 < pCell->GetColspan() && pCell->GetColspan() > m_arMinColspan[unIndex])
|
||
{
|
||
pCell->SetColspan(m_arMinColspan[unIndex], MAXCOLUMNSINTABLE);
|
||
continue;
|
||
}
|
||
|
||
if ((*pRow)[unIndex]->GetColspan() == m_arMinColspan[unIndex] + 1)
|
||
(*pRow)[unIndex]->SetColspan(2, MAXCOLUMNSINTABLE);
|
||
else if ((*pRow)[unIndex]->GetColspan() > m_arMinColspan[unIndex])
|
||
(*pRow)[unIndex]->SetColspan((*pRow)[unIndex]->GetColspan() - m_arMinColspan[unIndex], MAXCOLUMNSINTABLE);
|
||
}
|
||
|
||
++unIndex;
|
||
}
|
||
}
|
||
|
||
void CompleteTable()
|
||
{
|
||
UINT unMaxIndex = 0;
|
||
|
||
for (CTableRow* pRow : m_arRows)
|
||
unMaxIndex = std::max(unMaxIndex, pRow->GetIndex());
|
||
|
||
for (CTableRow* pRow : m_arRows)
|
||
{
|
||
if (NULL == pRow || 0 == pRow->GetCount())
|
||
continue;
|
||
|
||
for (UINT unIndex = pRow->GetIndex(); unIndex < unMaxIndex; ++unIndex)
|
||
pRow->InsertCell(CTableCell::CreateEmpty(), unIndex);
|
||
}
|
||
|
||
RecalculateMaxColumns();
|
||
}
|
||
|
||
bool ConvertToOOXML(NSStringUtils::CStringBuilder& oStringBuilder)
|
||
{
|
||
if (m_arRows.empty() && m_arHeaders.empty() && m_arFoother.empty())
|
||
return false;
|
||
|
||
oStringBuilder.WriteNodeBegin(L"w:tbl");
|
||
oStringBuilder.WriteNodeBegin(L"w:tblPr");
|
||
|
||
if (!m_oStyles.m_oWidth.Empty() && !m_oStyles.m_oWidth.Zero())
|
||
{
|
||
if (NSCSS::UnitMeasure::Percent == m_oStyles.m_oWidth.GetUnitMeasure())
|
||
oStringBuilder += L"<w:tblW w:w=\"" + std::to_wstring(m_oStyles.m_oWidth.ToInt(NSCSS::UnitMeasure::Percent, 5000)) + L"\" w:type=\"pct\"/>";
|
||
else
|
||
oStringBuilder += L"<w:tblW w:w=\"" + std::to_wstring(m_oStyles.m_oWidth.ToInt(NSCSS::UnitMeasure::Twips)) + L"\" w:type=\"dxa\"/>";
|
||
}
|
||
else
|
||
oStringBuilder += L"<w:tblW w:w=\"0\" w:type=\"auto\"/>";
|
||
|
||
if (!m_oStyles.m_oMargin.GetLeft().Empty() && !m_oStyles.m_oMargin.GetLeft().Zero())
|
||
{
|
||
if (NSCSS::UnitMeasure::Percent == m_oStyles.m_oMargin.GetLeft().GetUnitMeasure())
|
||
oStringBuilder += L"<w:tblInd w:w=\"" + std::to_wstring(m_oStyles.m_oMargin.GetLeft().ToInt(NSCSS::UnitMeasure::Percent, 5000)) + L"\" w:type=\"pct\"/>";
|
||
else
|
||
oStringBuilder += L"<w:tblInd w:w=\"" + std::to_wstring(m_oStyles.m_oMargin.GetLeft().ToInt(NSCSS::UnitMeasure::Twips)) + L"\" w:type=\"dxa\"/>";
|
||
}
|
||
|
||
if (!m_oStyles.m_wsAlign.empty())
|
||
oStringBuilder += L"<w:jc w:val=\"" + m_oStyles.m_wsAlign + L"\"/>";
|
||
|
||
if (0 < m_oStyles.m_nCellSpacing && m_oStyles.m_oBorder.GetCollapse() != NSCSS::NSProperties::BorderCollapse::Collapse)
|
||
oStringBuilder += L"<w:tblCellSpacing w:w=\"" + std::to_wstring(m_oStyles.m_nCellSpacing) + L"\" w:type=\"dxa\"/>";
|
||
|
||
if (!m_oStyles.m_oBorder.Empty() && !m_oStyles.m_oBorder.Zero())
|
||
oStringBuilder += L"<w:tblBorders>" + CreateBorders(m_oStyles.m_oBorder, NULL, true, (TTableStyles::ETableRules::Groups == m_oStyles.m_enRules && !m_arColgroups.empty()) ? TTableStyles::ETableRules::Cols : m_oStyles.m_enRules) + L"</w:tblBorders>";
|
||
|
||
if (!m_oStyles.m_oPadding.Empty() && !m_oStyles.m_oPadding.Zero())
|
||
{
|
||
const int nTopPadding = std::max(0, m_oStyles.m_oPadding.GetTop() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_HEIGHT));
|
||
const int nLeftPadding = std::max(0, m_oStyles.m_oPadding.GetLeft() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_WIDTH ));
|
||
const int nBottomPadding = std::max(0, m_oStyles.m_oPadding.GetBottom().ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_HEIGHT));
|
||
const int nRightPadding = std::max(0, m_oStyles.m_oPadding.GetRight() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_WIDTH ));
|
||
|
||
oStringBuilder.WriteNodeBegin(L"w:tblCellMar");
|
||
|
||
if (0 != nTopPadding)
|
||
oStringBuilder += L"<w:top w:w=\"" + std::to_wstring(nTopPadding) + L"\" w:type=\"dxa\"/>";
|
||
|
||
if (0 != nLeftPadding)
|
||
oStringBuilder += L"<w:left w:w=\"" + std::to_wstring(nLeftPadding) + L"\" w:type=\"dxa\"/>";
|
||
|
||
if (0 != nBottomPadding)
|
||
oStringBuilder += L"<w:bottom w:w=\"" + std::to_wstring(nBottomPadding) + L"\" w:type=\"dxa\"/>";
|
||
|
||
if (0 != nRightPadding)
|
||
oStringBuilder += L"<w:right w:w=\"" + std::to_wstring(nRightPadding) + L"\" w:type=\"dxa\"/>";
|
||
|
||
oStringBuilder.WriteNodeEnd(L"w:tblCellMar");
|
||
}
|
||
else
|
||
oStringBuilder += L"<w:tblCellMar><w:top w:w=\"15\" w:type=\"dxa\"/><w:left w:w=\"15\" w:type=\"dxa\"/><w:bottom w:w=\"15\" w:type=\"dxa\"/><w:right w:w=\"15\" w:type=\"dxa\"/></w:tblCellMar>";
|
||
|
||
oStringBuilder += L"<w:tblLook w:val=\"04A0\" w:noVBand=\"1\" w:noHBand=\"0\" w:lastColumn=\"0\" w:firstColumn=\"1\" w:lastRow=\"0\" w:firstRow=\"1\"/>";
|
||
oStringBuilder.WriteNodeEnd(L"w:tblPr");
|
||
|
||
if (HaveCaption())
|
||
{
|
||
oStringBuilder.WriteNodeBegin(L"w:tr");
|
||
oStringBuilder.WriteNodeBegin(L"w:tc");
|
||
oStringBuilder.WriteNodeBegin(L"w:tcPr");
|
||
oStringBuilder += L"<w:tcW w:w=\"0\" w:type=\"auto\"/>";
|
||
oStringBuilder += L"<w:gridSpan w:val=\"" + std::to_wstring(m_unMaxColumns) + L"\"/>";
|
||
oStringBuilder += L"<w:tcBorders><w:top w:val=\"nil\"/><w:left w:val=\"nil\"/><w:bottom w:val=\"nil\"/><w:right w:val=\"nil\"/></w:tcBorders>";
|
||
oStringBuilder += L"<w:vAlign w:val=\"center\"/>";
|
||
oStringBuilder += L"<w:hideMark/>";
|
||
oStringBuilder.WriteNodeEnd(L"w:tcPr");
|
||
WriteToStringBuilder(m_oCaption, oStringBuilder);
|
||
oStringBuilder.WriteNodeEnd(L"w:tc");
|
||
oStringBuilder.WriteNodeEnd(L"w:tr");
|
||
}
|
||
|
||
#define CONVERT_ROWS(rows, mode) \
|
||
{ \
|
||
for (UINT unRowIndex = 0; unRowIndex < rows.size(); ++unRowIndex) \
|
||
{ \
|
||
int nInstruction = 0; \
|
||
if (0 == unRowIndex) \
|
||
nInstruction |= FIRST_ELEMENT << 4; \
|
||
if (rows.size() - 1 == unRowIndex) \
|
||
nInstruction |= LAST_ELEMENT << 4; \
|
||
else if (0 != unRowIndex) \
|
||
nInstruction |= MID_ELEMENT << 4; \
|
||
nInstruction |= mode; \
|
||
oStringBuilder += rows[unRowIndex]->ConvertToOOXML(*this, nInstruction); \
|
||
} \
|
||
}
|
||
|
||
for (std::vector<CTableRow*>& arRows : m_arHeaders)
|
||
CONVERT_ROWS(arRows, PARSE_MODE_HEADER)
|
||
|
||
CONVERT_ROWS(m_arRows, PARSE_MODE_BODY)
|
||
CONVERT_ROWS(m_arFoother, PARSE_MODE_FOOTHER)
|
||
|
||
oStringBuilder.WriteNodeEnd(L"w:tbl");
|
||
|
||
return true;
|
||
}
|
||
private:
|
||
std::vector<std::vector<CTableRow*>> m_arHeaders;
|
||
std::vector<CTableRow*> m_arFoother;
|
||
std::vector<CTableRow*> m_arRows;
|
||
|
||
std::vector<UINT> m_arMinColspan;
|
||
|
||
NSStringUtils::CStringBuilder m_oCaption;
|
||
|
||
std::vector<CTableColgroup*> m_arColgroups;
|
||
|
||
TTableStyles m_oStyles;
|
||
|
||
UINT m_unMaxColumns;
|
||
};
|
||
|
||
enum class EAbstructNumType
|
||
{
|
||
Bullet,
|
||
CardinalText,
|
||
Chicago,
|
||
Decimal,
|
||
DecimalEnclosedCircle,
|
||
DecimalEnclosedFullstop,
|
||
DecimalEnclosedParen,
|
||
DecimalZero,
|
||
LowerLetter,
|
||
LowerRoman,
|
||
None,
|
||
OrdinalText,
|
||
UpperLetter,
|
||
UpperRoman
|
||
};
|
||
|
||
void replace_all(std::wstring& s, const std::wstring& s1, const std::wstring& s2)
|
||
{
|
||
size_t pos = s.find(s1);
|
||
size_t l = s2.length();
|
||
while (pos != std::string::npos)
|
||
{
|
||
if (!(s1 == L"&" && s2 == L"&" && s.length() > pos + 4 && s[pos] == L'&' && s[pos + 1] == L'a' && s[pos + 2] == L'm' && s[pos + 3] == L'p' && s[pos + 4] == L';'))
|
||
s.replace(pos, s1.length(), s2);
|
||
pos = s.find(s1, pos + l);
|
||
}
|
||
}
|
||
|
||
void ReplaceSpaces(std::wstring& wsValue)
|
||
{
|
||
// boost::wregex oRegex(L"\\s+");
|
||
// wsValue = boost::regex_replace(wsValue, oRegex, L" ");
|
||
|
||
std::wstring::const_iterator itBegin = std::find_if(wsValue.cbegin(), wsValue.cend(), [](wchar_t wchValue){ return std::iswspace(wchValue) && 0xa0 != wchValue; });
|
||
std::wstring::const_iterator itEnd;
|
||
|
||
while (wsValue.cend() != itBegin)
|
||
{
|
||
itEnd = std::find_if(itBegin, wsValue.cend(), [](wchar_t wchValue){ return !std::iswspace(wchValue) || 0xa0 == wchValue; });
|
||
|
||
wsValue.replace(itBegin, itEnd, L" ");
|
||
|
||
itBegin = std::find_if(itBegin + 1, wsValue.cend(), [](wchar_t wchValue){ return std::iswspace(wchValue) && 0xa0 != wchValue; });
|
||
}
|
||
}
|
||
|
||
std::wstring EncodeXmlString(const std::wstring& s)
|
||
{
|
||
std::wstring sRes = s;
|
||
|
||
replace_all(sRes, L"&", L"&");
|
||
replace_all(sRes, L"<", L"<");
|
||
replace_all(sRes, L">", L">");
|
||
replace_all(sRes, L"\"", L""");
|
||
replace_all(sRes, L"\'", L"'");
|
||
replace_all(sRes, L"\n", L"
");
|
||
replace_all(sRes, L"\r", L"
");
|
||
replace_all(sRes, L"\t", L"	");
|
||
|
||
return sRes;
|
||
}
|
||
|
||
bool GetStatusUsingExternalLocalFiles()
|
||
{
|
||
if (NSProcessEnv::IsPresent(NSProcessEnv::Converter::gc_allowPrivateIP))
|
||
return NSProcessEnv::GetBoolValue(NSProcessEnv::Converter::gc_allowPrivateIP);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool CanUseThisPath(const std::wstring& wsPath, const std::wstring& wsSrcPath, const std::wstring& wsCorePath, bool bIsAllowExternalLocalFiles)
|
||
{
|
||
if (bIsAllowExternalLocalFiles)
|
||
return true;
|
||
|
||
if (!wsCorePath.empty())
|
||
{
|
||
const std::wstring wsFullPath = NSSystemPath::ShortenPath(NSSystemPath::Combine(wsSrcPath, wsPath));
|
||
return boost::starts_with(wsFullPath, wsCorePath);
|
||
}
|
||
|
||
if (wsPath.length() >= 3 && L"../" == wsPath.substr(0, 3))
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
class CHtmlFile2_Private
|
||
{
|
||
public:
|
||
XmlUtils::CXmlLiteReader m_oLightReader; // SAX Reader
|
||
NSCSS::CCssCalculator m_oStylesCalculator; // Css калькулятор
|
||
NSCSS::CDocumentStyle m_oXmlStyle; // Ooxml стиль
|
||
|
||
NSCSS::NSProperties::CPage m_oPageData; // Стили страницы
|
||
|
||
std::wstring m_sTmp; // Temp папка
|
||
std::wstring m_sSrc; // Директория источника
|
||
std::wstring m_sDst; // Директория назначения
|
||
std::wstring m_sBase; // Полный базовый адрес
|
||
std::wstring m_sCore; // Путь до корневого файла (используется для работы с Epub)
|
||
|
||
private:
|
||
int m_nFootnoteId; // ID сноски
|
||
int m_nHyperlinkId; // ID ссылки
|
||
int m_nNumberingId; // ID списка
|
||
int m_nId; // ID остальные элементы
|
||
int m_nShapeId; // Id shape's
|
||
|
||
NSStringUtils::CStringBuilder m_oStylesXml; // styles.xml
|
||
NSStringUtils::CStringBuilder m_oDocXmlRels; // document.xml.rels
|
||
NSStringUtils::CStringBuilder m_oNoteXmlRels; // footnotes.xml.rels
|
||
NSStringUtils::CStringBuilder m_oDocXml; // document.xml
|
||
NSStringUtils::CStringBuilder m_oNoteXml; // footnotes.xml
|
||
NSStringUtils::CStringBuilder m_oNumberXml; // numbering.xml
|
||
NSStringUtils::CStringBuilder m_oWebSettings; // webSettings.xml
|
||
|
||
struct TState
|
||
{
|
||
bool m_bInP; // <w:p> открыт?
|
||
bool m_bInR; // <w:r> открыт?
|
||
bool m_bInT; // <w:t> открыт?
|
||
bool m_bWasPStyle; // <w:pStyle> записан?
|
||
bool m_bWasSpace; // Был пробел?
|
||
bool m_bInHyperlink; // <w:hyperlink> открыт?
|
||
|
||
bool m_bBanUpdatePageData; // Запретить обновление данных о странице?
|
||
|
||
TState()
|
||
: m_bInP(false), m_bInR(false), m_bInT(false), m_bWasPStyle(false), m_bWasSpace(true), m_bInHyperlink(false), m_bBanUpdatePageData(false)
|
||
{}
|
||
} m_oState;
|
||
|
||
std::vector<std::wstring> m_arrImages; // Картинки
|
||
std::map<std::wstring, std::wstring> m_mFootnotes; // Сноски
|
||
std::map<std::wstring, UINT> m_mBookmarks; // Закладки
|
||
std::map<std::wstring, UINT> m_mDivs; // Div элементы
|
||
|
||
NSFonts::IApplicationFonts* m_pFonts; // Необходимо для оптимизации работы со шрифтами
|
||
public:
|
||
|
||
CHtmlFile2_Private()
|
||
: m_nFootnoteId(1), m_nHyperlinkId(1), m_nNumberingId(1), m_nId(1), m_nShapeId(1), m_pFonts(NULL)
|
||
{
|
||
m_oPageData.SetWidth (DEFAULT_PAGE_WIDTH, NSCSS::UnitMeasure::Twips, 0, true);
|
||
m_oPageData.SetHeight(DEFAULT_PAGE_HEIGHT, NSCSS::UnitMeasure::Twips, 0, true);
|
||
m_oPageData.SetMargin(1440, NSCSS::UnitMeasure::Twips, 0, true);
|
||
m_oPageData.SetFooter(720, NSCSS::UnitMeasure::Twips, 0, true);
|
||
m_oPageData.SetHeader(720, NSCSS::UnitMeasure::Twips, 0, true);
|
||
}
|
||
|
||
~CHtmlFile2_Private()
|
||
{
|
||
m_oLightReader .Clear();
|
||
m_oStylesCalculator.Clear();
|
||
m_oXmlStyle .Clear();
|
||
m_oStylesXml .Clear();
|
||
m_oDocXmlRels .Clear();
|
||
m_oNoteXmlRels .Clear();
|
||
m_oDocXml .Clear();
|
||
m_oNoteXml .Clear();
|
||
m_oNumberXml .Clear();
|
||
m_oWebSettings .Clear();
|
||
|
||
if (NULL != m_pFonts)
|
||
RELEASEINTERFACE(m_pFonts);
|
||
}
|
||
|
||
// Проверяет наличие тэга html
|
||
bool isHtml()
|
||
{
|
||
return (m_oLightReader.ReadNextNode() ? m_oLightReader.GetName() == L"html" : false);
|
||
}
|
||
|
||
// Создаёт основу docx
|
||
void CreateDocxEmpty(CHtmlParams* oParams)
|
||
{
|
||
// Создаем пустые папки
|
||
NSDirectory::CreateDirectory(m_sDst + L"/_rels");
|
||
NSDirectory::CreateDirectory(m_sDst + L"/docProps");
|
||
NSDirectory::CreateDirectory(m_sDst + L"/word");
|
||
NSDirectory::CreateDirectory(m_sDst + L"/word/_rels");
|
||
NSDirectory::CreateDirectory(m_sDst + L"/word/media");
|
||
NSDirectory::CreateDirectory(m_sDst + L"/word/theme");
|
||
|
||
// theme1.xml
|
||
std::wstring sTheme = 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_sDst + L"/word/theme/theme1.xml"))
|
||
{
|
||
oThemeWriter.WriteStringUTF8(sTheme);
|
||
oThemeWriter.CloseFile();
|
||
}
|
||
|
||
// app.xml
|
||
std::wstring sApplication = NSSystemUtils::GetEnvVariable(NSSystemUtils::gc_EnvApplicationName);
|
||
if (sApplication.empty())
|
||
sApplication = NSSystemUtils::gc_EnvApplicationNameDefault;
|
||
#if defined(INTVER)
|
||
std::string sVersion = VALUE2STR(INTVER);
|
||
#endif
|
||
std::wstring sApp = 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>";
|
||
sApp += sApplication + L"/" + UTF8_TO_U(sVersion);
|
||
sApp += 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_sDst + L"/docProps/app.xml"))
|
||
{
|
||
oAppWriter.WriteStringUTF8(sApp);
|
||
oAppWriter.CloseFile();
|
||
}
|
||
|
||
// .rels
|
||
std::wstring sRels = 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_sDst + L"/_rels/.rels"))
|
||
{
|
||
oRelsWriter.WriteStringUTF8(sRels);
|
||
oRelsWriter.CloseFile();
|
||
}
|
||
|
||
// [Content_Types].xml
|
||
std::wstring sContent = L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\"><Default Extension=\"bmp\" ContentType=\"image/bmp\"/><Default Extension=\"svg\" ContentType=\"image/svg+xml\"/><Default Extension=\"jfif\" ContentType=\"image/jpeg\"/><Default Extension=\"wmf\" ContentType=\"image/x-wmf\"/><Default Extension=\"gif\" ContentType=\"image/gif\"/><Default Extension=\"jpe\" ContentType=\"image/jpeg\"/><Default Extension=\"png\" ContentType=\"image/png\"/><Default Extension=\"jpg\" ContentType=\"image/jpeg\"/><Default Extension=\"jpeg\" ContentType=\"image/jpeg\"/><Default Extension=\"xml\" ContentType=\"application/xml\"/><Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/><Default Extension=\"bin\" ContentType=\"application/vnd.openxmlformats-officedocument.oleObject\"/><Override PartName=\"/docProps/core.xml\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\"/><Override PartName=\"/word/theme/theme1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.theme+xml\"/><Override PartName=\"/word/fontTable.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml\"/><Override PartName=\"/word/webSettings.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml\"/><Override PartName=\"/word/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml\"/><Override PartName=\"/word/document.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\"/><Override PartName=\"/word/footnotes.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml\"/><Override PartName=\"/word/settings.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml\"/><Override PartName=\"/docProps/app.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\"/><Override PartName=\"/word/numbering.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml\"/></Types>";
|
||
NSFile::CFileBinary oContentWriter;
|
||
if (oContentWriter.CreateFileW(m_sDst + L"/[Content_Types].xml"))
|
||
{
|
||
oContentWriter.WriteStringUTF8(sContent);
|
||
oContentWriter.CloseFile();
|
||
}
|
||
|
||
// fontTable.xml
|
||
std::wstring sFontTable = 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_sDst + L"/word/fontTable.xml"))
|
||
{
|
||
oFontTableWriter.WriteStringUTF8(sFontTable);
|
||
oFontTableWriter.CloseFile();
|
||
}
|
||
|
||
// settings.xml
|
||
std::wstring sSettings = 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:displayBackgroundShape/><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:footnotePr><w:footnote w:id=\"-1\"/><w:footnote w:id=\"0\"/><w:numFmt w:val=\"decimal\"/><w:numRestart w:val=\"continuous\"/><w:numStart w:val=\"1\"/><w:pos w:val=\"pageBottom\"/></w:footnotePr><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_sDst + L"/word/settings.xml"))
|
||
{
|
||
oSettingsWriter.WriteStringUTF8(sSettings);
|
||
oSettingsWriter.CloseFile();
|
||
}
|
||
|
||
// numbering.xml
|
||
// Маркированный список
|
||
m_oNumberXml += L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><w:numbering 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: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:abstractNum w:abstractNumId=\"0\"><w:multiLevelType w:val=\"hybridMultilevel\"/><w:lvl w:ilvl=\"0\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"";
|
||
m_oNumberXml.AddCharSafe(183);
|
||
m_oNumberXml += L"\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"720\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Symbol\" w:hAnsi=\"Symbol\" w:cs=\"Symbol\" w:eastAsia=\"Symbol\"/></w:rPr></w:lvl><w:lvl w:ilvl=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"o\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"1440\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Courier New\" w:hAnsi=\"Courier New\" w:cs=\"Courier New\" w:eastAsia=\"Courier New\"/></w:rPr></w:lvl><w:lvl w:ilvl=\"2\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"";
|
||
m_oNumberXml.AddCharSafe(167);
|
||
m_oNumberXml += L"\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"2160\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Wingdings\" w:hAnsi=\"Wingdings\" w:cs=\"Wingdings\" w:eastAsia=\"Wingdings\"/></w:rPr></w:lvl><w:lvl w:ilvl=\"3\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"";
|
||
m_oNumberXml.AddCharSafe(183);
|
||
m_oNumberXml += L"\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"2880\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Symbol\" w:hAnsi=\"Symbol\" w:cs=\"Symbol\" w:eastAsia=\"Symbol\"/></w:rPr></w:lvl><w:lvl w:ilvl=\"4\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"o\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"3600\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Courier New\" w:hAnsi=\"Courier New\" w:cs=\"Courier New\" w:eastAsia=\"Courier New\"/></w:rPr></w:lvl><w:lvl w:ilvl=\"5\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"";
|
||
m_oNumberXml.AddCharSafe(167);
|
||
m_oNumberXml += L"\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"4320\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Wingdings\" w:hAnsi=\"Wingdings\" w:cs=\"Wingdings\" w:eastAsia=\"Wingdings\"/></w:rPr></w:lvl><w:lvl w:ilvl=\"6\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"";
|
||
m_oNumberXml.AddCharSafe(183);
|
||
m_oNumberXml += L"\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"5040\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Symbol\" w:hAnsi=\"Symbol\" w:cs=\"Symbol\" w:eastAsia=\"Symbol\"/></w:rPr></w:lvl><w:lvl w:ilvl=\"7\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"o\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"5760\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Courier New\" w:hAnsi=\"Courier New\" w:cs=\"Courier New\" w:eastAsia=\"Courier New\"/></w:rPr></w:lvl><w:lvl w:ilvl=\"8\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"";
|
||
m_oNumberXml.AddCharSafe(167);
|
||
m_oNumberXml += L"\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"6480\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Wingdings\" w:hAnsi=\"Wingdings\" w:cs=\"Wingdings\" w:eastAsia=\"Wingdings\"/></w:rPr></w:lvl></w:abstractNum>";
|
||
|
||
std::wstring wsCurrentLanguage;
|
||
|
||
// core.xml
|
||
std::wstring sCore = 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\">";
|
||
if(oParams)
|
||
{
|
||
if(!oParams->m_sBookTitle.empty())
|
||
{
|
||
sCore += L"<dc:title>";
|
||
sCore += EncodeXmlString(oParams->m_sBookTitle);
|
||
sCore += L"</dc:title>";
|
||
}
|
||
if(!oParams->m_sAuthors.empty())
|
||
{
|
||
sCore += L"<dc:creator>";
|
||
sCore += EncodeXmlString(oParams->m_sAuthors);
|
||
sCore += L"</dc:creator>";
|
||
}
|
||
if(!oParams->m_sGenres.empty())
|
||
{
|
||
sCore += L"<dc:subject>";
|
||
sCore += EncodeXmlString(oParams->m_sGenres);
|
||
sCore += L"</dc:subject>";
|
||
}
|
||
if(!oParams->m_sDate.empty())
|
||
{
|
||
sCore += L"<dcterms:created xsi:type=\"dcterms:W3CDTF\">";
|
||
sCore += EncodeXmlString(oParams->m_sDate);
|
||
sCore += L"</dcterms:created>";
|
||
}
|
||
if(!oParams->m_sDescription.empty())
|
||
{
|
||
sCore += L"<dc:description>";
|
||
sCore += EncodeXmlString(oParams->m_sDescription);
|
||
sCore += L"</dc:description>";
|
||
}
|
||
if (!oParams->m_sLanguage.empty())
|
||
{
|
||
wsCurrentLanguage = IndentifyLanguage(oParams->m_sLanguage);
|
||
|
||
sCore += L"<dc:language>";
|
||
sCore += wsCurrentLanguage;
|
||
sCore += L"</dc:language>";
|
||
}
|
||
}
|
||
sCore += L"<cp:lastModifiedBy/></cp:coreProperties>";
|
||
NSFile::CFileBinary oCoreWriter;
|
||
if (oCoreWriter.CreateFileW(m_sDst + L"/docProps/core.xml"))
|
||
{
|
||
oCoreWriter.WriteStringUTF8(sCore);
|
||
oCoreWriter.CloseFile();
|
||
}
|
||
|
||
// Начала файлов
|
||
m_oDocXmlRels += L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
|
||
m_oDocXmlRels += L"<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>";
|
||
m_oDocXmlRels += L"<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\" Target=\"settings.xml\"/>";
|
||
m_oDocXmlRels += L"<Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings\" Target=\"webSettings.xml\"/>";
|
||
m_oDocXmlRels += L"<Relationship Id=\"rId4\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\" Target=\"fontTable.xml\"/>";
|
||
m_oDocXmlRels += L"<Relationship Id=\"rId5\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme\" Target=\"theme/theme1.xml\"/>";
|
||
m_oDocXmlRels += L"<Relationship Id=\"rId6\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes\" Target=\"footnotes.xml\"/>";
|
||
m_oDocXmlRels += L"<Relationship Id=\"rId7\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering\" Target=\"numbering.xml\"/>";
|
||
m_oNoteXmlRels += L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
|
||
m_oDocXml += 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_oNoteXml += L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><w:footnotes 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:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\" xmlns:wps=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" mc:Ignorable=\"w14 w15 wp14\">";
|
||
m_oNoteXml += L"<w:footnote w:type=\"separator\" w:id=\"-1\"><w:p><w:pPr><w:spacing w:lineRule=\"auto\" w:line=\"240\" w:after=\"0\"/></w:pPr><w:r><w:separator/></w:r></w:p></w:footnote><w:footnote w:type=\"continuationSeparator\" w:id=\"0\"><w:p><w:pPr><w:spacing w:lineRule=\"auto\" w:line=\"240\" w:after=\"0\"/></w:pPr><w:r><w:continuationSeparator/></w:r></w:p></w:footnote>";
|
||
m_oStylesXml += 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_oWebSettings += L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><w:webSettings xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"><w:optimizeForBrowser/>";
|
||
|
||
m_nId += 7;
|
||
|
||
// docDefaults по умолчанию
|
||
if(oParams && !oParams->m_sdocDefaults.empty())
|
||
m_oStylesXml += oParams->m_sdocDefaults;
|
||
else
|
||
{
|
||
m_oStylesXml += L"<w:rPrDefault><w:rPr>";
|
||
m_oStylesXml += 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 += 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 += L"<w:lang w:val=\"" + ((!wsCurrentLanguage.empty()) ? wsCurrentLanguage : DEFAULT_LANGUAGE) + L"\" w:eastAsia=\"en-US\" w:bidi=\"ar-SA\"/>";
|
||
m_oStylesXml += L"</w:rPr></w:rPrDefault><w:pPrDefault/>";
|
||
|
||
// m_oStylesXml += L"<w:pPrDefault><w:pPr><w:spacing w:after=\"200\" w:line=\"276\" w:lineRule=\"auto\"/></w:pPr></w:pPrDefault>";
|
||
}
|
||
|
||
// normal по умолчанию
|
||
if(oParams && !oParams->m_sNormal.empty())
|
||
m_oStylesXml += oParams->m_sNormal;
|
||
else
|
||
{
|
||
m_oStylesXml += 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 += 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 += L"</w:rPr></w:style>";
|
||
}
|
||
|
||
// Маркированный список
|
||
m_oStylesXml += 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 += 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 += L"<w:style w:type=\"table\" w:default=\"1\" w:styleId=\"table-based\"><w:name w:val=\"Normal Table\"/><w:uiPriority w:val=\"99\"/><w:semiHidden/><w:unhideWhenUsed/><w:tblPr><w:tblInd w:w=\"0\" w:type=\"dxa\"/><w:tblCellMar><w:top w:w=\"0\" w:type=\"dxa\"/><w:left w:w=\"108\" w:type=\"dxa\"/><w:bottom w:w=\"0\" w:type=\"dxa\"/><w:right w:w=\"108\" w:type=\"dxa\"/></w:tblCellMar></w:tblPr></w:style><w:style w:type=\"table\" w:styleId=\"table\"><w:name w:val=\"Table Grid\"/><w:basedOn w:val=\"table-based\"/><w:uiPriority w:val=\"59\"/><w:pPr><w:spacing w:lineRule=\"auto\" w:line=\"240\" w:after=\"0\"/></w:pPr><w:tblPr><w:tblBorders><w:top w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"000000\"/><w:left w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"000000\"/><w:bottom w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"000000\"/><w:right w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"000000\"/><w:insideH w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"000000\"/><w:insideV w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"000000\"/></w:tblBorders></w:tblPr></w:style>";
|
||
// Сноски
|
||
m_oStylesXml += 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>";
|
||
// Web стиль по-умолчанию
|
||
m_oStylesXml += 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>";
|
||
}
|
||
|
||
// Читает файл
|
||
void readSrc()
|
||
{
|
||
// Читаем html
|
||
m_oLightReader.ReadNextNode();
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while(m_oLightReader.ReadNextSiblingNode(nDeath))
|
||
{
|
||
std::wstring sName = m_oLightReader.GetName();
|
||
if(sName == L"head")
|
||
readHead();
|
||
else if(sName == L"body")
|
||
readBody();
|
||
}
|
||
}
|
||
|
||
// Дописывает концы docx
|
||
void write()
|
||
{
|
||
m_oDocXmlRels.WriteString(L"</Relationships>");
|
||
NSFile::CFileBinary oRelsWriter;
|
||
if (oRelsWriter.CreateFileW(m_sDst + L"/word/_rels/document.xml.rels"))
|
||
{
|
||
oRelsWriter.WriteStringUTF8(m_oDocXmlRels.GetData());
|
||
oRelsWriter.CloseFile();
|
||
}
|
||
|
||
for (const std::pair<std::wstring, std::wstring>& oFootnote : m_mFootnotes)
|
||
{
|
||
m_oNoteXml.WriteString(L"<w:footnote w:id=\"");
|
||
m_oNoteXml.WriteString(oFootnote.second);
|
||
m_oNoteXml.WriteString(L"\"><w:p><w:pPr><w:pStyle w:val=\"footnote-p\"/></w:pPr><w:r><w:rPr><w:rStyle w:val=\"footnote\"/></w:rPr></w:r><w:r><w:t xml:space=\"preserve\">");
|
||
m_oNoteXml.WriteEncodeXmlString(oFootnote.first);
|
||
m_oNoteXml.WriteString(L"</w:t></w:r></w:p></w:footnote>");
|
||
}
|
||
|
||
m_oNoteXmlRels.WriteString(L"</Relationships>");
|
||
if (oRelsWriter.CreateFileW(m_sDst + L"/word/_rels/footnotes.xml.rels"))
|
||
{
|
||
oRelsWriter.WriteStringUTF8(m_oNoteXmlRels.GetData());
|
||
oRelsWriter.CloseFile();
|
||
}
|
||
|
||
if (m_oState.m_bInP)
|
||
m_oDocXml.WriteString(L"</w:p>");
|
||
|
||
m_oDocXml.WriteString(L"<w:sectPr w:rsidR=\"0007083F\" w:rsidRPr=\"0007083F\" w:rsidSect=\"0007612E\">");
|
||
m_oDocXml.WriteString(L"<w:pgSz w:w=\"" + std::to_wstring(m_oPageData.GetWidth().ToInt(NSCSS::Twips)) + L"\" ");
|
||
m_oDocXml.WriteString(L" w:h=\"" + std::to_wstring(m_oPageData.GetHeight().ToInt(NSCSS::Twips)) + L"\"/>");
|
||
m_oDocXml.WriteString(L"<w:pgMar w:top=\"" + std::to_wstring(m_oPageData.GetMargin().GetTop().ToInt(NSCSS::Twips)) + L"\" ");
|
||
m_oDocXml.WriteString(L"w:right=\"" + std::to_wstring(m_oPageData.GetMargin().GetRight().ToInt(NSCSS::Twips)) + L"\" ");
|
||
m_oDocXml.WriteString(L"w:bottom=\"" + std::to_wstring(m_oPageData.GetMargin().GetBottom().ToInt(NSCSS::Twips)) + L"\" ");
|
||
m_oDocXml.WriteString(L"w:left=\"" + std::to_wstring(m_oPageData.GetMargin().GetLeft().ToInt(NSCSS::Twips)) + L"\" ");
|
||
m_oDocXml.WriteString(L"w:header=\"" + std::to_wstring(m_oPageData.GetHeader().ToInt(NSCSS::Twips)) + L"\" ");
|
||
m_oDocXml.WriteString(L"w:footer=\"" + std::to_wstring(m_oPageData.GetFooter().ToInt(NSCSS::Twips)) + L"\" ");
|
||
m_oDocXml.WriteString(L"w:gutter=\"0\"/><w:cols w:space=\"720\"/><w:docGrid w:linePitch=\"360\"/></w:sectPr></w:body></w:document>");
|
||
|
||
NSFile::CFileBinary oDocumentWriter;
|
||
if (oDocumentWriter.CreateFileW(m_sDst + L"/word/document.xml"))
|
||
{
|
||
oDocumentWriter.WriteStringUTF8(m_oDocXml.GetData());
|
||
oDocumentWriter.CloseFile();
|
||
}
|
||
|
||
m_oNoteXml.WriteString(L"</w:footnotes>");
|
||
NSFile::CFileBinary oFootnotesWriter;
|
||
if (oFootnotesWriter.CreateFileW(m_sDst + L"/word/footnotes.xml"))
|
||
{
|
||
oFootnotesWriter.WriteStringUTF8(m_oNoteXml.GetData());
|
||
oFootnotesWriter.CloseFile();
|
||
}
|
||
|
||
// styles.xml
|
||
m_oStylesXml.WriteString(L"</w:styles>");
|
||
NSFile::CFileBinary oStylesWriter;
|
||
if (oStylesWriter.CreateFileW(m_sDst + L"/word/styles.xml"))
|
||
{
|
||
oStylesWriter.WriteStringUTF8(m_oStylesXml.GetData());
|
||
oStylesWriter.CloseFile();
|
||
}
|
||
|
||
// numbering.xml
|
||
// Маркированный список
|
||
m_oNumberXml.WriteString(L"<w:num w:numId=\"1\"><w:abstractNumId w:val=\"0\"/></w:num>");
|
||
// Нумерованный список
|
||
for(int i = 1; i < m_nNumberingId; i++)
|
||
{
|
||
m_oNumberXml.WriteString(L"<w:num w:numId=\"");
|
||
m_oNumberXml.WriteString(std::to_wstring(i + 1));
|
||
m_oNumberXml.WriteString(L"\"><w:abstractNumId w:val=\"");
|
||
m_oNumberXml.WriteString(std::to_wstring(i));
|
||
m_oNumberXml.WriteString(L"\"/></w:num>");
|
||
}
|
||
m_oNumberXml.WriteString(L"</w:numbering>");
|
||
NSFile::CFileBinary oNumberingWriter;
|
||
if (oNumberingWriter.CreateFileW(m_sDst + L"/word/numbering.xml"))
|
||
{
|
||
oNumberingWriter.WriteStringUTF8(m_oNumberXml.GetData());
|
||
oNumberingWriter.CloseFile();
|
||
}
|
||
|
||
// webSettings.xml
|
||
if (!m_mDivs.empty())
|
||
m_oWebSettings.WriteString(L"</w:divs>");
|
||
|
||
m_oWebSettings.WriteString(L"</w:webSettings>");
|
||
NSFile::CFileBinary oWebSettingsWriter;
|
||
if (oWebSettingsWriter.CreateFileW(m_sDst + L"/word/webSettings.xml"))
|
||
{
|
||
oWebSettingsWriter.WriteStringUTF8(m_oWebSettings.GetData());
|
||
oWebSettingsWriter.CloseFile();
|
||
}
|
||
}
|
||
|
||
// Конвертирует html в xhtml
|
||
bool htmlXhtml(const std::wstring& sSrc)
|
||
{
|
||
BYTE* pData;
|
||
DWORD nLength;
|
||
if (!NSFile::CFileBinary::ReadAllBytes(sSrc, &pData, nLength))
|
||
return false;
|
||
|
||
std::string sFileContent = XmlUtils::GetUtf8FromFileContent(pData, nLength);
|
||
|
||
bool bNeedConvert = true;
|
||
if (nLength > 4)
|
||
{
|
||
if (pData[0] == 0xFF && pData[1] == 0xFE && !(pData[2] == 0x00 && pData[3] == 0x00))
|
||
bNeedConvert = false;
|
||
if (pData[0] == 0xFE && pData[1] == 0xFF)
|
||
bNeedConvert = false;
|
||
|
||
if (pData[0] == 0xFF && pData[1] == 0xFE && pData[2] == 0x00 && pData[3] == 0x00)
|
||
bNeedConvert = false;
|
||
if (pData[0] == 0 && pData[1] == 0 && pData[2] == 0xFE && pData[3] == 0xFF)
|
||
bNeedConvert = false;
|
||
}
|
||
|
||
RELEASEARRAYOBJECTS(pData);
|
||
|
||
size_t nFind = sFileContent.find("version=\"");
|
||
if(nFind != std::string::npos)
|
||
{
|
||
nFind += 9;
|
||
size_t nFindEnd = sFileContent.find("\"", nFind);
|
||
if(nFindEnd != std::string::npos)
|
||
sFileContent.replace(nFind, nFindEnd - nFind, "1.0");
|
||
}
|
||
|
||
const std::wstring sRes{htmlToXhtml(sFileContent, bNeedConvert)};
|
||
|
||
#ifdef SAVE_NORMALIZED_HTML
|
||
#if 1 == SAVE_NORMALIZED_HTML
|
||
NSFile::CFileBinary oWriter;
|
||
if (oWriter.CreateFileW(m_sTmp + L"/res.html"))
|
||
{
|
||
oWriter.WriteStringUTF8(sRes);
|
||
oWriter.CloseFile();
|
||
}
|
||
#endif
|
||
#endif
|
||
|
||
return m_oLightReader.FromString(sRes);
|
||
}
|
||
|
||
// Конвертирует mht в xhtml
|
||
bool mhtXhtml(const std::wstring& sSrc)
|
||
{
|
||
NSFile::CFileBinary file;
|
||
if (!file.OpenFile(sSrc))
|
||
return false;
|
||
|
||
unsigned char* buffer = new unsigned char[4096];
|
||
if (!buffer)
|
||
{
|
||
file.CloseFile();
|
||
return false;
|
||
}
|
||
|
||
DWORD dwReadBytes = 0;
|
||
file.ReadFile(buffer, 4096, dwReadBytes);
|
||
file.CloseFile();
|
||
std::string xml_string = XmlUtils::GetUtf8FromFileContent(buffer, dwReadBytes);
|
||
|
||
const std::string sContentType = NSStringFinder::FindProperty(xml_string, "content-type", ":", ";");
|
||
bool bRes = false;
|
||
|
||
if(NSStringFinder::Equals(sContentType, "multipart/related"))
|
||
{
|
||
BYTE* pData;
|
||
DWORD nLength;
|
||
if (!NSFile::CFileBinary::ReadAllBytes(sSrc, &pData, nLength))
|
||
return false;
|
||
|
||
std::string sFileContent = XmlUtils::GetUtf8FromFileContent(pData, nLength);
|
||
RELEASEARRAYOBJECTS(pData);
|
||
std::wstring sRes = mhtToXhtml(sFileContent);
|
||
/*
|
||
NSFile::CFileBinary oWriter;
|
||
if (oWriter.CreateFileW(m_sTmp + L"/res.html"))
|
||
{
|
||
oWriter.WriteStringUTF8(sRes);
|
||
oWriter.CloseFile();
|
||
}
|
||
*/
|
||
bRes = m_oLightReader.FromString(sRes);
|
||
}
|
||
else
|
||
bRes = htmlXhtml(sSrc);
|
||
|
||
RELEASEARRAYOBJECTS(buffer);
|
||
return bRes;
|
||
}
|
||
|
||
// Читает стили
|
||
void readStyle()
|
||
{
|
||
if(m_oLightReader.IsEmptyNode())
|
||
return;
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while(m_oLightReader.ReadNextSiblingNode(nDeath))
|
||
{
|
||
std::wstring sName = m_oLightReader.GetName();
|
||
|
||
if(sName == L"body")
|
||
readStyle2();
|
||
else
|
||
{
|
||
// Стиль по ссылке
|
||
if(sName == L"link")
|
||
{
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
if(m_oLightReader.GetName() != L"href")
|
||
continue;
|
||
std::wstring sRef = m_oLightReader.GetText();
|
||
if(NSFile::GetFileExtention(sRef) != L"css")
|
||
continue;
|
||
std::wstring sFName = NSFile::GetFileName(sRef);
|
||
// Стиль в сети
|
||
if(sRef.substr(0, 4) == L"http")
|
||
{
|
||
sFName = m_sTmp + L'/' + sFName;
|
||
NSNetwork::NSFileTransport::CFileDownloader oDownloadStyle(sRef, false);
|
||
oDownloadStyle.SetFilePath(sFName);
|
||
if(oDownloadStyle.DownloadSync())
|
||
{
|
||
m_oStylesCalculator.AddStylesFromFile(sFName);
|
||
NSFile::CFileBinary::Remove(sFName);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_oStylesCalculator.AddStylesFromFile(m_sSrc + L'/' + sFName);
|
||
m_oStylesCalculator.AddStylesFromFile(m_sSrc + L'/' + sRef);
|
||
}
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
}
|
||
// тэг style содержит стили для styles.xml
|
||
else if(sName == L"style")
|
||
m_oStylesCalculator.AddStyles(m_oLightReader.GetText2());
|
||
else
|
||
readStyle();
|
||
}
|
||
}
|
||
}
|
||
|
||
void readStyle2()
|
||
{
|
||
std::wstring sName = m_oLightReader.GetName();
|
||
// Стиль по ссылке
|
||
if(sName == L"link")
|
||
{
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
if(m_oLightReader.GetName() != L"href")
|
||
continue;
|
||
std::wstring sRef = m_oLightReader.GetText();
|
||
if(NSFile::GetFileExtention(sRef) != L"css")
|
||
continue;
|
||
std::wstring sFName = NSFile::GetFileName(sRef);
|
||
// Стиль в сети
|
||
if(sRef.substr(0, 4) == L"http")
|
||
{
|
||
sFName = m_sTmp + L'/' + sFName;
|
||
NSNetwork::NSFileTransport::CFileDownloader oDownloadStyle(sRef, false);
|
||
oDownloadStyle.SetFilePath(sFName);
|
||
if(oDownloadStyle.DownloadSync())
|
||
{
|
||
m_oStylesCalculator.AddStylesFromFile(sFName);
|
||
NSFile::CFileBinary::Remove(sFName);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_oStylesCalculator.AddStylesFromFile(m_sSrc + L'/' + sFName);
|
||
m_oStylesCalculator.AddStylesFromFile(m_sSrc + L'/' + sRef);
|
||
}
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
}
|
||
// тэг style содержит стили для styles.xml
|
||
else if(sName == L"style")
|
||
m_oStylesCalculator.AddStyles(m_oLightReader.GetText2());
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while(m_oLightReader.ReadNextSiblingNode(nDeath))
|
||
{
|
||
if(!m_oLightReader.IsEmptyNode())
|
||
readStyle2();
|
||
}
|
||
}
|
||
|
||
void PageBreakBefore()
|
||
{
|
||
if (!m_oState.m_bInP)
|
||
m_oDocXml.WriteString(L"<w:p>");
|
||
|
||
m_oDocXml.WriteString(L"<w:pPr><w:pageBreakBefore/></w:pPr>");
|
||
|
||
if (!m_oState.m_bInP)
|
||
m_oDocXml.WriteString(L"</w:p>");
|
||
}
|
||
|
||
private:
|
||
bool NodeBelongToTable(const std::wstring& wsNodeName) const
|
||
{
|
||
return L"table" == wsNodeName || L"tbody" == wsNodeName || L"th" == wsNodeName || L"td" == wsNodeName ||
|
||
L"tr" == wsNodeName || L"thead" == wsNodeName || L"tfoot" == wsNodeName;
|
||
}
|
||
|
||
std::wstring GetArgumentValue(const std::wstring& wsArgumentName, const std::wstring& wsDefaultValue = L"")
|
||
{
|
||
if (!m_oLightReader.MoveToFirstAttribute())
|
||
return wsDefaultValue;
|
||
|
||
std::wstring wsValue{wsDefaultValue};
|
||
|
||
do
|
||
{
|
||
if (wsArgumentName == m_oLightReader.GetName())
|
||
{
|
||
wsValue = m_oLightReader.GetText();
|
||
break;
|
||
}
|
||
} while (m_oLightReader.MoveToNextAttribute());
|
||
|
||
m_oLightReader.MoveToElement();
|
||
return wsValue;
|
||
}
|
||
|
||
// Так как CSS калькулятор не знает для какой ноды производится расчет стиля
|
||
// и не знает, что некоторые стили предназначены только определенной ноде,
|
||
// то проще пока обрабатывать это заранее
|
||
// ! Используется для стилей, заданных через аргументы !
|
||
bool CheckArgumentMath(const std::wstring& wsNodeName, const std::wstring& wsStyleName) const
|
||
{
|
||
if (L"border" == wsStyleName && L"table" != wsNodeName)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool OpenP(NSStringUtils::CStringBuilder* pXml)
|
||
{
|
||
if (m_oState.m_bInP)
|
||
return false;
|
||
|
||
pXml->WriteString(L"<w:p>");
|
||
m_oState.m_bInP = true;
|
||
m_oState.m_bWasPStyle = false;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool OpenR(NSStringUtils::CStringBuilder* pXml)
|
||
{
|
||
if (m_oState.m_bInR)
|
||
return false;
|
||
|
||
pXml->WriteString(L"<w:r>");
|
||
m_oState.m_bInR = true;
|
||
return true;
|
||
}
|
||
|
||
void CloseR(NSStringUtils::CStringBuilder* pXml)
|
||
{
|
||
if (!m_oState.m_bInR)
|
||
return;
|
||
|
||
pXml->WriteString(L"</w:r>");
|
||
m_oState.m_bInR = false;
|
||
}
|
||
|
||
bool OpenT(NSStringUtils::CStringBuilder* pXml)
|
||
{
|
||
if (m_oState.m_bInT)
|
||
return false;
|
||
|
||
pXml->WriteString(L"<w:t xml:space=\"preserve\">");
|
||
m_oState.m_bInT = true;
|
||
return true;
|
||
}
|
||
|
||
void CloseT(NSStringUtils::CStringBuilder* pXml)
|
||
{
|
||
if (!m_oState.m_bInT)
|
||
return;
|
||
|
||
pXml->WriteString(L"</w:t>");
|
||
m_oState.m_bInT = false;
|
||
}
|
||
|
||
void CloseP(NSStringUtils::CStringBuilder* pXml, const std::vector<NSCSS::CNode>& arSelectors)
|
||
{
|
||
m_oState.m_bWasSpace = true;
|
||
|
||
if (!m_oState.m_bInP)
|
||
return;
|
||
|
||
CloseT(pXml);
|
||
CloseR(pXml);
|
||
|
||
if (m_oState.m_bInHyperlink)
|
||
{
|
||
if (arSelectors.rend() != std::find_if(arSelectors.rbegin(), arSelectors.rend(), [](const NSCSS::CNode& oNode) { return L"a" == oNode.m_wsName; }))
|
||
{
|
||
pXml->WriteString(L"</w:hyperlink>");
|
||
m_oState.m_bInHyperlink = false;
|
||
}
|
||
}
|
||
|
||
pXml->WriteString(L"</w:p>");
|
||
m_oState.m_bInP = false;
|
||
}
|
||
|
||
void WriteSpace(NSStringUtils::CStringBuilder* pXml)
|
||
{
|
||
if (NULL == pXml)
|
||
return;
|
||
|
||
OpenR(pXml);
|
||
pXml->WriteString(L"<w:rPr><w:rFonts w:eastAsia=\"Times New Roman\"/></w:rPr><w:t xml:space=\"preserve\"> </w:t>");
|
||
CloseR(pXml);
|
||
m_oState.m_bWasSpace = true;
|
||
}
|
||
|
||
void WriteBookmark(NSStringUtils::CStringBuilder* pXml, const std::wstring& wsId)
|
||
{
|
||
if (NULL == pXml)
|
||
return;
|
||
|
||
const std::wstring sCrossId = std::to_wstring(m_mBookmarks.size() + 1);
|
||
std::wstring sName;
|
||
|
||
if (m_mBookmarks.end() != m_mBookmarks.find(wsId))
|
||
sName = wsId + L"_" + std::to_wstring(++m_mBookmarks[wsId]);
|
||
else
|
||
{
|
||
sName = wsId;
|
||
m_mBookmarks.insert({wsId, 1});
|
||
}
|
||
|
||
pXml->WriteString(L"<w:bookmarkStart w:id=\"");
|
||
pXml->WriteString(sCrossId);
|
||
pXml->WriteString(L"\" w:name=\"");
|
||
pXml->WriteEncodeXmlString(sName);
|
||
pXml->WriteString(L"\"/><w:bookmarkEnd w:id=\"");
|
||
pXml->WriteString(sCrossId);
|
||
pXml->WriteString(L"\"/>");
|
||
}
|
||
|
||
std::wstring WriteDiv(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml || sSelectors.empty())
|
||
return std::wstring();
|
||
|
||
const std::wstring wsKeyWord{sSelectors.back().m_wsName};
|
||
|
||
std::map<std::wstring, UINT>::const_iterator itFound = m_mDivs.find(wsKeyWord);
|
||
|
||
if (m_mDivs.end() != itFound)
|
||
return std::to_wstring(itFound->second);
|
||
|
||
const std::wstring wsId{std::to_wstring(m_mDivs.size() + 1)};
|
||
|
||
if (m_mDivs.empty())
|
||
pXml->WriteString(L"<w:divs>");
|
||
|
||
NSCSS::CCompiledStyle *pStyle = sSelectors.back().m_pCompiledStyle;
|
||
|
||
const bool bInTable = ElementInTable(sSelectors);
|
||
|
||
INT nMarLeft = (!bInTable) ? 720 : 0;
|
||
INT nMarRight = (!bInTable) ? 720 : 0;
|
||
INT nMarTop = (!bInTable) ? 100 : 0;
|
||
INT nMarBottom = (!bInTable) ? 100 : 0;
|
||
|
||
if (!pStyle->m_oMargin.GetLeft().Empty() && !pStyle->m_oMargin.GetLeft().Zero())
|
||
nMarLeft = pStyle->m_oMargin.GetLeft().ToInt(NSCSS::Twips, m_oPageData.GetWidth().ToInt(NSCSS::Twips));
|
||
|
||
if (!pStyle->m_oMargin.GetRight().Empty() && !pStyle->m_oMargin.GetRight().Zero())
|
||
nMarRight = pStyle->m_oMargin.GetRight().ToInt(NSCSS::Twips, m_oPageData.GetWidth().ToInt(NSCSS::Twips));
|
||
|
||
if (!pStyle->m_oMargin.GetTop().Empty() && !pStyle->m_oMargin.GetTop().Zero())
|
||
nMarTop = pStyle->m_oMargin.GetTop().ToInt(NSCSS::Twips, m_oPageData.GetHeight().ToInt(NSCSS::Twips));
|
||
|
||
if (!pStyle->m_oMargin.GetBottom().Empty() && !pStyle->m_oMargin.GetBottom().Zero())
|
||
nMarBottom = pStyle->m_oMargin.GetBottom().ToInt(NSCSS::Twips, m_oPageData.GetHeight().ToInt(NSCSS::Twips));
|
||
|
||
if (L"blockquote" == wsKeyWord)
|
||
{
|
||
sSelectors.back().m_mAttributes.insert({L"margin", L"0px"});
|
||
|
||
pXml->WriteString(L"<w:div w:id=\"" + wsId + L"\">");
|
||
pXml->WriteString(L"<w:blockQuote w:val=\"1\"/>");
|
||
pXml->WriteString(L"<w:marLeft w:val=\"" + std::to_wstring(nMarLeft) + L"\"/>");
|
||
pXml->WriteString(L"<w:marRight w:val=\"" + std::to_wstring(nMarRight) + L"\"/>");
|
||
pXml->WriteString(L"<w:marTop w:val=\"" + std::to_wstring(nMarTop) + L"\"/>");
|
||
pXml->WriteString(L"<w:marBottom w:val=\"" + std::to_wstring(nMarBottom) + L"\"/>");
|
||
pXml->WriteString(L"<w:divBdr>");
|
||
pXml->WriteString(L"<w:top w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\"/>");
|
||
pXml->WriteString(L"<w:left w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\"/>");
|
||
pXml->WriteString(L"<w:bottom w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\"/>");
|
||
pXml->WriteString(L"<w:right w:val=\"none\" w:sz=\"0\" w:space=\"0\" w:color=\"auto\"/>");
|
||
pXml->WriteString(L"</w:divBdr>");
|
||
pXml->WriteString(L"</w:div>");
|
||
}
|
||
|
||
m_mDivs.insert(std::make_pair(wsKeyWord, m_mDivs.size() + 1));
|
||
|
||
return wsId;
|
||
}
|
||
|
||
std::wstring GetSubClass(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors)
|
||
{
|
||
NSCSS::CNode oNode;
|
||
std::wstring sNote;
|
||
oNode.m_wsName = m_oLightReader.GetName();
|
||
// Стиль по атрибуту
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
std::wstring sName = m_oLightReader.GetName();
|
||
if(sName == L"class")
|
||
oNode.m_wsClass = EncodeXmlString(m_oLightReader.GetText());
|
||
else if(sName == L"id")
|
||
{
|
||
oNode.m_wsId = EncodeXmlString(m_oLightReader.GetText());
|
||
WriteBookmark(oXml, oNode.m_wsId);
|
||
|
||
if (!m_oStylesCalculator.HaveStylesById(oNode.m_wsId))
|
||
oNode.m_wsId.clear();
|
||
}
|
||
else if(sName == L"style")
|
||
oNode.m_wsStyle += m_oLightReader.GetText();
|
||
else if(sName == L"title")
|
||
sNote = m_oLightReader.GetText();
|
||
else
|
||
{
|
||
if (CheckArgumentMath(oNode.m_wsName, sName))
|
||
oNode.m_mAttributes[sName] = m_oLightReader.GetText();
|
||
}
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
sSelectors.push_back(oNode);
|
||
|
||
m_oStylesCalculator.CalculateCompiledStyle(sSelectors);
|
||
return sNote;
|
||
}
|
||
|
||
std::wstring GetStyle(const NSCSS::CCompiledStyle& oStyle, bool bP)
|
||
{
|
||
// NSCSS::CCompiledStyle oStyle = m_oStylesCalculator.GetCompiledStyle(sSelectors);
|
||
if ((bP && !m_oXmlStyle.WritePStyle(oStyle)) || (!bP && !m_oXmlStyle.WriteRStyle(oStyle)))
|
||
return L"";
|
||
|
||
m_oStylesXml.WriteString(m_oXmlStyle.GetStyle());
|
||
return m_oXmlStyle.GetIdAndClear();
|
||
}
|
||
|
||
void readHead()
|
||
{
|
||
if(m_oLightReader.IsEmptyNode())
|
||
return;
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while (m_oLightReader.ReadNextSiblingNode(nDeath))
|
||
{
|
||
const std::wstring wsName = m_oLightReader.GetName();
|
||
// Базовый адрес
|
||
if (L"base" == wsName)
|
||
m_sBase = GetArgumentValue(L"href");
|
||
}
|
||
|
||
m_oLightReader.MoveToElement();
|
||
}
|
||
|
||
void readBody()
|
||
{
|
||
std::vector<NSCSS::CNode> sSelectors;
|
||
|
||
sSelectors.push_back(NSCSS::CNode(L"html", L"", L""));
|
||
|
||
GetSubClass(&m_oDocXml, sSelectors);
|
||
/*
|
||
std::wstring sCrossId = std::to_wstring(m_nCrossId++);
|
||
m_oDocXml.WriteString(L"<w:bookmarkStart w:id=\"");
|
||
m_oDocXml.WriteString(sCrossId);
|
||
m_oDocXml.WriteString(L"\" w:name=\"");
|
||
m_oDocXml.WriteString(sFileName);
|
||
m_oDocXml.WriteString(L"\"/><w:bookmarkEnd w:id=\"");
|
||
m_oDocXml.WriteString(sCrossId);
|
||
m_oDocXml.WriteString(L"\"/>");
|
||
*/
|
||
|
||
if (!sSelectors.back().m_mAttributes.empty())
|
||
{
|
||
std::map<std::wstring, std::wstring>::iterator itFound = sSelectors.back().m_mAttributes.find(L"bgcolor");
|
||
|
||
if (sSelectors.back().m_mAttributes.end() != itFound)
|
||
{
|
||
NSCSS::NSProperties::CColor oColor;
|
||
oColor.SetValue(itFound->second);
|
||
|
||
if (!oColor.Empty() && !oColor.None())
|
||
{
|
||
const std::wstring wsHEXColor{oColor.ToHEX()};
|
||
|
||
if (!wsHEXColor.empty())
|
||
m_oDocXml.WriteString(L"<w:background w:color=\"" + wsHEXColor + L"\"/>");
|
||
|
||
sSelectors.back().m_mAttributes.erase(itFound);
|
||
}
|
||
}
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
|
||
CTextSettings oTS;
|
||
readStream(&m_oDocXml, sSelectors, oTS);
|
||
}
|
||
|
||
bool ReadText(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
std::wstring sText = m_oLightReader.GetText();
|
||
|
||
if (sText.empty())
|
||
return false;
|
||
|
||
bool bPre = oTS.bPre;
|
||
|
||
if (!bPre && nullptr != arSelectors.back().m_pCompiledStyle)
|
||
{
|
||
NSCSS::CCompiledStyle* pCompiledStyle{arSelectors.back().m_pCompiledStyle};
|
||
|
||
// TODO::поведение должно быть немного разное (реализовать)
|
||
switch(pCompiledStyle->m_oDisplay.GetWhiteSpace().ToInt())
|
||
{
|
||
case NSCSS::NSProperties::EWhiteSpace::Pre:
|
||
case NSCSS::NSProperties::EWhiteSpace::Pre_Wrap:
|
||
case NSCSS::NSProperties::EWhiteSpace::Pre_Line:
|
||
bPre = true;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!bPre && sText.end() == std::find_if_not(sText.begin(), sText.end(), [](wchar_t wchChar){ return iswspace(wchChar) && 0xa0 != wchChar;}))
|
||
return false;
|
||
|
||
if(oTS.bBdo)
|
||
std::reverse(sText.begin(), sText.end());
|
||
|
||
const bool bInT = m_oState.m_bInT;
|
||
|
||
GetSubClass(pXml, arSelectors);
|
||
|
||
//TODO:: сделать так, чтобы параграф (со своими стилями) открывался при чтении сооответствующей ноды, а не при чтении текста
|
||
OpenP(pXml);
|
||
|
||
NSStringUtils::CStringBuilder oPPr;
|
||
|
||
const std::wstring sPStyle = wrP(&oPPr, arSelectors, oTS);
|
||
|
||
WriteToStringBuilder(oPPr, *pXml);
|
||
|
||
NSStringUtils::CStringBuilder oRPr;
|
||
std::wstring sRStyle;
|
||
|
||
if (OpenR(pXml))
|
||
{
|
||
sRStyle = wrRPr(&oRPr, arSelectors, oTS);
|
||
|
||
WriteToStringBuilder(oRPr, *pXml);
|
||
|
||
if (oTS.bQ)
|
||
pXml->WriteString(L"<w:t xml:space=\"preserve\">"</w:t>");
|
||
}
|
||
|
||
if (oTS.bQ)
|
||
pXml->WriteString(L"<w:t xml:space=\"preserve\">"</w:t>");
|
||
|
||
if (!bPre && oTS.bAddSpaces && m_oState.m_bInP && !m_oState.m_bInR && !iswspace(sText.front()) && !iswpunct(sText.front()) && !m_oState.m_bWasSpace && CTextSettings::Normal == oTS.eTextMode)
|
||
WriteSpace(pXml);
|
||
|
||
if(bPre)
|
||
{
|
||
size_t unBegin = 0, unEnd = sText.find_first_of(L"\n\r\t");
|
||
|
||
while (std::wstring::npos != unBegin)
|
||
{
|
||
if (OpenR(pXml))
|
||
{
|
||
pXml->WriteString(L"<w:test/>");
|
||
WriteToStringBuilder(oRPr, *pXml);
|
||
}
|
||
|
||
OpenT(pXml);
|
||
if (unEnd == std::wstring::npos)
|
||
{
|
||
pXml->WriteEncodeXmlString(sText.c_str() + unBegin, sText.length() - unBegin);
|
||
break;
|
||
}
|
||
|
||
if (unBegin != unEnd)
|
||
{
|
||
pXml->WriteEncodeXmlString(sText.c_str() + unBegin, unEnd - unBegin);
|
||
CloseT(pXml);
|
||
}
|
||
|
||
if (L'\n' == sText[unEnd])
|
||
{
|
||
pXml->WriteString(L"<w:br/>");
|
||
}
|
||
else if (L'\t' == sText[unEnd])
|
||
{
|
||
pXml->WriteString(L"<w:tab/>");
|
||
}
|
||
|
||
unBegin = unEnd + 1;
|
||
unEnd = sText.find_first_of(L"\n\r\t", unBegin);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ReplaceSpaces(sText);
|
||
|
||
if (!sText.empty() && L'\t' == sText[0])
|
||
{
|
||
pXml->WriteString(L"<w:tab/>");
|
||
sText.erase(0, 1);
|
||
}
|
||
|
||
if (!sText.empty() && std::iswspace(sText.front()) && m_oState.m_bWasSpace)
|
||
sText.erase(0, 1);
|
||
|
||
OpenT(pXml);
|
||
|
||
if (oTS.bMergeText && !m_oState.m_bWasSpace && bInT && !bPre)
|
||
pXml->WriteEncodeXmlString(L" ");
|
||
|
||
if (!sText.empty())
|
||
{
|
||
m_oState.m_bWasSpace = std::iswspace(sText.back());
|
||
pXml->WriteEncodeXmlString(sText);
|
||
}
|
||
}
|
||
|
||
if (oTS.bQ)
|
||
pXml->WriteString(L"<w:t xml:space=\"preserve\">"</w:t>");
|
||
|
||
CloseT(pXml);
|
||
|
||
if (!oTS.bMergeText)
|
||
CloseR(pXml);
|
||
|
||
arSelectors.pop_back();
|
||
return true;
|
||
}
|
||
|
||
bool ReadAbbr(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS, std::wstring& wsNote)
|
||
{
|
||
if (NULL == pXml || wsNote.empty())
|
||
return false;
|
||
|
||
wrP(pXml, arSelectors, oTS);
|
||
const std::wstring wsName{L"Bookmark" + std::to_wstring(m_mBookmarks.size() + 1)};
|
||
m_mBookmarks.insert(std::make_pair(wsName, m_mBookmarks.size() + 1));
|
||
pXml->WriteString(L"<w:r><w:fldChar w:fldCharType=\"begin\"/></w:r><w:r><w:instrText>HYPERLINK \\l \"" + wsName + L"\" \\o \"");
|
||
pXml->WriteEncodeXmlString(wsNote);
|
||
pXml->WriteString(L"\"</w:instrText></w:r>");
|
||
pXml->WriteString(L"<w:r><w:fldChar w:fldCharType=\"separate\"/></w:r>");
|
||
const bool bResult = readStream(pXml, arSelectors, oTS);
|
||
pXml->WriteString(L"<w:r><w:fldChar w:fldCharType=\"end\"/></w:r>");
|
||
wsNote.clear();
|
||
|
||
return bResult;
|
||
}
|
||
|
||
bool ReadBold(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.oAdditionalStyle.m_oFont.SetWeight(L"bold", UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadBdo(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
const std::wstring sDir{GetArgumentValue(L"dir")};
|
||
|
||
CTextSettings oTSBdo(oTS);
|
||
oTSBdo.bBdo = (sDir == L"rtl");
|
||
|
||
return readStream(pXml, arSelectors, oTSBdo);
|
||
}
|
||
|
||
bool ReadBdi(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSBdo(oTS);
|
||
oTSBdo.bBdo = false;
|
||
return readStream(pXml, arSelectors, oTSBdo);
|
||
}
|
||
|
||
bool ReadBr(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
if (m_oState.m_bInP)
|
||
{
|
||
OpenR(pXml);
|
||
if(arSelectors.back().m_pCompiledStyle->m_oText.GetAlign() == L"both")
|
||
pXml->WriteString(L"<w:tab/>");
|
||
pXml->WriteString(L"<w:br/>");
|
||
CloseR(pXml);
|
||
}
|
||
else
|
||
WriteEmptyParagraph(pXml, false, m_oState.m_bInP);
|
||
|
||
m_oState.m_bWasSpace = true;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool ReadCenter(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSP(oTS);
|
||
oTSP.oAdditionalStyle.m_oText.SetAlign(L"center", UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSP);
|
||
}
|
||
|
||
bool ReadItalic(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.oAdditionalStyle.m_oFont.SetStyle(L"italic", UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadCode(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml || arSelectors.empty())
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.oAdditionalStyle.m_oFont.SetFamily(L"Courier New", UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadKbd(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.oAdditionalStyle.m_oFont.SetFamily(L"Courier New", UINT_MAX, true);
|
||
oTSR.oAdditionalStyle.m_oFont.SetSize(20, NSCSS::UnitMeasure::Point, UINT_MAX, true);
|
||
oTSR.oAdditionalStyle.m_oFont.SetWeight(L"bold", UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadSamp(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.oAdditionalStyle.m_oFont.SetFamily(L"Courier New", UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadStrike(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.oAdditionalStyle.m_oText.SetDecoration(L"line-through", UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadFont(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
std::wstring sAName = m_oLightReader.GetName();
|
||
if(sAName == L"color")
|
||
oTSR.oAdditionalStyle.m_oText.SetColor(m_oLightReader.GetText(), UINT_MAX, true);
|
||
else if(sAName == L"face")
|
||
oTSR.oAdditionalStyle.m_oFont.SetFamily(m_oLightReader.GetText(), UINT_MAX, true);
|
||
else if(sAName == L"size")
|
||
{
|
||
int nSize = 3;
|
||
const std::wstring sSize = m_oLightReader.GetText();
|
||
if(!sSize.empty())
|
||
{
|
||
if(sSize.front() == L'+')
|
||
nSize += NSStringFinder::ToInt(sSize.substr(1));
|
||
else if(sSize.front() == L'-')
|
||
nSize -= NSStringFinder::ToInt(sSize.substr(1));
|
||
else
|
||
nSize = NSStringFinder::ToInt(sSize);
|
||
}
|
||
|
||
if (nSize < 1 || nSize > 7)
|
||
nSize = 3;
|
||
|
||
oTSR.oAdditionalStyle.m_oFont.SetSize(HTML_FONTS[nSize - 1], NSCSS::UnitMeasure::Point, UINT_MAX, true);
|
||
}
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
const bool bResult = readStream(pXml, arSelectors, oTSR);
|
||
m_oState.m_bWasSpace = true;
|
||
|
||
return bResult;
|
||
}
|
||
|
||
bool ReadUnderline(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.oAdditionalStyle.m_oText.SetDecoration(L"underline", UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadMark(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.oAdditionalStyle.m_oText.SetHighlight(L"yellow", UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadQ(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSQ(oTS);
|
||
oTSQ.bQ = true;
|
||
|
||
return readStream(pXml, arSelectors, oTSQ);
|
||
}
|
||
|
||
bool ReadSup(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.eTextMode = CTextSettings::Superscript;
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadSub(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.eTextMode = CTextSettings::Subscript;
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadSpan(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml || arSelectors.empty() || arSelectors.back().m_wsClass == L"MsoFootnoteReference")
|
||
return false;
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.bAddSpaces = false;
|
||
|
||
return readStream(pXml, arSelectors, oTSR);
|
||
}
|
||
|
||
bool ReadNobr(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSPre(oTS);
|
||
oTSPre.bPre = true;
|
||
|
||
return readStream(pXml, arSelectors, oTSPre);
|
||
}
|
||
|
||
bool ReadBasefont(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml || !m_oLightReader.MoveToFirstAttribute())
|
||
return false;
|
||
|
||
do
|
||
{
|
||
if (L"face" == m_oLightReader.GetName())
|
||
oTS.oAdditionalStyle.m_oFont.SetFamily(m_oLightReader.GetText(), UINT_MAX, true);
|
||
else if (L"size" == m_oLightReader.GetName())
|
||
{
|
||
switch(NSStringFinder::ToInt(m_oLightReader.GetText(), 3))
|
||
{
|
||
case 1: oTS.oAdditionalStyle.m_oFont.SetSize(7.5, NSCSS::UnitMeasure::Point, UINT_MAX, true); break;
|
||
case 2: oTS.oAdditionalStyle.m_oFont.SetSize(10, NSCSS::UnitMeasure::Point, UINT_MAX, true); break;
|
||
default:
|
||
case 3: oTS.oAdditionalStyle.m_oFont.SetSize(12, NSCSS::UnitMeasure::Point, UINT_MAX, true); break;
|
||
case 4: oTS.oAdditionalStyle.m_oFont.SetSize(13.5, NSCSS::UnitMeasure::Point, UINT_MAX, true); break;
|
||
case 5: oTS.oAdditionalStyle.m_oFont.SetSize(18, NSCSS::UnitMeasure::Point, UINT_MAX, true); break;
|
||
case 6: oTS.oAdditionalStyle.m_oFont.SetSize(24, NSCSS::UnitMeasure::Point, UINT_MAX, true); break;
|
||
case 7: oTS.oAdditionalStyle.m_oFont.SetSize(36, NSCSS::UnitMeasure::Point, UINT_MAX, true); break;
|
||
}
|
||
}
|
||
else if (L"color" == m_oLightReader.GetName())
|
||
oTS.oAdditionalStyle.m_oText.SetColor(m_oLightReader.GetText(), UINT_MAX, true);
|
||
} while (m_oLightReader.MoveToNextAttribute());
|
||
|
||
m_oLightReader.MoveToElement();
|
||
|
||
oTS.oAdditionalStyle.SetID(m_oStylesCalculator.CalculateStyleId(arSelectors.back()));
|
||
|
||
return true;
|
||
}
|
||
|
||
bool ReadDD(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSP(oTS);
|
||
oTSP.oAdditionalStyle.m_oMargin.SetLeft(720, NSCSS::UnitMeasure::Twips, UINT_MAX, true);
|
||
|
||
return readStream(pXml, arSelectors, oTSP);
|
||
}
|
||
|
||
bool ReadDiv(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
if (!m_oState.m_bBanUpdatePageData)
|
||
m_oStylesCalculator.CalculatePageStyle(m_oPageData, arSelectors);
|
||
|
||
int bMsoFootnote = 0;
|
||
std::wstring sFootnoteID;
|
||
while (m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
std::wstring sAName = m_oLightReader.GetName();
|
||
std::wstring sAText = m_oLightReader.GetText();
|
||
if (sAName == L"epub:type" && sAText == L"footnote")
|
||
bMsoFootnote++;
|
||
else if (sAName == L"style" && sAText == L"mso-element:footnote")
|
||
bMsoFootnote++;
|
||
else if (sAName == L"id")
|
||
{
|
||
std::map<std::wstring, std::wstring>::iterator it = m_mFootnotes.find(sAText);
|
||
if (it != m_mFootnotes.end())
|
||
{
|
||
bMsoFootnote++;
|
||
sFootnoteID = it->second;
|
||
}
|
||
}
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
if (bMsoFootnote >= 2)
|
||
{
|
||
m_oNoteXml.WriteString(L"<w:footnote w:id=\"");
|
||
m_oNoteXml.WriteString(sFootnoteID);
|
||
m_oNoteXml.WriteString(L"\">");
|
||
readStream(&m_oNoteXml, arSelectors, oTS);
|
||
m_oNoteXml.WriteString(L"</w:footnote>");
|
||
}
|
||
else
|
||
return readStream(pXml, arSelectors, oTS);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool ReadBlockquote(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oNewTS{oTS};
|
||
oNewTS.sPStyle += L"<w:divId w:val=\"" + WriteDiv(&m_oWebSettings, arSelectors, oNewTS) + L"\"/>";
|
||
|
||
return readStream(pXml, arSelectors, oNewTS);
|
||
}
|
||
|
||
bool ReadHr(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
for (const NSCSS::CNode& item : arSelectors)
|
||
{
|
||
if (item.m_wsName == L"div" && item.m_wsStyle == L"mso-element:footnote-list")
|
||
return false;
|
||
}
|
||
|
||
NSCSS::NSProperties::CDigit oSize, oWidth;
|
||
NSCSS::NSProperties::CColor oColor;
|
||
bool bShade = true;
|
||
std::wstring wsAlign{L"center"};
|
||
|
||
if (m_oLightReader.MoveToFirstAttribute())
|
||
{
|
||
std::wstring wsAttributeName;
|
||
do
|
||
{
|
||
wsAttributeName = m_oLightReader.GetName();
|
||
|
||
if (L"align" == wsAttributeName)
|
||
{
|
||
const std::wstring wsValue{m_oLightReader.GetText()};
|
||
|
||
if (NSStringFinder::Equals(L"left", wsValue))
|
||
wsAlign = L"left";
|
||
else if (NSStringFinder::Equals(L"right", wsValue))
|
||
wsAlign = L"right";
|
||
else if (NSStringFinder::Equals(L"center", wsValue))
|
||
wsAlign = L"center";
|
||
}
|
||
if (L"color" == wsAttributeName)
|
||
oColor.SetValue(m_oLightReader.GetText());
|
||
else if (L"noshade" == wsAttributeName)
|
||
bShade = false;
|
||
else if (L"size" == wsAttributeName)
|
||
oSize.SetValue(m_oLightReader.GetText());
|
||
else if (L"width" == wsAttributeName)
|
||
oWidth.SetValue(m_oLightReader.GetText());
|
||
} while (m_oLightReader.MoveToNextAttribute());
|
||
|
||
m_oLightReader.MoveToElement();
|
||
}
|
||
|
||
OpenP(pXml);
|
||
|
||
pXml->WriteString(L"<w:pPr><w:jc w:val=\"" + wsAlign + L"\"/></w:pPr>");
|
||
|
||
OpenR(pXml);
|
||
|
||
const unsigned int unPageWidth{static_cast<unsigned int>((m_oPageData.GetWidth().ToDouble(NSCSS::Inch) - m_oPageData.GetMargin().GetLeft().ToDouble(NSCSS::Inch) - m_oPageData.GetMargin().GetRight().ToDouble(NSCSS::Inch)) * 914400.)};
|
||
|
||
std::wstring wsWidth;
|
||
|
||
// width измеряется в px или %
|
||
if (!oWidth.Empty())
|
||
wsWidth = std::to_wstring(static_cast<int>((NSCSS::UnitMeasure::Percent != oWidth.GetUnitMeasure()) ? (NSCSS::CUnitMeasureConverter::ConvertPx(oWidth.ToDouble(), NSCSS::Inch, 96) * 914400.) : oWidth.ToDouble(NSCSS::Inch, unPageWidth)));
|
||
else
|
||
wsWidth = std::to_wstring(unPageWidth);
|
||
|
||
std::wstring wsHeight{L"14288"};
|
||
|
||
// size измеряется только в px
|
||
if (!oSize.Empty())
|
||
wsHeight = std::to_wstring(static_cast<int>(NSCSS::CUnitMeasureConverter::ConvertPx(oSize.ToDouble(), NSCSS::Inch, 96) * 914400.));
|
||
|
||
pXml->WriteString(L"<w:rPr><w:noProof/></w:rPr>");
|
||
pXml->WriteString(L"<mc:AlternateContent><mc:Choice Requires=\"wps\"><w:drawing><wp:inline distT=\"0\" distB=\"0\" distL=\"0\" distR=\"0\">");
|
||
pXml->WriteString(L"<wp:extent cx=\"" + wsWidth + L"\" cy=\"0\"/>");
|
||
pXml->WriteString(L"<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>");
|
||
pXml->WriteString(L"<wp:docPr id=\"" + std::to_wstring(m_nShapeId) + L"\" name=\"Line " + std::to_wstring(m_nShapeId) + L"\"/>"
|
||
"<wp:cNvGraphicFramePr/>"
|
||
"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
|
||
"<a:graphicData uri=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\">"
|
||
"<wps:wsp>"
|
||
"<wps:cNvSpPr/>"
|
||
"<wps:spPr>");
|
||
pXml->WriteString(L"<a:xfrm>"
|
||
"<a:off x=\"0\" y=\"0\"/>"
|
||
"<a:ext cx=\"" + wsWidth + L"\" cy=\"0\"/>"
|
||
"</a:xfrm>"
|
||
"<a:custGeom><a:pathLst><a:path>"
|
||
"<a:moveTo><a:pt x=\"0\" y=\"0\"/></a:moveTo>"
|
||
"<a:lnTo><a:pt x=\"" + wsWidth + L"\" y=\"0\"/></a:lnTo>"
|
||
"</a:path></a:pathLst></a:custGeom>"
|
||
"<a:ln w=\"" + wsHeight + L"\"><a:solidFill><a:srgbClr val=\"" + ((!oColor.Empty()) ? oColor.ToHEX() : L"808080") + L"\"/></a:solidFill></a:ln>");
|
||
|
||
if (bShade)
|
||
pXml->WriteString(L"<a:scene3d><a:camera prst=\"orthographicFront\"/><a:lightRig rig=\"threePt\" dir=\"t\"/></a:scene3d><a:sp3d><a:bevelT prst=\"angle\"/></a:sp3d>");
|
||
|
||
pXml->WriteString(L"</wps:spPr><wps:bodyPr/></wps:wsp></a:graphicData></a:graphic></wp:inline></w:drawing></mc:Choice></mc:AlternateContent>");
|
||
|
||
CloseP(pXml, arSelectors);
|
||
|
||
++m_nShapeId;
|
||
return true;
|
||
}
|
||
|
||
bool ReadPre(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSPre(oTS);
|
||
oTSPre.oAdditionalStyle.m_oFont.SetFamily(L"Courier New", NEXT_LEVEL);
|
||
oTSPre.oAdditionalStyle.m_oFont.SetSize(20, NSCSS::UnitMeasure::Point, NEXT_LEVEL);
|
||
oTSPre.oAdditionalStyle.m_oMargin.SetTop(0, NSCSS::UnitMeasure::Twips, NEXT_LEVEL);
|
||
oTSPre.oAdditionalStyle.m_oMargin.SetBottom(0, NSCSS::UnitMeasure::Twips, NEXT_LEVEL);
|
||
oTSPre.bPre = true;
|
||
|
||
return readStream(pXml, arSelectors, oTSPre);
|
||
}
|
||
|
||
bool ReadTextarea(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
CTextSettings oTSP(oTS);
|
||
oTSP.AddPStyle(L"<w:pBdr><w:left w:val=\"single\" w:color=\"000000\" w:sz=\"8\" w:space=\"0\"/><w:top w:val=\"single\" w:color=\"000000\" w:sz=\"8\" w:space=\"0\"/><w:right w:val=\"single\" w:color=\"000000\" w:sz=\"8\" w:space=\"0\"/><w:bottom w:val=\"single\" w:color=\"000000\" w:sz=\"8\" w:space=\"0\"/></w:pBdr>");
|
||
|
||
return readStream(pXml, arSelectors, oTSP);
|
||
}
|
||
|
||
bool ReadDetails(NSStringUtils::CStringBuilder* pXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (NULL == pXml)
|
||
return false;
|
||
|
||
bool bOpened = false;
|
||
if (m_oLightReader.MoveToFirstAttribute())
|
||
{
|
||
do
|
||
{
|
||
bOpened = (L"open" == m_oLightReader.GetName());
|
||
} while (m_oLightReader.MoveToNextAttribute() && !bOpened);
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
if(m_oLightReader.IsEmptyNode() || !m_oLightReader.ReadNextSiblingNode2(nDeath))
|
||
return false;
|
||
|
||
NSStringUtils::CStringBuilder oSummary;
|
||
NSStringUtils::CStringBuilder oBody;
|
||
|
||
const TState oCurrentState{m_oState};
|
||
TState oSummaryState{m_oState};
|
||
TState oBodyState{m_oState};
|
||
|
||
do
|
||
{
|
||
if (L"summary" == m_oLightReader.GetName())
|
||
{
|
||
m_oState = oSummaryState;
|
||
if (0 == oSummary.GetSize())
|
||
{
|
||
OpenP(&oSummary);
|
||
OpenR(&oSummary);
|
||
OpenT(&oSummary);
|
||
oSummary.WriteString((bOpened) ? L"\u25BD" : L"\u25B7");
|
||
}
|
||
|
||
readStream(&oSummary, arSelectors, oTS);
|
||
CloseP(&oSummary, arSelectors);
|
||
oSummaryState = m_oState;
|
||
m_oState = oCurrentState;
|
||
}
|
||
else if (bOpened)
|
||
{
|
||
m_oState = oBodyState;
|
||
readStream(&oBody, arSelectors, oTS);
|
||
CloseP(&oBody, arSelectors);
|
||
oBodyState = m_oState;
|
||
m_oState = oCurrentState;
|
||
}
|
||
} while (m_oLightReader.ReadNextSiblingNode2(nDeath));
|
||
|
||
WriteToStringBuilder(oSummary, *pXml);
|
||
|
||
if (bOpened)
|
||
{
|
||
m_oState = oBodyState;
|
||
WriteToStringBuilder(oBody, *pXml);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool readInside (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS, const std::wstring& sName)
|
||
{
|
||
//TODO:: обработать все варианты return'а
|
||
|
||
if(sName == L"#text")
|
||
return ReadText(oXml, sSelectors, oTS);
|
||
|
||
if (TagIsUnprocessed(sName))
|
||
return false;
|
||
|
||
std::wstring sNote = GetSubClass(oXml, sSelectors);
|
||
|
||
bool bResult = true;
|
||
|
||
const HtmlTag eHtmlTag{GetHtmlTag(sName)};
|
||
|
||
switch(eHtmlTag)
|
||
{
|
||
case HTML_TAG(A):
|
||
case HTML_TAG(AREA):
|
||
{
|
||
bResult = readA(oXml, sSelectors, oTS, sNote);
|
||
break;
|
||
}
|
||
case HTML_TAG(ABBR):
|
||
{
|
||
bResult = ReadAbbr(oXml, sSelectors, oTS, sNote);
|
||
break;
|
||
}
|
||
case HTML_TAG(B):
|
||
case HTML_TAG(STRONG):
|
||
{
|
||
bResult = ReadBold(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(BDO):
|
||
{
|
||
bResult = ReadBdo(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(BDI):
|
||
{
|
||
bResult = ReadBdi(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(BR):
|
||
{
|
||
bResult = ReadBr(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(CENTER):
|
||
{
|
||
bResult = ReadCenter(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(CITE):
|
||
case HTML_TAG(DFN):
|
||
case HTML_TAG(EM):
|
||
case HTML_TAG(I):
|
||
case HTML_TAG(VAR):
|
||
{
|
||
bResult = ReadItalic(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(CODE):
|
||
case HTML_TAG(TT):
|
||
{
|
||
bResult = ReadCode(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(KBD):
|
||
{
|
||
bResult = ReadKbd(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(SAMP):
|
||
{
|
||
bResult = ReadSamp(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(DEL):
|
||
case HTML_TAG(S):
|
||
case HTML_TAG(STRIKE):
|
||
{
|
||
bResult = ReadStrike(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(FONT):
|
||
{
|
||
bResult = ReadFont(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(IMG):
|
||
{
|
||
bResult = readImage(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(INS):
|
||
case HTML_TAG(U):
|
||
{
|
||
bResult = ReadUnderline(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(MARK):
|
||
{
|
||
bResult = ReadMark(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(Q):
|
||
{
|
||
bResult = ReadQ(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(SUP):
|
||
{
|
||
bResult = ReadSup(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(SUB):
|
||
{
|
||
bResult = ReadSub(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(SVG):
|
||
{
|
||
wrP(oXml, sSelectors, oTS);
|
||
bResult = readSVG(m_oLightReader.GetOuterXml());
|
||
|
||
if (bResult)
|
||
ImageRels(oXml, -1, L"", L"png");
|
||
|
||
break;
|
||
}
|
||
case HTML_TAG(INPUT):
|
||
{
|
||
bResult = readInput(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(CANVAS):
|
||
case HTML_TAG(VIDEO):
|
||
case HTML_TAG(MATH):
|
||
case HTML_TAG(IFRAME):
|
||
case HTML_TAG(EMBED):
|
||
case HTML_TAG(WBR):
|
||
case HTML_TAG(AUDIO):
|
||
case HTML_TAG(BGSOUND):
|
||
case HTML_TAG(APPLET):
|
||
case HTML_TAG(BLINK):
|
||
case HTML_TAG(KEYGEN):
|
||
case HTML_TAG(TITLE):
|
||
case HTML_TAG(STYLE):
|
||
case HTML_TAG(SCRIPT):
|
||
{
|
||
//Если встретили не обрабатываемые теги, то просто пропускаем
|
||
sSelectors.pop_back();
|
||
return false;
|
||
}
|
||
case HTML_TAG(SPAN):
|
||
{
|
||
bResult = ReadSpan(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(NOBR):
|
||
{
|
||
bResult = ReadNobr(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(BASEFONT):
|
||
{
|
||
bResult = ReadBasefont(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(BUTTON):
|
||
case HTML_TAG(LABEL):
|
||
case HTML_TAG(DATA):
|
||
case HTML_TAG(OBJECT):
|
||
case HTML_TAG(NOSCRIPT):
|
||
case HTML_TAG(OUTPUT):
|
||
case HTML_TAG(TIME):
|
||
case HTML_TAG(SMALL):
|
||
case HTML_TAG(PROGRESS):
|
||
case HTML_TAG(HGROUP):
|
||
case HTML_TAG(METER):
|
||
case HTML_TAG(ACRONYM):
|
||
case HTML_TAG(BIG):
|
||
{
|
||
bResult = readStream(oXml, sSelectors, oTS);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
NSStringUtils::CStringBuilder oXmlData;
|
||
TState oCurentState{m_oState};
|
||
|
||
CloseP(&oXmlData, sSelectors);
|
||
|
||
switch(eHtmlTag)
|
||
{
|
||
case HTML_TAG(ADDRESS):
|
||
{
|
||
bResult = ReadItalic(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(DD):
|
||
{
|
||
bResult = ReadDD(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(ASIDE):
|
||
case HTML_TAG(DIV):
|
||
{
|
||
bResult = ReadDiv(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(BLOCKQUOTE):
|
||
{
|
||
bResult = ReadBlockquote(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(ARTICLE):
|
||
case HTML_TAG(HEADER):
|
||
case HTML_TAG(MAIN):
|
||
case HTML_TAG(SUMMARY):
|
||
case HTML_TAG(FOOTER):
|
||
case HTML_TAG(NAV):
|
||
case HTML_TAG(FIGCAPTION):
|
||
case HTML_TAG(FORM):
|
||
case HTML_TAG(OPTION):
|
||
case HTML_TAG(DT):
|
||
case HTML_TAG(P):
|
||
case HTML_TAG(SECTION):
|
||
case HTML_TAG(FIGURE):
|
||
case HTML_TAG(DL):
|
||
case HTML_TAG(LEGEND):
|
||
case HTML_TAG(MAP):
|
||
case HTML_TAG(H1):
|
||
case HTML_TAG(H2):
|
||
case HTML_TAG(H3):
|
||
case HTML_TAG(H4):
|
||
case HTML_TAG(H5):
|
||
case HTML_TAG(H6):
|
||
{
|
||
bResult = readStream(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(HR):
|
||
{
|
||
bResult = ReadHr(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(LI):
|
||
{
|
||
bResult = ReadListElement(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(OL):
|
||
case HTML_TAG(UL):
|
||
{
|
||
bResult = ReadList(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(MENU):
|
||
case HTML_TAG(SELECT):
|
||
case HTML_TAG(DATALIST):
|
||
case HTML_TAG(DIR):
|
||
{
|
||
bResult = readLi(&oXmlData, sSelectors, oTS, HTML_TAG(OL) != eHtmlTag);
|
||
break;
|
||
}
|
||
case HTML_TAG(PRE):
|
||
case HTML_TAG(XMP):
|
||
{
|
||
bResult = ReadPre(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(TABLE):
|
||
{
|
||
bResult = ParseTable(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(RUBY):
|
||
{
|
||
bResult = ParseRuby(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(TEXTAREA):
|
||
case HTML_TAG(FIELDSET):
|
||
{
|
||
bResult = ReadTextarea(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
case HTML_TAG(DETAILS):
|
||
{
|
||
bResult = ReadDetails(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
bResult = readStream(&oXmlData, sSelectors, oTS);
|
||
break;
|
||
}
|
||
}
|
||
|
||
readNote(&oXmlData, sSelectors, sNote);
|
||
|
||
CloseP(&oXmlData, sSelectors);
|
||
|
||
if (bResult)
|
||
WriteToStringBuilder(oXmlData, *oXml);
|
||
else
|
||
m_oState = oCurentState;
|
||
}
|
||
}
|
||
|
||
if (HTML_TAG(DIV) != eHtmlTag && HTML_TAG(ASIDE) != eHtmlTag)
|
||
m_oState.m_bBanUpdatePageData = true;
|
||
|
||
readNote(oXml, sSelectors, sNote);
|
||
sSelectors.pop_back();
|
||
return bResult;
|
||
}
|
||
|
||
bool readStream (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS, bool bInsertEmptyP = false)
|
||
{
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
if(m_oLightReader.IsEmptyNode() || !m_oLightReader.ReadNextSiblingNode2(nDeath))
|
||
{
|
||
if (bInsertEmptyP)
|
||
{
|
||
wrP(oXml, sSelectors, oTS);
|
||
wrRPr(oXml, sSelectors, oTS);
|
||
CloseP(oXml, sSelectors);
|
||
m_oState.m_bInP = false;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool bResult = false;
|
||
|
||
do
|
||
{
|
||
if (readInside(oXml, sSelectors, oTS, m_oLightReader.GetName()))
|
||
bResult = true;
|
||
} while(m_oLightReader.ReadNextSiblingNode2(nDeath));
|
||
|
||
if (!bResult && bInsertEmptyP)
|
||
{
|
||
wrP(oXml, sSelectors, oTS);
|
||
wrRPr(oXml, sSelectors, oTS);
|
||
CloseP(oXml, sSelectors);
|
||
m_oState.m_bInP = false;
|
||
}
|
||
|
||
return bResult;
|
||
}
|
||
|
||
void CalculateCellStyles(TTableCellStyle* pCellStyle, std::vector<NSCSS::CNode>& arSelectors)
|
||
{
|
||
if (NULL == pCellStyle)
|
||
return;
|
||
|
||
pCellStyle->m_wsVAlign = arSelectors.back().m_pCompiledStyle->m_oDisplay.GetVAlign().ToWString();
|
||
pCellStyle->m_wsHAlign = arSelectors.back().m_pCompiledStyle->m_oDisplay.GetHAlign().ToWString();
|
||
pCellStyle->m_oBackground = arSelectors.back().m_pCompiledStyle->m_oBackground.GetColor();
|
||
pCellStyle->m_oHeight = arSelectors.back().m_pCompiledStyle->m_oDisplay.GetHeight();
|
||
pCellStyle->m_oWidth = arSelectors.back().m_pCompiledStyle->m_oDisplay.GetWidth();
|
||
pCellStyle->m_oPadding = arSelectors.back().m_pCompiledStyle->m_oPadding;
|
||
pCellStyle->m_oBorder = arSelectors.back().m_pCompiledStyle->m_oBorder;
|
||
|
||
if (pCellStyle->m_wsHAlign.empty())
|
||
pCellStyle->m_wsHAlign = arSelectors.back().m_pCompiledStyle->m_oText.GetAlign().ToWString();
|
||
}
|
||
|
||
void ParseTableCaption(CTable& oTable, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS)
|
||
{
|
||
GetSubClass(NULL, sSelectors);
|
||
|
||
NSStringUtils::CStringBuilder oData;
|
||
|
||
CTextSettings oTSCaption{oTS};
|
||
oTSCaption.sPStyle += L"<w:jc w:val=\"center\"/>";
|
||
|
||
wrP(&oData, sSelectors, oTSCaption);
|
||
readStream(&oData, sSelectors, oTSCaption);
|
||
CloseP(&oData, sSelectors);
|
||
|
||
oTable.AddCaption(oData);
|
||
|
||
sSelectors.pop_back();
|
||
return;
|
||
}
|
||
|
||
void ParseTableColspan(CTable& oTable)
|
||
{
|
||
CTableColgroup *pColgroup = new CTableColgroup(m_oLightReader);
|
||
|
||
if (NULL == pColgroup)
|
||
return;
|
||
|
||
std::vector<NSCSS::CNode> arNodes;
|
||
|
||
GetSubClass(NULL, arNodes);
|
||
|
||
oTable.AddColgroup(pColgroup);
|
||
|
||
const int nDeath = m_oLightReader.GetDepth();
|
||
if (!m_oLightReader.IsEmptyNode() && m_oLightReader.ReadNextSiblingNode2(nDeath))
|
||
{
|
||
do
|
||
{
|
||
if (L"col" != m_oLightReader.GetName())
|
||
continue;
|
||
|
||
CTableCol *pCol = new CTableCol(m_oLightReader);
|
||
|
||
if (NULL == pCol)
|
||
continue;
|
||
|
||
GetSubClass(NULL, arNodes);
|
||
CalculateCellStyles(pCol->GetStyle(), arNodes);
|
||
arNodes.pop_back();
|
||
|
||
if (NULL == pCol)
|
||
continue;
|
||
|
||
pColgroup->AddCol(pCol);
|
||
} while(m_oLightReader.ReadNextSiblingNode2(nDeath));
|
||
}
|
||
|
||
if(pColgroup->Empty())
|
||
{
|
||
std::map<std::wstring, std::wstring>::const_iterator itFound = arNodes.begin()->m_mAttributes.find(L"span");
|
||
|
||
CTableCol *pCol = new CTableCol((arNodes.begin()->m_mAttributes.cend() != itFound) ? NSStringFinder::ToInt(itFound->second, 1) : 1);
|
||
|
||
if (NULL == pCol)
|
||
return;
|
||
|
||
CalculateCellStyles(pCol->GetStyle(), arNodes);
|
||
|
||
pColgroup->AddCol(pCol);
|
||
}
|
||
}
|
||
|
||
struct TRowspanElement
|
||
{
|
||
UINT m_unRowSpan;
|
||
UINT m_unColumnIndex;
|
||
const CTableCell* m_pCell;
|
||
|
||
TRowspanElement(UINT unRowSpan, UINT unColumnIndex, const CTableCell* pCell)
|
||
: m_unRowSpan(unRowSpan), m_unColumnIndex(unColumnIndex), m_pCell(pCell)
|
||
{}
|
||
};
|
||
|
||
void ParseTableRows(CTable& oTable, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS, ERowParseMode eMode)
|
||
{
|
||
std::vector<TRowspanElement> arRowspanElements;
|
||
std::vector<CTableRow*> arRows;
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while (m_oLightReader.ReadNextSiblingNode(nDeath))
|
||
{
|
||
if (L"tr" != m_oLightReader.GetName())
|
||
continue;
|
||
|
||
GetSubClass(NULL, sSelectors);
|
||
|
||
CTableRow *pRow = new CTableRow();
|
||
|
||
for (std::vector<TRowspanElement>::iterator itElement = arRowspanElements.begin(); itElement < arRowspanElements.end();)
|
||
{
|
||
pRow->InsertCell(CTableCell::CreateEmpty(itElement->m_pCell->GetColspan(), true, itElement->m_pCell->GetStyles()), itElement->m_unColumnIndex);
|
||
|
||
itElement->m_unRowSpan--;
|
||
if (1 == itElement->m_unRowSpan)
|
||
itElement = arRowspanElements.erase(itElement);
|
||
else
|
||
++itElement;
|
||
}
|
||
|
||
UINT unColumnIndex = 0;
|
||
int nTrDepth = m_oLightReader.GetDepth();
|
||
while (m_oLightReader.ReadNextSiblingNode(nTrDepth))
|
||
{
|
||
CTableCell *pCell = new CTableCell();
|
||
|
||
if (NULL == pCell)
|
||
continue;
|
||
|
||
GetSubClass(pCell->GetData(), sSelectors);
|
||
|
||
std::vector<NSCSS::CNode> arNewSelectors{(std::vector<NSCSS::CNode>::const_iterator)std::find_if(sSelectors.begin(), sSelectors.end(), [](const NSCSS::CNode& oNode){ return L"table" == oNode.m_wsName; }), sSelectors.cend()};
|
||
|
||
CalculateCellStyles(pCell->GetStyles(), arNewSelectors);
|
||
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
if(m_oLightReader.GetName() == L"colspan")
|
||
pCell->SetColspan(NSStringFinder::ToInt(m_oLightReader.GetText(), 1), pRow->GetIndex());
|
||
else if(m_oLightReader.GetName() == L"rowspan")
|
||
{
|
||
pCell->SetRowspan(NSStringFinder::ToInt(m_oLightReader.GetText(), 1));
|
||
|
||
if (1 != pCell->GetRowspan())
|
||
arRowspanElements.push_back({pCell->GetRowspan(), unColumnIndex, pCell});
|
||
}
|
||
}
|
||
|
||
m_oLightReader.MoveToElement();
|
||
m_oState.m_bWasPStyle = false;
|
||
|
||
// Читаем th. Ячейка заголовка таблицы. Выравнивание посередине. Выделяется полужирным
|
||
if(m_oLightReader.GetName() == L"th")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
|
||
if (pCell->GetStyles()->m_wsHAlign.empty())
|
||
oTSR.oAdditionalStyle.m_oText.SetAlign(L"center", NEXT_LEVEL);
|
||
|
||
oTSR.oAdditionalStyle.m_oFont.SetWeight(L"bold", NEXT_LEVEL);
|
||
|
||
readStream(pCell->GetData(), sSelectors, oTSR, true);
|
||
}
|
||
// Читаем td. Ячейка таблицы
|
||
else if(m_oLightReader.GetName() == L"td")
|
||
readStream(pCell->GetData(), sSelectors, oTS, true);
|
||
|
||
if (pRow->GetIndex() == MAXCOLUMNSINTABLE - 1)
|
||
{
|
||
CTextSettings oTrTS{oTS};
|
||
oTrTS.bMergeText = true;
|
||
oTrTS.bAddSpaces = true;
|
||
m_oState.m_bWasSpace = true;
|
||
|
||
while (m_oLightReader.ReadNextSiblingNode(nTrDepth))
|
||
{
|
||
if (L"td" != m_oLightReader.GetName() && L"th" != m_oLightReader.GetName())
|
||
continue;
|
||
|
||
GetSubClass(pCell->GetData(), sSelectors);
|
||
readStream(pCell->GetData(), sSelectors, oTrTS);
|
||
sSelectors.pop_back();
|
||
}
|
||
}
|
||
CloseP(pCell->GetData(), sSelectors);
|
||
|
||
pRow->AddCell(pCell);
|
||
|
||
sSelectors.pop_back();
|
||
|
||
++unColumnIndex;
|
||
|
||
if (pRow->GetIndex() == MAXCOLUMNSINTABLE)
|
||
break;
|
||
}
|
||
|
||
sSelectors.pop_back();
|
||
arRows.push_back(pRow);
|
||
}
|
||
|
||
oTable.AddRows(arRows, eMode);
|
||
}
|
||
|
||
bool ParseRuby(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS)
|
||
{
|
||
if(m_oLightReader.IsEmptyNode())
|
||
return false;
|
||
|
||
const int nDepth = m_oLightReader.GetDepth();
|
||
|
||
#ifdef DISABLE_RUBY_SUPPORT
|
||
wrP(oXml, sSelectors, oTS);
|
||
|
||
while (m_oLightReader.ReadNextSiblingNode2(nDepth))
|
||
{
|
||
GetSubClass(NULL, sSelectors);
|
||
|
||
if (L"rp" == sSelectors.back().m_wsName)
|
||
{
|
||
sSelectors.pop_back();
|
||
continue;
|
||
}
|
||
else if (L"rt" == sSelectors.back().m_wsName)
|
||
readStream(oXml, sSelectors, oTS);
|
||
else
|
||
readInside(oXml, sSelectors, oTS, sSelectors.back().m_wsName);
|
||
|
||
sSelectors.pop_back();
|
||
}
|
||
|
||
CloseP(oXml, sSelectors);
|
||
|
||
return true;
|
||
#endif
|
||
|
||
NSStringUtils::CStringBuilder oBase;
|
||
NSStringUtils::CStringBuilder oRT;
|
||
|
||
TState oRtState{m_oState};
|
||
oRtState.m_bInP = true;
|
||
|
||
TState oBaseState{m_oState};
|
||
oBaseState.m_bInP = true;
|
||
|
||
while (m_oLightReader.ReadNextSiblingNode2(nDepth))
|
||
{
|
||
GetSubClass(NULL, sSelectors);
|
||
|
||
CTextSettings oNewSettings{oTS};
|
||
|
||
const std::wstring wsHighlight{sSelectors.back().m_pCompiledStyle->m_oBackground.GetColor()
|
||
.EquateToColor({{{0, 0, 0}, L"black"}, {{0, 0, 255}, L"blue"}, {{0, 255, 255}, L"cyan"},
|
||
{{0, 255, 0}, L"green"}, {{255, 0, 255}, L"magenta"}, {{255, 0, 0}, L"red"},
|
||
{{255, 255, 0}, L"yellow"}, {{255, 255, 255}, L"white"}, {{0, 0, 139}, L"darkBlue"},
|
||
{{0, 139, 139}, L"darkCyan"}, {{0, 100, 0}, L"darkGreen"}, {{139, 0, 139}, L"darkMagenta"},
|
||
{{139, 0, 0}, L"darkRed"}, {{128, 128, 0}, L"darkYellow"},{{169, 169, 169}, L"darkGray"},
|
||
{{211, 211, 211}, L"lightGray"}})};
|
||
|
||
if (L"none" != wsHighlight)
|
||
oNewSettings.oAdditionalStyle.m_oText.SetHighlight(sSelectors.back().m_pCompiledStyle->m_oBackground.GetColor().ToWString(), NEXT_LEVEL);
|
||
// oNewSettings.AddRStyle(L"<w:shd w:val=\"" + wsHighlight + L"\"/>");
|
||
|
||
if (L"rt" == sSelectors.back().m_wsName)
|
||
{
|
||
std::swap(m_oState, oRtState);
|
||
readStream(&oRT, sSelectors, oNewSettings);
|
||
std::swap(m_oState, oRtState);
|
||
}
|
||
else if (L"rp" == sSelectors.back().m_wsName)
|
||
{
|
||
sSelectors.pop_back();
|
||
continue;
|
||
}
|
||
else if (L"#text" == sSelectors.back().m_wsName)
|
||
{
|
||
std::swap(m_oState, oBaseState);
|
||
readInside(&oBase, sSelectors, oNewSettings, sSelectors.back().m_wsName);
|
||
std::swap(m_oState, oBaseState);
|
||
}
|
||
sSelectors.pop_back();
|
||
}
|
||
|
||
WriteSpace(&oBase);
|
||
|
||
wrP(oXml, sSelectors, oTS);
|
||
|
||
if (0 != oRT.GetSize())
|
||
{
|
||
NSCSS::CCompiledStyle *pStyle = sSelectors.back().m_pCompiledStyle;
|
||
|
||
int nFontSize = 24;
|
||
|
||
if (!pStyle->m_oFont.GetSize().Empty() && !pStyle->m_oFont.GetSize().Zero())
|
||
nFontSize = pStyle->m_oFont.GetSize().ToInt(NSCSS::Point) * 2;
|
||
|
||
bool bConsistsChineseCharacters = false;
|
||
|
||
const std::vector<NSCSS::CNode>::const_reverse_iterator oFound{std::find_if(sSelectors.crbegin(), sSelectors.crend(), [](const NSCSS::CNode& oNode){ return oNode.m_mAttributes.cend() != oNode.m_mAttributes.find(L"lang");})};
|
||
|
||
if (sSelectors.crend() != oFound)
|
||
{
|
||
const size_t unFound{oFound->m_mAttributes.at(L"lang").find(L"-")};
|
||
|
||
if (std::wstring::npos != unFound)
|
||
bConsistsChineseCharacters = ConsistsChineseCharacters(oFound->m_mAttributes.at(L"lang").substr(0, unFound));
|
||
}
|
||
|
||
OpenR(oXml);
|
||
oXml->WriteString(L"<w:ruby><w:rubyPr><w:rubyAlign w:val=\"" + std::wstring((bConsistsChineseCharacters) ? L"distributeSpace" : L"center") + L"\"/><w:hps w:val=\"" + std::to_wstring(nFontSize) + L"\"/><w:hpsRaise w:val=\"" + std::to_wstring(nFontSize - 2) + L"\"/><w:hpsBaseText w:val=\"" + std::to_wstring(nFontSize) + L"\"/></w:rubyPr>");
|
||
oXml->WriteString(L"<w:rt>");
|
||
WriteToStringBuilder(oRT, *oXml);
|
||
oXml->WriteString(L"</w:rt>");
|
||
oXml->WriteString(L"<w:rubyBase>");
|
||
WriteToStringBuilder(oBase, *oXml);
|
||
oXml->WriteString(L"</w:rubyBase>");
|
||
oXml->WriteString(L"</w:ruby>");
|
||
CloseR(oXml);
|
||
}
|
||
else
|
||
WriteToStringBuilder(oBase, *oXml);
|
||
|
||
CloseP(oXml, sSelectors);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool ParseTable(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS)
|
||
{
|
||
if(m_oLightReader.IsEmptyNode())
|
||
return false;
|
||
|
||
CTable oTable;
|
||
CTextSettings oTextSettings{oTS};
|
||
oTextSettings.sPStyle.clear();
|
||
|
||
NSCSS::CCompiledStyle *pStyle = sSelectors.back().m_pCompiledStyle;
|
||
|
||
//Table styles
|
||
std::wstring wsFrame;
|
||
|
||
for (const std::pair<std::wstring, std::wstring>& oArgument : sSelectors.back().m_mAttributes)
|
||
{
|
||
if (L"border" == oArgument.first)
|
||
{
|
||
const int nWidth = NSStringFinder::ToInt(oArgument.second);
|
||
|
||
if (0 < nWidth)
|
||
{
|
||
oTable.SetRules(L"all");
|
||
|
||
if (!pStyle->m_oBorder.Empty())
|
||
continue;
|
||
|
||
pStyle->m_oBorder.SetStyle(L"outset", 0, true);
|
||
pStyle->m_oBorder.SetWidth(nWidth, NSCSS::UnitMeasure::Point, 0, true);
|
||
pStyle->m_oBorder.SetColor(L"auto", 0, true);
|
||
}
|
||
else if (pStyle->m_oBorder.Empty())
|
||
{
|
||
pStyle->m_oBorder.SetNone(0, true);
|
||
oTable.SetRules(L"none");
|
||
}
|
||
}
|
||
else if (L"cellpadding" == oArgument.first)
|
||
pStyle->m_oPadding.SetValues(oArgument.second + L"px", 0, true);
|
||
else if (L"rules" == oArgument.first)
|
||
oTable.SetRules(oArgument.second);
|
||
else if (L"frame" == oArgument.first)
|
||
wsFrame = oArgument.second;
|
||
}
|
||
|
||
if (!wsFrame.empty() && pStyle->m_oBorder.Empty())
|
||
{
|
||
#define SetDefaultBorderSide(side) \
|
||
pStyle->m_oBorder.SetStyle##side(L"solid", 0, true); \
|
||
pStyle->m_oBorder.SetWidth##side(1, NSCSS::UnitMeasure::Point, 0, true); \
|
||
pStyle->m_oBorder.SetColor##side(L"black", 0, true)
|
||
|
||
if (NSStringFinder::Equals(L"border", wsFrame))
|
||
{
|
||
SetDefaultBorderSide();
|
||
}
|
||
else if (NSStringFinder::Equals(L"above", wsFrame))
|
||
{
|
||
SetDefaultBorderSide(TopSide);
|
||
}
|
||
else if (NSStringFinder::Equals(L"below", wsFrame))
|
||
{
|
||
SetDefaultBorderSide(BottomSide);
|
||
}
|
||
else if (NSStringFinder::Equals(L"hsides", wsFrame))
|
||
{
|
||
SetDefaultBorderSide(TopSide);
|
||
SetDefaultBorderSide(BottomSide);
|
||
}
|
||
else if (NSStringFinder::Equals(L"vsides", wsFrame))
|
||
{
|
||
SetDefaultBorderSide(LeftSide);
|
||
SetDefaultBorderSide(RightSide);
|
||
}
|
||
else if (NSStringFinder::Equals(L"rhs", wsFrame))
|
||
{
|
||
SetDefaultBorderSide(RightSide);
|
||
}
|
||
else if (NSStringFinder::Equals(L"lhs", wsFrame))
|
||
{
|
||
SetDefaultBorderSide(LeftSide);
|
||
}
|
||
}
|
||
|
||
if (pStyle->m_oBorder.GetCollapse() == NSCSS::NSProperties::BorderCollapse::Collapse)
|
||
oTable.SetCellSpacing(0);
|
||
else if (sSelectors.back().m_mAttributes.end() != sSelectors.back().m_mAttributes.find(L"cellspacing"))
|
||
oTable.SetCellSpacing(NSStringFinder::ToInt(sSelectors.back().m_mAttributes[L"cellspacing"]));
|
||
else if (pStyle->m_oBorder.GetCollapse() == NSCSS::NSProperties::BorderCollapse::Separate)
|
||
oTable.SetCellSpacing(15);
|
||
|
||
oTable.SetWidth(pStyle->m_oDisplay.GetWidth());
|
||
oTable.SetBorder(pStyle->m_oBorder);
|
||
oTable.SetPadding(pStyle->m_oPadding);
|
||
oTable.SetMargin(pStyle->m_oMargin);
|
||
oTable.SetAlign(pStyle->m_oDisplay.GetHAlign().ToWString());
|
||
//------
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while(m_oLightReader.ReadNextSiblingNode(nDeath))
|
||
{
|
||
const std::wstring sName = m_oLightReader.GetName();
|
||
GetSubClass(oXml, sSelectors);
|
||
|
||
if(sName == L"caption")
|
||
ParseTableCaption(oTable, sSelectors, oTS);
|
||
if(sName == L"thead")
|
||
ParseTableRows(oTable, sSelectors, oTextSettings, ERowParseMode::ParseModeHeader);
|
||
if(sName == L"tbody")
|
||
ParseTableRows(oTable, sSelectors, oTextSettings, ERowParseMode::ParseModeBody);
|
||
else if(sName == L"tfoot")
|
||
ParseTableRows(oTable, sSelectors, oTextSettings, ERowParseMode::ParseModeFoother);
|
||
else if (sName == L"colgroup")
|
||
ParseTableColspan(oTable);
|
||
|
||
sSelectors.pop_back();
|
||
}
|
||
|
||
oTable.Shorten();
|
||
oTable.CompleteTable();
|
||
oTable.ConvertToOOXML(*oXml);
|
||
WriteEmptyParagraph(oXml, true);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool readInput (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS)
|
||
{
|
||
std::wstring sValue;
|
||
std::wstring sAlt;
|
||
std::wstring sType;
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
std::wstring sName = m_oLightReader.GetName();
|
||
if(sName == L"value")
|
||
sValue = m_oLightReader.GetText();
|
||
else if(sName == L"alt")
|
||
sAlt = m_oLightReader.GetText();
|
||
else if(sName == L"type")
|
||
sType = m_oLightReader.GetText();
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
if(sType == L"hidden")
|
||
return false;
|
||
if(sValue.empty())
|
||
sValue = sAlt;
|
||
if(!sValue.empty())
|
||
{
|
||
wrP(oXml, sSelectors, oTS);
|
||
OpenR(oXml);
|
||
wrRPr(oXml, sSelectors, oTS);
|
||
OpenT(oXml);
|
||
oXml->WriteEncodeXmlString(sValue + L' ');
|
||
CloseT(oXml);
|
||
CloseR(oXml);
|
||
}
|
||
|
||
return readStream(oXml, sSelectors, oTS, ElementInTable(sSelectors));
|
||
}
|
||
|
||
bool ReadListElement(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if (OpenP(oXml))
|
||
wrP(oXml, arSelectors, oTS);
|
||
|
||
const bool bResult{readStream(oXml, arSelectors, oTS)};
|
||
|
||
CloseP(oXml, arSelectors);
|
||
|
||
return bResult;
|
||
}
|
||
|
||
bool ReadList(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& arSelectors, CTextSettings& oTS)
|
||
{
|
||
if(m_oLightReader.IsEmptyNode())
|
||
return false;
|
||
|
||
GetSubClass(oXml, arSelectors);
|
||
|
||
CloseP(oXml, arSelectors);
|
||
|
||
CTextSettings oTSLi(oTS);
|
||
|
||
++oTSLi.nLi;
|
||
|
||
//Нумерованный список
|
||
if (L"ol" == arSelectors.back().m_wsName)
|
||
{
|
||
int nStart = 1;
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
if(m_oLightReader.GetName() == L"start")
|
||
nStart = NSStringFinder::ToInt(m_oLightReader.GetText(), 1);
|
||
m_oLightReader.MoveToElement();
|
||
|
||
oTSLi.bNumberingLi = true;
|
||
|
||
const std::wstring wsStart(std::to_wstring(nStart));
|
||
m_oNumberXml.WriteString(L"<w:abstractNum w:abstractNumId=\"");
|
||
m_oNumberXml.WriteString(std::to_wstring(m_nNumberingId++));
|
||
m_oNumberXml.WriteString(L"\"><w:multiLevelType w:val=\"hybridMultilevel\"/><w:lvl w:ilvl=\"0\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%1.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"709\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"1\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%2.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"1429\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"2\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%3.\"/><w:lvlJc w:val=\"right\"/><w:pPr><w:ind w:left=\"2149\" w:hanging=\"180\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"3\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%4.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"2869\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"4\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%5.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"3589\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"5\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%6.\"/><w:lvlJc w:val=\"right\"/><w:pPr><w:ind w:left=\"4309\" w:hanging=\"180\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"6\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%7.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"5029\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"7\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%8.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"5749\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"8\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%9.\"/><w:lvlJc w:val=\"right\"/><w:pPr><w:ind w:left=\"6469\" w:hanging=\"180\"/></w:pPr></w:lvl></w:abstractNum>");
|
||
}
|
||
|
||
CTextSettings oTSList{oTSLi};
|
||
|
||
oTSList.oAdditionalStyle.m_oMargin.SetTop (100, NSCSS::UnitMeasure::Twips, 0, true);
|
||
oTSList.oAdditionalStyle.m_oMargin.SetBottom(100, NSCSS::UnitMeasure::Twips, 0, true);
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while(m_oLightReader.ReadNextSiblingNode2(nDeath))
|
||
{
|
||
const std::wstring wsName = m_oLightReader.GetName();
|
||
|
||
if (L"li" == wsName)
|
||
ReadListElement(oXml, arSelectors, oTSList);
|
||
else
|
||
{
|
||
CloseP(oXml, arSelectors);
|
||
readInside(oXml, arSelectors, oTSLi, wsName);
|
||
}
|
||
}
|
||
|
||
CloseP(oXml, arSelectors);
|
||
arSelectors.pop_back();
|
||
|
||
return true;
|
||
}
|
||
|
||
bool readLi (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS, bool bType)
|
||
{
|
||
if(m_oLightReader.IsEmptyNode())
|
||
return false;
|
||
|
||
int nStart = 1;
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
if(m_oLightReader.GetName() == L"start")
|
||
nStart = NSStringFinder::ToInt(m_oLightReader.GetText(), 1);
|
||
m_oLightReader.MoveToElement();
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while(m_oLightReader.ReadNextSiblingNode(nDeath))
|
||
{
|
||
const std::wstring sName = m_oLightReader.GetName();
|
||
if (sName == L"optgroup")
|
||
{
|
||
GetSubClass(oXml, sSelectors);
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
if(m_oLightReader.GetName() != L"label")
|
||
continue;
|
||
|
||
CloseP(oXml, sSelectors);
|
||
wrP(oXml, sSelectors, oTS);
|
||
OpenR(oXml);
|
||
wrRPr(oXml, sSelectors, oTS);
|
||
OpenT(oXml);
|
||
oXml->WriteEncodeXmlString(m_oLightReader.GetText());
|
||
CloseT(oXml);
|
||
CloseR(oXml);
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
readLi(oXml, sSelectors, oTS, true);
|
||
sSelectors.pop_back();
|
||
continue;
|
||
}
|
||
if (sName != L"li" && sName != L"option")
|
||
{
|
||
readInside(oXml, sSelectors, oTS, sName);
|
||
continue;
|
||
}
|
||
|
||
CloseP(oXml, sSelectors);
|
||
|
||
CTextSettings oTSLiP(oTS);
|
||
|
||
oTSLiP.bNumberingLi = !bType;
|
||
|
||
std::wstring wsValue;
|
||
const std::wstring wsParentName{(!sSelectors.empty()) ? sSelectors.back().m_wsName : L""};
|
||
|
||
GetSubClass(oXml, sSelectors);
|
||
|
||
std::wstring wsArgumentName;
|
||
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
wsArgumentName = m_oLightReader.GetName();
|
||
|
||
if(L"value" == wsArgumentName && L"datalist" == wsParentName)
|
||
{
|
||
if (sName == L"option")
|
||
wsValue = m_oLightReader.GetText();
|
||
else
|
||
nStart = NSStringFinder::ToInt(m_oLightReader.GetText(), 1);
|
||
}
|
||
else if (L"disabled" == wsArgumentName)
|
||
oTSLiP.oAdditionalStyle.m_oText.SetColor(L"#808080", NEXT_LEVEL);
|
||
else if (L"selected" == wsArgumentName)
|
||
oTSLiP.oAdditionalStyle.m_oText.SetDecoration(L"underline", NEXT_LEVEL);
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
|
||
oTSLiP.nLi++;
|
||
|
||
if (!wsValue.empty())
|
||
{
|
||
OpenR(oXml);
|
||
OpenT(oXml);
|
||
oXml->WriteEncodeXmlString(wsValue);
|
||
CloseT(oXml);
|
||
CloseR(oXml);
|
||
}
|
||
|
||
readStream(oXml, sSelectors, oTSLiP);
|
||
|
||
CloseP(oXml, sSelectors);
|
||
|
||
sSelectors.pop_back();
|
||
}
|
||
// Нумерованный список
|
||
if(!bType)
|
||
{
|
||
const std::wstring wsStart(std::to_wstring(nStart));
|
||
m_oNumberXml.WriteString(L"<w:abstractNum w:abstractNumId=\"");
|
||
m_oNumberXml.WriteString(std::to_wstring(m_nNumberingId++));
|
||
m_oNumberXml.WriteString(L"\"><w:multiLevelType w:val=\"hybridMultilevel\"/><w:lvl w:ilvl=\"0\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%1.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"709\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"1\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%2.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"1429\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"2\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%3.\"/><w:lvlJc w:val=\"right\"/><w:pPr><w:ind w:left=\"2149\" w:hanging=\"180\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"3\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%4.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"2869\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"4\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%5.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"3589\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"5\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%6.\"/><w:lvlJc w:val=\"right\"/><w:pPr><w:ind w:left=\"4309\" w:hanging=\"180\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"6\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%7.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"5029\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"7\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%8.\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"5749\" w:hanging=\"360\"/></w:pPr></w:lvl><w:lvl w:ilvl=\"8\"><w:start w:val=\"");
|
||
m_oNumberXml.WriteString(wsStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"decimal\"/><w:isLgl w:val=\"false\"/><w:suff w:val=\"tab\"/><w:lvlText w:val=\"%9.\"/><w:lvlJc w:val=\"right\"/><w:pPr><w:ind w:left=\"6469\" w:hanging=\"180\"/></w:pPr></w:lvl></w:abstractNum>");
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool readA (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS, std::wstring& sNote)
|
||
{
|
||
std::wstring sRef;
|
||
std::wstring sAlt;
|
||
bool bCross = false;
|
||
std::wstring sFootnote;
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
std::wstring sName = m_oLightReader.GetName();
|
||
std::wstring sText = m_oLightReader.GetText();
|
||
if(sName == L"href")
|
||
{
|
||
sRef = sText;
|
||
if(sRef.find('#') != std::wstring::npos)
|
||
bCross = true;
|
||
}
|
||
else if(sName == L"name")
|
||
WriteBookmark(oXml, sText);
|
||
else if(sName == L"alt")
|
||
sAlt = sText;
|
||
else if (sName == L"style" && sText.find(L"mso-footnote-id") != std::wstring::npos)
|
||
sFootnote = sText.substr(sText.rfind(L':') + 1);
|
||
else if (sName == L"epub:type" && sText.find(L"noteref"))
|
||
sFootnote = L"href";
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
|
||
if(sNote.empty())
|
||
sNote = sRef;
|
||
|
||
if (bCross && sFootnote == L"href")
|
||
sFootnote = sRef.substr(sRef.find('#') + 1);
|
||
|
||
if (!OpenP(oXml))
|
||
CloseR(oXml);
|
||
else
|
||
wrP(oXml, sSelectors, oTS);
|
||
|
||
// Перекрестная ссылка внутри файла
|
||
if(bCross)
|
||
{
|
||
m_oState.m_bInHyperlink = true;
|
||
oXml->WriteString(L"<w:hyperlink w:tooltip=\"Current Document\" w:anchor=\"");
|
||
size_t nSharp = sRef.find('#');
|
||
if(nSharp == std::wstring::npos)
|
||
oXml->WriteString(NSFile::GetFileName(sRef));
|
||
else
|
||
oXml->WriteEncodeXmlString(sRef.c_str() + nSharp + 1);
|
||
}
|
||
// Внешняя ссылка
|
||
else
|
||
{
|
||
// Пишем рельсы
|
||
NSStringUtils::CStringBuilder* oRelationshipXml = &m_oDocXmlRels;
|
||
if (oXml == &m_oNoteXml)
|
||
oRelationshipXml = &m_oNoteXmlRels;
|
||
oRelationshipXml->WriteString(L"<Relationship Id=\"rHyp");
|
||
oRelationshipXml->WriteString(std::to_wstring(m_nHyperlinkId));
|
||
oRelationshipXml->WriteString(L"\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink\" Target=\"");
|
||
oRelationshipXml->WriteEncodeXmlString(sRef);
|
||
oRelationshipXml->WriteString(L"\" TargetMode=\"External\"/>");
|
||
|
||
m_oState.m_bInHyperlink = true;
|
||
// Пишем в document.xml
|
||
oXml->WriteString(L"<w:hyperlink w:tooltip=\"");
|
||
oXml->WriteEncodeXmlString(sNote);
|
||
oXml->WriteString(L"\" r:id=\"rHyp");
|
||
oXml->WriteString(std::to_wstring(m_nHyperlinkId++));
|
||
}
|
||
oXml->WriteString(L"\">");
|
||
|
||
if(!readStream(oXml, sSelectors, oTS))
|
||
{
|
||
OpenR(oXml);
|
||
wrRPr(oXml, sSelectors, oTS);
|
||
OpenT(oXml);
|
||
oXml->WriteEncodeXmlString(!sAlt.empty() ? sAlt : L" ");
|
||
CloseT(oXml);
|
||
CloseR(oXml);
|
||
}
|
||
|
||
if (m_oState.m_bInP)
|
||
{
|
||
if (m_oState.m_bInHyperlink)
|
||
{
|
||
CloseT(oXml);
|
||
CloseR(oXml);
|
||
oXml->WriteString(L"</w:hyperlink>");
|
||
m_oState.m_bInHyperlink = false;
|
||
}
|
||
|
||
bool bFootnote = false;
|
||
if (sSelectors.size() > 1)
|
||
{
|
||
const NSCSS::CNode& oNode = sSelectors[sSelectors.size() - 2];
|
||
bFootnote = oNode.m_wsName == L"p" && oNode.m_wsClass == L"MsoFootnoteText";
|
||
}
|
||
|
||
// Сноска
|
||
if (bCross && !sFootnote.empty())
|
||
{
|
||
if (!bFootnote)
|
||
{
|
||
std::wstring sFootnoteID = std::to_wstring(m_nFootnoteId++);
|
||
OpenR(oXml);
|
||
oXml->WriteString(L"<w:rPr><w:rStyle w:val=\"footnote\"/></w:rPr><w:footnoteReference w:id=\"");
|
||
oXml->WriteString(sFootnoteID);
|
||
oXml->WriteString(L"\"/>");
|
||
CloseR(oXml);
|
||
m_mFootnotes.insert(std::make_pair(sFootnote, sFootnoteID));
|
||
}
|
||
else
|
||
{
|
||
OpenR(oXml);
|
||
oXml->WriteString(L"<w:rPr><w:rStyle w:val=\"footnote\"/></w:rPr><w:footnoteRef/>");
|
||
CloseR(oXml);
|
||
}
|
||
}
|
||
|
||
// CloseP(oXml, sSelectors);
|
||
}
|
||
|
||
sNote.clear();
|
||
|
||
return true;
|
||
}
|
||
|
||
bool readBase64 (const std::wstring& sSrcM, std::wstring& sExtention)
|
||
{
|
||
bool bRes = false;
|
||
size_t nBase = sSrcM.find(L"/", 4);
|
||
nBase++;
|
||
|
||
size_t nEndBase = sSrcM.find(L";", nBase);
|
||
if (nEndBase == std::wstring::npos)
|
||
return bRes;
|
||
sExtention = sSrcM.substr(nBase, nEndBase - nBase);
|
||
if (sExtention == L"octet-stream")
|
||
sExtention = L"jpg";
|
||
|
||
if (NotValidExtension(sExtention))
|
||
return bRes;
|
||
|
||
nBase = sSrcM.find(L"base64", nEndBase);
|
||
if (nBase == std::wstring::npos)
|
||
return bRes;
|
||
|
||
int nOffset = nBase + 7;
|
||
int nSrcLen = (int)(sSrcM.length() - nBase + 1);
|
||
int nDecodeLen = NSBase64::Base64DecodeGetRequiredLength(nSrcLen);
|
||
if (nDecodeLen != 0)
|
||
{
|
||
BYTE* pImageData = new BYTE[nDecodeLen];
|
||
|
||
if (!pImageData || FALSE == NSBase64::Base64Decode(sSrcM.c_str() + nOffset, nSrcLen, pImageData, &nDecodeLen))
|
||
return bRes;
|
||
|
||
if (IsSVG(sExtention))
|
||
{
|
||
std::wstring wsSvg(pImageData, pImageData + nDecodeLen);
|
||
bRes = readSVG(wsSvg);
|
||
sExtention = L"png";
|
||
}
|
||
else
|
||
{
|
||
NSFile::CFileBinary oImageWriter;
|
||
std::wstring sImageName = std::to_wstring(m_arrImages.size()) + L'.' + sExtention;
|
||
|
||
if (oImageWriter.CreateFileW(m_sDst + L"/word/media/i" + sImageName))
|
||
bRes = oImageWriter.WriteFile(pImageData, (DWORD)nDecodeLen);
|
||
|
||
oImageWriter.CloseFile();
|
||
}
|
||
|
||
RELEASEARRAYOBJECTS(pImageData);
|
||
}
|
||
|
||
return bRes;
|
||
}
|
||
|
||
bool CopyImage (const std::wstring& wscSrc, const std::wstring& wsDst, bool bIsAllowExternalLocalFiles)
|
||
{
|
||
bool bRes = false;
|
||
bool bAllow = true;
|
||
|
||
std::wstring wsSrc = wscSrc;
|
||
if (!bIsAllowExternalLocalFiles)
|
||
{
|
||
wsSrc = NSSystemPath::NormalizePath(wsSrc);
|
||
std::wstring wsStartSrc = NSSystemPath::NormalizePath(m_sSrc);
|
||
bAllow = wsSrc.substr(0, wsStartSrc.length()) == wsStartSrc;
|
||
}
|
||
if (bAllow)
|
||
bRes = NSFile::CFileBinary::Copy(wsSrc, wsDst);
|
||
|
||
return bRes;
|
||
}
|
||
|
||
inline bool NotValidExtension(const std::wstring& sExtention)
|
||
{
|
||
return sExtention != L"bmp" && sExtention != L"emf" && sExtention != L"emz" && sExtention != L"eps" && sExtention != L"fpx" && sExtention != L"gif" &&
|
||
sExtention != L"jpe" && sExtention != L"jpeg" && sExtention != L"jpg" && sExtention != L"jfif" && sExtention != L"pct" && sExtention != L"pict" &&
|
||
sExtention != L"png" && sExtention != L"pntg" && sExtention != L"psd" && sExtention != L"qtif" && sExtention != L"sgi" && sExtention != L"wmz" &&
|
||
sExtention != L"tga" && sExtention != L"tpic" && sExtention != L"tiff" && sExtention != L"tif" && sExtention != L"wmf" && !IsSVG(sExtention);
|
||
}
|
||
|
||
void ImageAlternative(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS, const std::wstring& wsAlt, const std::wstring& wsSrc, const TImageData& oImageData)
|
||
{
|
||
m_oDocXmlRels.WriteString(L"<Relationship Id=\"rId");
|
||
m_oDocXmlRels.WriteString(std::to_wstring(m_nId));
|
||
m_oDocXmlRels.WriteString(L"\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" Target=\"");
|
||
m_oDocXmlRels.WriteEncodeXmlString(wsSrc);
|
||
m_oDocXmlRels.WriteString(L"\" TargetMode=\"External\"/>");
|
||
|
||
const bool bOpenedP{OpenP(oXml)};
|
||
|
||
WriteEmptyImage(oXml, (0 != oImageData.m_unWidth) ? oImageData.m_unWidth : DEFAULT_IMAGE_WIDTH, (0 != oImageData.m_unHeight) ? oImageData.m_unHeight : DEFAULT_IMAGE_HEIGHT, L"", wsAlt);
|
||
|
||
if (bOpenedP)
|
||
CloseP(oXml, sSelectors);
|
||
}
|
||
|
||
bool readImage (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS)
|
||
{
|
||
std::wstring wsAlt, sSrcM;
|
||
bool bRes = false;
|
||
TImageData oImageData;
|
||
|
||
#define READ_IMAGE_DATA(data) \
|
||
{ \
|
||
NSCSS::NSProperties::CDigit oDigit; \
|
||
if (oDigit.SetValue(m_oLightReader.GetText())) \
|
||
{ \
|
||
if (NSCSS::UnitMeasure::None == oDigit.GetUnitMeasure()) \
|
||
data = static_cast<int>(NSCSS::CUnitMeasureConverter::ConvertPx(oDigit.ToDouble(), NSCSS::Inch, 96) * 914400); \
|
||
else \
|
||
data = static_cast<int>(oDigit.ToDouble(NSCSS::Inch) * 914400); \
|
||
} \
|
||
}\
|
||
|
||
while (m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
const std::wstring wsName = m_oLightReader.GetName();
|
||
if (wsName == L"alt")
|
||
wsAlt = m_oLightReader.GetText();
|
||
else if (wsName == L"src")
|
||
sSrcM = m_oLightReader.GetText();
|
||
else if (wsName == L"width")
|
||
READ_IMAGE_DATA(oImageData.m_unWidth)
|
||
else if (wsName == L"height")
|
||
READ_IMAGE_DATA(oImageData.m_unHeight)
|
||
else if (wsName == L"hspace")
|
||
READ_IMAGE_DATA(oImageData.m_nHSpace)
|
||
else if (wsName == L"vspace")
|
||
READ_IMAGE_DATA(oImageData.m_nVSpace)
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
|
||
if (NULL != sSelectors.back().m_pCompiledStyle)
|
||
{
|
||
const NSCSS::NSProperties::CDigit& oWidth {sSelectors.back().m_pCompiledStyle->m_oDisplay.GetWidth() };
|
||
const NSCSS::NSProperties::CDigit& oHeight{sSelectors.back().m_pCompiledStyle->m_oDisplay.GetHeight()};
|
||
|
||
if (0 == oImageData.m_unWidth && !oWidth.Empty())
|
||
{
|
||
if (NSCSS::UnitMeasure::None == oWidth.GetUnitMeasure())
|
||
oImageData.m_unWidth = static_cast<int>(NSCSS::CUnitMeasureConverter::ConvertPx(oWidth.ToDouble(), NSCSS::Inch, 96) * 914400);
|
||
else
|
||
oImageData.m_unWidth = static_cast<int>(oWidth.ToDouble(NSCSS::Inch) * 914400);
|
||
}
|
||
|
||
if (0 == oImageData.m_unHeight && !oHeight.Empty())
|
||
{
|
||
if (NSCSS::UnitMeasure::None == oHeight.GetUnitMeasure())
|
||
oImageData.m_unHeight = static_cast<int>(NSCSS::CUnitMeasureConverter::ConvertPx(oHeight.ToDouble(), NSCSS::Inch, 96) * 914400);
|
||
else
|
||
oImageData.m_unHeight = static_cast<int>(oHeight.ToDouble(NSCSS::Inch) * 914400);
|
||
}
|
||
}
|
||
|
||
if (sSrcM.empty())
|
||
{
|
||
ImageAlternative(oXml, sSelectors, oTS, wsAlt, sSrcM, oImageData);
|
||
return true;
|
||
}
|
||
|
||
std::wstring sExtention;
|
||
|
||
// Предполагаем картинку в Base64
|
||
if (sSrcM.length() > 4 && sSrcM.substr(0, 4) == L"data" && sSrcM.find(L"/", 4) != std::wstring::npos)
|
||
bRes = readBase64(sSrcM, sExtention);
|
||
|
||
const bool bIsAllowExternalLocalFiles = GetStatusUsingExternalLocalFiles();
|
||
|
||
if (!bRes && (sSrcM.length() <= 7 || L"http" != sSrcM.substr(0, 4)))
|
||
{
|
||
sSrcM = NSSystemPath::ShortenPath(sSrcM);
|
||
|
||
if (!CanUseThisPath(sSrcM, m_sSrc, m_sCore, bIsAllowExternalLocalFiles))
|
||
{
|
||
ImageAlternative(oXml, sSelectors, oTS, wsAlt, sSrcM, oImageData);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// Проверка расширения
|
||
if (!bRes)
|
||
{
|
||
sExtention = NSFile::GetFileExtention(sSrcM);
|
||
std::transform(sExtention.begin(), sExtention.end(), sExtention.begin(), tolower);
|
||
|
||
std::wstring::const_iterator itFound = std::find_if(sExtention.cbegin(), sExtention.cend(), [](wchar_t wChar){ return !iswalpha(wChar) && L'+' != wChar; });
|
||
|
||
if (sExtention.cend() != itFound)
|
||
sExtention.erase(itFound, sExtention.cend());
|
||
}
|
||
|
||
// Предполагаем картинку в сети
|
||
if (!bRes &&
|
||
((!m_sBase.empty() && m_sBase.length() > 4 && m_sBase.substr(0, 4) == L"http") ||
|
||
(sSrcM.length() > 4 && sSrcM.substr(0, 4) == L"http")))
|
||
{
|
||
const std::wstring wsDst = m_sDst + L"/word/media/i" + std::to_wstring(m_arrImages.size()) + L'.' + ((!sExtention.empty()) ? sExtention : L"png");
|
||
|
||
// Проверка gc_allowNetworkRequest предполагается в kernel_network
|
||
NSNetwork::NSFileTransport::CFileDownloader oDownloadImg(m_sBase + sSrcM, false);
|
||
oDownloadImg.SetFilePath(wsDst);
|
||
bRes = oDownloadImg.DownloadSync();
|
||
|
||
if (!bRes)
|
||
{
|
||
ImageAlternative(oXml, sSelectors, oTS, wsAlt, sSrcM, oImageData);
|
||
return true;
|
||
}
|
||
|
||
if (IsSVG(sExtention))
|
||
{
|
||
std::wstring wsFileData;
|
||
|
||
if (!NSFile::CFileBinary::ReadAllTextUtf8(wsDst, wsFileData) || !readSVG(wsFileData))
|
||
bRes = false;
|
||
|
||
NSFile::CFileBinary::Remove(wsDst);
|
||
sExtention = L"png";
|
||
}
|
||
else if (sExtention.empty())
|
||
{
|
||
//TODO:: лучше узнавать формат изображения из содержимого
|
||
sExtention = L"png";
|
||
}
|
||
}
|
||
|
||
int nImageId = -1;
|
||
|
||
if (!bRes)
|
||
{
|
||
if (NotValidExtension(sExtention))
|
||
{
|
||
ImageAlternative(oXml, sSelectors, oTS, wsAlt, sSrcM, oImageData);
|
||
return true;
|
||
}
|
||
|
||
// Проверка на повтор
|
||
std::vector<std::wstring>::iterator nFind = std::find(m_arrImages.begin(), m_arrImages.end(), sSrcM);
|
||
if (nFind != m_arrImages.end())
|
||
{
|
||
bRes = true;
|
||
nImageId = nFind - m_arrImages.begin();
|
||
}
|
||
}
|
||
|
||
// Предполагаем картинку по локальному пути
|
||
if (!bRes)
|
||
{
|
||
const std::wstring wsDst = m_sDst + L"/word/media/i" + std::to_wstring(m_arrImages.size()) + L'.' + sExtention;
|
||
|
||
if (!m_sBase.empty())
|
||
{
|
||
if (!bRes)
|
||
bRes = CopyImage(NSSystemPath::Combine(m_sBase, sSrcM), wsDst, bIsAllowExternalLocalFiles);
|
||
if (!bRes)
|
||
bRes = CopyImage(NSSystemPath::Combine(m_sSrc, m_sBase + sSrcM), wsDst, bIsAllowExternalLocalFiles);
|
||
}
|
||
if (!bRes)
|
||
bRes = CopyImage(NSSystemPath::Combine(m_sSrc, sSrcM), wsDst, bIsAllowExternalLocalFiles);
|
||
if (!bRes)
|
||
bRes = CopyImage(m_sSrc + L"/" + NSFile::GetFileName(sSrcM), wsDst, bIsAllowExternalLocalFiles);
|
||
if (!bRes)
|
||
bRes = CopyImage(sSrcM, wsDst, bIsAllowExternalLocalFiles);
|
||
}
|
||
|
||
if (!bRes)
|
||
ImageAlternative(oXml, sSelectors, oTS, wsAlt, sSrcM, oImageData);
|
||
else
|
||
{
|
||
wrP(oXml, sSelectors, oTS);
|
||
ImageRels(oXml, nImageId, sSrcM, sExtention, oImageData);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
std::wstring wrP(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, CTextSettings& oTS)
|
||
{
|
||
OpenP(oXml);
|
||
|
||
if (m_oState.m_bWasPStyle)
|
||
return L"";
|
||
|
||
std::wstring sPStyle = GetStyle(*sSelectors.back().m_pCompiledStyle, true);
|
||
|
||
if (sPStyle.empty() && !ElementInTable(sSelectors))
|
||
sPStyle = L"normal-web";
|
||
|
||
if (sPStyle.empty() && oTS.sPStyle.empty() && 0 > oTS.nLi)
|
||
return L"";
|
||
|
||
m_oXmlStyle.WriteLitePStyle(oTS.oAdditionalStyle);
|
||
const std::wstring sPSettings = m_oXmlStyle.GetStyle();
|
||
m_oXmlStyle.Clear();
|
||
|
||
oXml->WriteNodeBegin(L"w:pPr");
|
||
|
||
if (!sPStyle.empty())
|
||
{
|
||
oXml->WriteString(L"<w:pStyle w:val=\"");
|
||
oXml->WriteString(sPStyle);
|
||
oXml->WriteString(L"\"/>");
|
||
}
|
||
|
||
if (oTS.nLi >= 0)
|
||
oXml->WriteString(L"<w:numPr><w:ilvl w:val=\"" + std::to_wstring(oTS.nLi) + L"\"/><w:numId w:val=\"" +
|
||
(!oTS.bNumberingLi ? L"1" : std::to_wstring(m_nNumberingId)) + L"\"/></w:numPr>");
|
||
|
||
oXml->WriteString(oTS.sPStyle + sPSettings);
|
||
oXml->WriteNodeEnd(L"w:pPr");
|
||
m_oState.m_bWasPStyle = true;
|
||
|
||
return sPStyle;
|
||
}
|
||
|
||
std::wstring wrRPr(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS)
|
||
{
|
||
if (!m_oState.m_bInP)
|
||
return L"";
|
||
|
||
std::wstring sRStyle = GetStyle(*sSelectors.back().m_pCompiledStyle, false);
|
||
|
||
m_oXmlStyle.WriteLiteRStyle(oTS.oAdditionalStyle);
|
||
const std::wstring sRSettings = m_oXmlStyle.GetStyle();
|
||
m_oXmlStyle.Clear();
|
||
|
||
std::wstring wsFontSize;
|
||
|
||
const int nCalculatedFontChange{CalculateFontChange(sSelectors)};
|
||
|
||
if (0 != nCalculatedFontChange)
|
||
{
|
||
int nFontSizeLevel{static_cast<int>((sSelectors.back().m_pCompiledStyle->m_oFont.Empty()) ? 3 : GetFontSizeLevel(sSelectors.back().m_pCompiledStyle->m_oFont.GetSize().ToInt(NSCSS::Point) * 2))};
|
||
|
||
nFontSizeLevel += nCalculatedFontChange;
|
||
|
||
const UINT unFontSize{GetFontSizeByLevel(nFontSizeLevel)};
|
||
|
||
wsFontSize += L"<w:sz w:val=\"" + std::to_wstring(unFontSize) + L"\"/><w:szCs w:val=\"" + std::to_wstring(unFontSize) + L"\"/>";
|
||
}
|
||
|
||
if (!sRStyle.empty() || CTextSettings::Normal != oTS.eTextMode || !wsFontSize.empty() || !sRSettings.empty())
|
||
{
|
||
oXml->WriteString(L"<w:rPr>");
|
||
if (!sRStyle.empty())
|
||
{
|
||
oXml->WriteString(L"<w:rStyle w:val=\"");
|
||
oXml->WriteString(sRStyle);
|
||
oXml->WriteString(L"\"/>");
|
||
}
|
||
|
||
switch (oTS.eTextMode)
|
||
{
|
||
case CTextSettings::Subscript:
|
||
{
|
||
oXml->WriteString(L"<w:vertAlign w:val=\"subscript\"/>");
|
||
break;
|
||
}
|
||
case CTextSettings::Superscript:
|
||
{
|
||
oXml->WriteString(L"<w:vertAlign w:val=\"superscript\"/>");
|
||
break;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
|
||
oXml->WriteString(sRSettings + wsFontSize);
|
||
oXml->WriteString(L"</w:rPr>");
|
||
}
|
||
return sRStyle;
|
||
}
|
||
|
||
void WriteImage(NSStringUtils::CStringBuilder* pXml, const TImageData& oImageData, const std::wstring& wsId)
|
||
{
|
||
if (NULL == pXml)
|
||
return;
|
||
|
||
OpenR(pXml);
|
||
|
||
// Пишем в document.xml
|
||
if (oImageData.ZeroSpaces())
|
||
{
|
||
pXml->WriteString(L"<w:drawing><wp:inline distT=\"0\" distB=\"0\" distL=\"0\" distR=\"0\"><wp:extent cx=\"");
|
||
pXml->WriteString(std::to_wstring(oImageData.m_unWidth));
|
||
pXml->WriteString(L"\" cy=\"");
|
||
pXml->WriteString(std::to_wstring(oImageData.m_unHeight));
|
||
pXml->WriteString(L"\"/><wp:docPr id=\"");
|
||
pXml->WriteString(wsId);
|
||
pXml->WriteString(L"\" name=\"Picture " + wsId + L"\"/><a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"><a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"><pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"><pic:nvPicPr><pic:cNvPr id=\"");
|
||
pXml->WriteString(wsId);
|
||
pXml->WriteString(L"\" name=\"Picture " + wsId + L"\"/><pic:cNvPicPr></pic:cNvPicPr></pic:nvPicPr><pic:blipFill><a:blip r:embed=\"rPic");
|
||
pXml->WriteString(wsId);
|
||
pXml->WriteString(L"\"/><a:stretch/></pic:blipFill><pic:spPr bwMode=\"auto\"><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"");
|
||
pXml->WriteString(std::to_wstring(oImageData.m_unWidth));
|
||
pXml->WriteString(L"\" cy=\"");
|
||
pXml->WriteString(std::to_wstring(oImageData.m_unHeight));
|
||
pXml->WriteString(L"\"/></a:xfrm><a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing>");
|
||
}
|
||
else
|
||
{
|
||
pXml->WriteString(L"<w:rPr><w:noProof/></w:rPr><w:drawing>");
|
||
pXml->WriteString(L"<wp:anchor distT=\"" + std::to_wstring(oImageData.m_nHSpace) + L"\" distB=\"" + std::to_wstring(oImageData.m_nHSpace) + L"\" distL=\"" + std::to_wstring(oImageData.m_nVSpace) + L"\" distR=\"" + std::to_wstring(oImageData.m_nVSpace) + L"\" simplePos=\"0\" relativeHeight=\"251658240\" behindDoc=\"0\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"0\">");
|
||
pXml->WriteString(L"<wp:simplePos x=\"0\" y=\"0\"/>");
|
||
pXml->WriteString(L"<wp:positionH relativeFrom=\"column\"><wp:align>" + oImageData.m_wsAlign + L"</wp:align></wp:positionH>");
|
||
pXml->WriteString(L"<wp:positionV relativeFrom=\"line\"><wp:posOffset>0</wp:posOffset></wp:positionV>");
|
||
pXml->WriteString(L"<wp:extent cx=\"" + std::to_wstring(oImageData.m_unWidth) + L"\" cy=\"" + std::to_wstring(oImageData.m_unHeight) + L"\"/>");
|
||
pXml->WriteString(L"<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>");
|
||
pXml->WriteString(L"<wp:wrapSquare wrapText=\"bothSides\"/>");
|
||
pXml->WriteString(L"<wp:docPr id=\"" + wsId + L"\" name=\"Picture " + wsId + L"\"/>");
|
||
pXml->WriteString(L"<wp:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" noChangeAspect=\"1\"/></wp:cNvGraphicFramePr>");
|
||
pXml->WriteString(L"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">");
|
||
pXml->WriteString(L"<a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">");
|
||
pXml->WriteString(L"<pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">");
|
||
pXml->WriteString(L"<pic:nvPicPr><pic:cNvPr id=\"" + wsId + L"\" name=\"Picture " + wsId + L"\"/>");
|
||
pXml->WriteString(L"<pic:cNvPicPr><a:picLocks noChangeAspect=\"1\" noChangeArrowheads=\"1\"/></pic:cNvPicPr></pic:nvPicPr>");
|
||
pXml->WriteString(L"<pic:blipFill><a:blip r:link=\"rPic" + wsId + 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>");
|
||
pXml->WriteString(L"<pic:spPr bwMode=\"auto\"><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"" + std::to_wstring(oImageData.m_unWidth) + L"\" cy=\"" + std::to_wstring(oImageData.m_unHeight) + L"\"/></a:xfrm>");
|
||
pXml->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>");
|
||
pXml->WriteString(L"<wp14:sizeRelH relativeFrom=\"page\"><wp14:pctWidth>0</wp14:pctWidth></wp14:sizeRelH><wp14:sizeRelV relativeFrom=\"page\"><wp14:pctHeight>0</wp14:pctHeight></wp14:sizeRelV>");
|
||
pXml->WriteString(L"</wp:anchor></w:drawing>");
|
||
}
|
||
|
||
CloseR(pXml);
|
||
}
|
||
|
||
#define WRITE_ENCODE_ARGUMENT(ptrStringBuilder, argumentName, argumentValue) \
|
||
ptrStringBuilder->WriteString(L" " + std::wstring(argumentName) + L"=\""); \
|
||
ptrStringBuilder->WriteEncodeXmlString(argumentValue); \
|
||
ptrStringBuilder->WriteString(L"\"")
|
||
|
||
void WriteEmptyImage(NSStringUtils::CStringBuilder* pXml, int nWidth, int nHeight, const std::wstring& wsName = L"", const std::wstring& wsDescr = L"")
|
||
{
|
||
if (NULL == pXml)
|
||
return;
|
||
|
||
OpenR(pXml);
|
||
|
||
pXml->WriteString(L"<w:rPr><w:noProof/></w:rPr><w:drawing><wp:inline distT=\"0\" distB=\"0\" distL=\"0\" distR=\"0\"><wp:extent cx=\"" + std::to_wstring(nWidth) + L"\" cy=\"" + std::to_wstring(nHeight) + L"\"/><wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>");
|
||
pXml->WriteString(L"<wp:docPr id=\"" + std::to_wstring(m_nId - 7) + L"\"");
|
||
WRITE_ENCODE_ARGUMENT(pXml, L"name", wsName);
|
||
WRITE_ENCODE_ARGUMENT(pXml, L"descr", wsDescr);
|
||
pXml->WriteString(L"/>");
|
||
pXml->WriteString(L"<wp:cNvGraphicFramePr><a:graphicFrameLocks xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" noChangeAspect=\"1\"/></wp:cNvGraphicFramePr>");
|
||
pXml->WriteString(L"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"><a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\"><pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">");
|
||
pXml->WriteString(L"<pic:nvPicPr><pic:cNvPr id=\"0\"");
|
||
WRITE_ENCODE_ARGUMENT(pXml, L"name", wsName);
|
||
WRITE_ENCODE_ARGUMENT(pXml, L"descr", wsDescr);
|
||
pXml->WriteString(L"/>");
|
||
pXml->WriteString(L"<pic:cNvPicPr><a:picLocks noChangeAspect=\"1\" noChangeArrowheads=\"1\"/></pic:cNvPicPr></pic:nvPicPr>");
|
||
pXml->WriteString(L"<pic:blipFill><a:blip r:link=\"rId" + std::to_wstring(m_nId++) + 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>");
|
||
pXml->WriteString(L"<pic:spPr bwMode=\"auto\"><a:xfrm><a:off x=\"0\" y=\"0\"/><a:ext cx=\"" + std::to_wstring(nWidth) + L"\" cy=\"" + std::to_wstring(nHeight) + L"\"/></a:xfrm><a:prstGeom prst=\"rect\"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln></pic:spPr>");
|
||
pXml->WriteString(L"</pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing>");
|
||
|
||
CloseR(pXml);
|
||
}
|
||
|
||
void ImageRels (NSStringUtils::CStringBuilder* oXml, int nImageId, const std::wstring& sImageSrc, const std::wstring& sExtention, const TImageData& oImageData = TImageData())
|
||
{
|
||
bool bNew = nImageId < 0;
|
||
if (bNew)
|
||
nImageId = m_arrImages.size();
|
||
|
||
const std::wstring sImageId = std::to_wstring(nImageId);
|
||
const std::wstring sImageName = sImageId + L'.' + sExtention;
|
||
|
||
CBgraFrame oBgraFrame;
|
||
if (!oBgraFrame.OpenFile(m_sDst + L"/word/media/i" + sImageName))
|
||
{
|
||
NSFile::CFileBinary::Remove(m_sDst + L"/word/media/i" + sImageName);
|
||
return;
|
||
}
|
||
// Прописать рельсы
|
||
if (bNew)
|
||
{
|
||
m_arrImages.push_back(sImageSrc);
|
||
|
||
m_oDocXmlRels.WriteString(L"<Relationship Id=\"rPic");
|
||
m_oDocXmlRels.WriteString(sImageId);
|
||
m_oDocXmlRels.WriteString(L"\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" Target=\"media/i");
|
||
m_oDocXmlRels.WriteEncodeXmlString(sImageName);
|
||
m_oDocXmlRels.WriteString(L"\"/>");
|
||
}
|
||
|
||
if (!oImageData.ZeroSize())
|
||
return WriteImage(oXml, oImageData, sImageId);
|
||
|
||
TImageData oNewImageData{oImageData};
|
||
|
||
if (0 != oNewImageData.m_unWidth || 0 != oNewImageData.m_unHeight)
|
||
{
|
||
const double dMaxScale = std::max(oNewImageData.m_unWidth / oBgraFrame.get_Width(),
|
||
oNewImageData.m_unHeight / oBgraFrame.get_Height());
|
||
|
||
oNewImageData.m_unWidth = oBgraFrame.get_Width() * dMaxScale;
|
||
oNewImageData.m_unHeight = oBgraFrame.get_Height() * dMaxScale;
|
||
}
|
||
else
|
||
{
|
||
oNewImageData.m_unWidth = oBgraFrame.get_Width();
|
||
oNewImageData.m_unHeight = oBgraFrame.get_Height();
|
||
|
||
if (oNewImageData.m_unWidth > oNewImageData.m_unHeight)
|
||
{
|
||
int nW = oNewImageData.m_unWidth * 9525;
|
||
nW = (nW > 7000000 ? 7000000 : nW);
|
||
oNewImageData.m_unHeight = (int)((double)oNewImageData.m_unHeight * (double)nW / (double)oNewImageData.m_unWidth);
|
||
oNewImageData.m_unWidth = nW;
|
||
}
|
||
else
|
||
{
|
||
int nH = oNewImageData.m_unHeight * 9525;
|
||
nH = (nH > 8000000 ? 8000000 : nH);
|
||
int nW = (int)((double)oNewImageData.m_unWidth * (double)nH / (double)oNewImageData.m_unHeight);
|
||
if (nW > 7000000)
|
||
{
|
||
nW = 7000000;
|
||
oNewImageData.m_unHeight = (int)((double)oNewImageData.m_unHeight * (double)nW / (double)oNewImageData.m_unWidth);
|
||
}
|
||
else
|
||
oNewImageData.m_unHeight = nH;
|
||
oNewImageData.m_unWidth = nW;
|
||
}
|
||
}
|
||
|
||
WriteImage(oXml, oNewImageData, sImageId);
|
||
}
|
||
|
||
void readNote (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, std::wstring& sNote)
|
||
{
|
||
if(sNote.empty())
|
||
return;
|
||
|
||
OpenP(oXml);
|
||
|
||
oXml->WriteString(L"<w:r><w:rPr><w:rStyle w:val=\"footnote\"/></w:rPr><w:footnoteReference w:id=\"");
|
||
oXml->WriteString(std::to_wstring(m_nFootnoteId));
|
||
oXml->WriteString(L"\"/></w:r>");
|
||
m_oNoteXml.WriteString(L"<w:footnote w:id=\"");
|
||
m_oNoteXml.WriteString(std::to_wstring(m_nFootnoteId++));
|
||
m_oNoteXml.WriteString(L"\"><w:p><w:pPr><w:pStyle w:val=\"footnote-p\"/></w:pPr><w:r><w:rPr><w:rStyle w:val=\"footnote\"/></w:rPr><w:footnoteRef/></w:r><w:r><w:t xml:space=\"preserve\"> </w:t></w:r><w:r><w:t xml:space=\"preserve\">");
|
||
m_oNoteXml.WriteEncodeXmlString(sNote);
|
||
m_oNoteXml.WriteString(L"</w:t></w:r></w:p></w:footnote>");
|
||
|
||
sNote.clear();
|
||
}
|
||
|
||
bool readSVG (const std::wstring& wsSvg)
|
||
{
|
||
if (wsSvg.empty())
|
||
return false;
|
||
|
||
if (NULL == m_pFonts)
|
||
{
|
||
m_pFonts = NSFonts::NSApplication::Create();
|
||
|
||
if (NULL != m_pFonts)
|
||
m_pFonts->Initialize();
|
||
}
|
||
|
||
MetaFile::IMetaFile* pSvgReader = MetaFile::Create(m_pFonts);
|
||
if (!pSvgReader->LoadFromString(wsSvg))
|
||
{
|
||
RELEASEINTERFACE(pSvgReader);
|
||
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;
|
||
|
||
BYTE* pBgraData = (BYTE*)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 = (BYTE*)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);
|
||
|
||
// TODO: src directory as tmp - it's not good idea
|
||
pSvgReader->SetTempDirectory(m_sSrc);
|
||
pSvgReader->DrawOnRenderer(pGrRenderer, 0, 0, dWidth, dHeight);
|
||
|
||
oFrame.SaveFile(m_sDst + L"/word/media/i" + std::to_wstring(m_arrImages.size()) + L".png", 4);
|
||
oFrame.put_Data(NULL);
|
||
|
||
RELEASEINTERFACE(pGrRenderer);
|
||
|
||
if (pBgraData)
|
||
free(pBgraData);
|
||
|
||
RELEASEINTERFACE(pSvgReader);
|
||
|
||
return true;
|
||
}
|
||
};
|
||
|
||
CHtmlFile2::CHtmlFile2()
|
||
{
|
||
m_internal = new CHtmlFile2_Private();
|
||
}
|
||
|
||
CHtmlFile2::~CHtmlFile2()
|
||
{
|
||
RELEASEOBJECT(m_internal);
|
||
}
|
||
|
||
bool CHtmlFile2::IsHtmlFile(const std::wstring& sFile)
|
||
{
|
||
// Конвертируем в xhtml
|
||
if(!m_internal->htmlXhtml(sFile))
|
||
return false;
|
||
// Читаем html
|
||
return m_internal->isHtml();
|
||
}
|
||
|
||
bool CHtmlFile2::IsMhtFile(const std::wstring& sFile)
|
||
{
|
||
// Конвертируем в xhtml
|
||
if(!m_internal->mhtXhtml(sFile))
|
||
return false;
|
||
// Читаем html
|
||
return m_internal->isHtml();
|
||
}
|
||
|
||
void CHtmlFile2::SetTmpDirectory(const std::wstring& sFolder)
|
||
{
|
||
m_internal->m_sTmp = NSSystemPath::NormalizePath(sFolder);
|
||
}
|
||
|
||
void CHtmlFile2::SetCoreDirectory(const std::wstring& wsFolder)
|
||
{
|
||
m_internal->m_sCore = NSSystemPath::NormalizePath(wsFolder);
|
||
}
|
||
|
||
HRESULT CHtmlFile2::OpenHtml(const std::wstring& sSrc, const std::wstring& sDst, CHtmlParams* oParams)
|
||
{
|
||
if(!m_internal->m_oLightReader.IsValid())
|
||
if(!IsHtmlFile(sSrc))
|
||
return S_FALSE;
|
||
|
||
m_internal->m_sSrc = NSSystemPath::GetDirectoryName(sSrc);
|
||
m_internal->m_sDst = sDst;
|
||
m_internal->CreateDocxEmpty(oParams);
|
||
m_internal->readStyle();
|
||
|
||
// Переходим в начало
|
||
if(!m_internal->m_oLightReader.MoveToStart())
|
||
return S_FALSE;
|
||
|
||
if(oParams && oParams->m_bNeedPageBreakBefore)
|
||
m_internal->PageBreakBefore();
|
||
m_internal->readSrc();
|
||
m_internal->write();
|
||
return S_OK;
|
||
}
|
||
|
||
HRESULT CHtmlFile2::OpenMht(const std::wstring& sSrc, const std::wstring& sDst, CHtmlParams* oParams)
|
||
{
|
||
if(!m_internal->m_oLightReader.IsValid())
|
||
if(!IsMhtFile(sSrc))
|
||
return S_FALSE;
|
||
|
||
m_internal->m_sSrc = NSSystemPath::GetDirectoryName(sSrc);
|
||
m_internal->m_sDst = sDst;
|
||
m_internal->CreateDocxEmpty(oParams);
|
||
m_internal->readStyle();
|
||
|
||
// Переходим в начало
|
||
if(!m_internal->m_oLightReader.MoveToStart())
|
||
return S_FALSE;
|
||
|
||
if(oParams && oParams->m_bNeedPageBreakBefore)
|
||
m_internal->PageBreakBefore();
|
||
m_internal->readSrc();
|
||
m_internal->write();
|
||
return S_OK;
|
||
}
|
||
|
||
HRESULT CHtmlFile2::OpenBatchHtml(const std::vector<std::wstring>& sSrc, const std::wstring& sDst, CHtmlParams* oParams)
|
||
{
|
||
m_internal->m_sDst = sDst;
|
||
m_internal->CreateDocxEmpty(oParams);
|
||
bool bFirst = true;
|
||
|
||
for(const std::wstring& sS : sSrc)
|
||
{
|
||
#ifdef _DEBUG
|
||
std::wcout << NSFile::GetFileName(sS) << std::endl;
|
||
#endif
|
||
|
||
m_internal->m_sSrc = NSSystemPath::GetDirectoryName(sS);
|
||
if(!IsHtmlFile(sS))
|
||
continue;
|
||
m_internal->readStyle();
|
||
|
||
// Переходим в начало
|
||
if(m_internal->m_oLightReader.MoveToStart())
|
||
{
|
||
if(oParams && oParams->m_bNeedPageBreakBefore && !bFirst)
|
||
m_internal->PageBreakBefore();
|
||
bFirst = false;
|
||
m_internal->readSrc();
|
||
m_internal->m_oLightReader.Clear();
|
||
m_internal->m_sBase.clear();
|
||
}
|
||
|
||
// Очищаем разрешенные файлы стилей
|
||
// Это необходимо, чтобы мы не могли взять стили из не подключенного файла, но при этом, чтобы данные оставались,
|
||
// т.к. ко многим файлам может быть подключен один и тот же файл (проблема возникает когда он большой)
|
||
// и подключать (в нашем случае заново парсить) его будет долго
|
||
m_internal->m_oStylesCalculator.ClearAllowedStyleFiles();
|
||
m_internal->m_oStylesCalculator.ClearEmbeddedStyles();
|
||
}
|
||
|
||
m_internal->write();
|
||
return S_OK;
|
||
}
|
||
|
||
std::wstring CTableRow::ConvertToOOXML(const CTable& oTable, int nInstruction)
|
||
{
|
||
if (m_arCells.empty())
|
||
return std::wstring();
|
||
|
||
NSStringUtils::CStringBuilder oRow;
|
||
oRow.WriteNodeBegin(L"w:tr");
|
||
|
||
const TTableStyles oTableStyles{oTable.GetTableStyles()};
|
||
|
||
if (!m_oStyles.Empty() || 0 < oTableStyles.m_nCellSpacing)
|
||
{
|
||
oRow.WriteNodeBegin(L"w:trPr");
|
||
|
||
if (m_oStyles.m_bIsHeader)
|
||
oRow += L"<w:tblHeader/>";
|
||
|
||
if (0 < m_oStyles.m_unMaxHeight)
|
||
oRow += L"<w:trHeight w:val=\"" + std::to_wstring(m_oStyles.m_unMaxHeight) + L"\"/>";
|
||
|
||
if (0 < oTableStyles.m_nCellSpacing)
|
||
oRow += L"<w:tblCellSpacing w:w=\"" + std::to_wstring(oTableStyles.m_nCellSpacing) + L"\" w:type=\"dxa\"/>";
|
||
|
||
oRow.WriteNodeEnd(L"w:trPr");
|
||
}
|
||
|
||
for (UINT unIndex = 0; unIndex < m_arCells.size(); ++unIndex)
|
||
{
|
||
int nNewInstruction{nInstruction};
|
||
|
||
if (0 == unIndex)
|
||
nNewInstruction |= FIRST_ELEMENT;
|
||
if (m_arCells.size() - 1 == unIndex)
|
||
nNewInstruction |= LAST_ELEMENT;
|
||
else if (0 != unIndex)
|
||
nNewInstruction |= MID_ELEMENT;
|
||
|
||
oRow += m_arCells[unIndex]->ConvertToOOXML(oTable, unIndex, nNewInstruction);
|
||
}
|
||
|
||
oRow.WriteNodeEnd(L"w:tr");
|
||
|
||
return oRow.GetData();
|
||
}
|
||
|
||
std::wstring CTableCell::ConvertToOOXML(const CTable& oTable, UINT unColumnNumber, int nInstruction)
|
||
{
|
||
NSStringUtils::CStringBuilder oCell;
|
||
|
||
oCell.WriteNodeBegin(L"w:tc");
|
||
oCell.WriteNodeBegin(L"w:tcPr");
|
||
|
||
if (PARSE_MODE_HEADER == (nInstruction & PARSE_MODE_MASK))
|
||
oCell += L"<w:tblHeader/>";
|
||
|
||
TTableCellStyle oCellStyle(m_oStyles);
|
||
|
||
const TTableCellStyle* pColStyle = oTable.GetColStyle(unColumnNumber);
|
||
|
||
if (NULL != pColStyle)
|
||
oCellStyle += pColStyle;
|
||
|
||
if (!oCellStyle.m_oWidth.Empty())
|
||
{
|
||
if (NSCSS::UnitMeasure::Percent == oCellStyle.m_oWidth.GetUnitMeasure())
|
||
oCell += L"<w:tcW w:w=\"" + std::to_wstring(oCellStyle.m_oWidth.ToInt(NSCSS::UnitMeasure::Percent, 5000)) + L"\" w:type=\"pct\"/>";
|
||
else
|
||
{
|
||
if (!oCellStyle.m_oWidth.Zero())
|
||
{
|
||
int nWidth;
|
||
if (NSCSS::UnitMeasure::None != oCellStyle.m_oWidth.GetUnitMeasure())
|
||
nWidth = oCellStyle.m_oWidth.ToInt(NSCSS::UnitMeasure::Twips);
|
||
else
|
||
nWidth = static_cast<int>(NSCSS::CUnitMeasureConverter::ConvertPx(oCellStyle.m_oWidth.ToDouble(), NSCSS::UnitMeasure::Twips, 96) + 0.5);
|
||
|
||
oCell += L"<w:tcW w:w=\"" + std::to_wstring(nWidth) + L"\" w:type=\"dxa\"/>";
|
||
}
|
||
else
|
||
oCell += L"<w:tcW w:w=\"6\" w:type=\"dxa\"/>";
|
||
}
|
||
}
|
||
else
|
||
oCell += L"<w:tcW w:w=\"0\" w:type=\"auto\"/>";
|
||
|
||
if (1 != m_unColspan)
|
||
oCell += L"<w:gridSpan w:val=\"" + std::to_wstring(m_unColspan) + L"\"/>";
|
||
|
||
if (m_bIsMerged)
|
||
oCell += L"<w:vMerge w:val=\"continue\"/>";
|
||
else if (1 < m_unRowSpan)
|
||
oCell += L"<w:vMerge w:val=\"restart\"/>";
|
||
|
||
const TTableStyles oTableStyles{oTable.GetTableStyles()};
|
||
|
||
if (!oCellStyle.m_oBorder.Empty() && !oCellStyle.m_oBorder.Zero() /*&& oCellStyle.m_oBorder != oTableStyles.m_oBorder*/)
|
||
oCell += L"<w:tcBorders>" + CreateBorders(oCellStyle.m_oBorder, &oCellStyle.m_oPadding) + L"</w:tcBorders>";
|
||
else if (TTableStyles::ETableRules::Groups == oTable.GetTableStyles().m_enRules)
|
||
{
|
||
std::wstring wsBorders;
|
||
|
||
if (oTable.HaveColgroups())
|
||
wsBorders += oTable.CalculateSidesToClean(unColumnNumber);
|
||
|
||
if (PARSE_MODE_HEADER == (nInstruction & PARSE_MODE_MASK) && (((nInstruction & ROW_POSITION_MASK) >> 4) & LAST_ELEMENT))
|
||
wsBorders += CreateDefaultBorder(L"bottom");
|
||
else if (PARSE_MODE_FOOTHER == (nInstruction & PARSE_MODE_MASK) && (((nInstruction & ROW_POSITION_MASK) >> 4) & FIRST_ELEMENT))
|
||
wsBorders += CreateDefaultBorder(L"top");
|
||
|
||
if (!wsBorders.empty())
|
||
oCell += L"<w:tcBorders>" + wsBorders + L"</w:tcBorders>";
|
||
}
|
||
|
||
if (!oCellStyle.m_oBackground.Empty())
|
||
{
|
||
const std::wstring wsShdFill{(NSCSS::NSProperties::ColorNone == oCellStyle.m_oBackground.GetType()) ? L"auto" : oCellStyle.m_oBackground.ToWString()};
|
||
oCell += L"<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"" + wsShdFill + L"\"/>";
|
||
}
|
||
|
||
if (!oCellStyle.m_wsVAlign.empty())
|
||
oCell += L"<w:vAlign w:val=\"" + oCellStyle.m_wsVAlign + L"\"/>";
|
||
else
|
||
oCell += L"<w:vAlign w:val=\"center\"/>";
|
||
|
||
if (!oCellStyle.m_oPadding.Empty() && oTableStyles.m_oPadding != oCellStyle.m_oPadding)
|
||
{
|
||
const int nTopPadding = std::max(oTableStyles.m_oPadding.GetTop() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_HEIGHT),
|
||
oCellStyle .m_oPadding.GetTop() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_HEIGHT));
|
||
const int nLeftPadding = std::max(oTableStyles.m_oPadding.GetLeft() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_WIDTH),
|
||
oCellStyle .m_oPadding.GetLeft() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_WIDTH));
|
||
const int nBottomPadding = std::max(oTableStyles.m_oPadding.GetBottom().ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_HEIGHT),
|
||
oCellStyle .m_oPadding.GetBottom().ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_HEIGHT));
|
||
const int nRightPadding = std::max(oTableStyles.m_oPadding.GetRight() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_WIDTH),
|
||
oCellStyle .m_oPadding.GetRight() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_WIDTH));
|
||
|
||
oCell += L"<w:tcMar>"
|
||
"<w:top w:w=\"" + std::to_wstring(nTopPadding) + L"\" w:type=\"dxa\"/>"
|
||
"<w:left w:w=\"" + std::to_wstring(nLeftPadding) + L"\" w:type=\"dxa\"/>"
|
||
"<w:bottom w:w=\"" + std::to_wstring(nBottomPadding) + L"\" w:type=\"dxa\"/>"
|
||
"<w:right w:w=\"" + std::to_wstring(nRightPadding) + L"\" w:type=\"dxa\"/>"
|
||
"</w:tcMar>";
|
||
}
|
||
|
||
oCell += L"<w:hideMark/>";
|
||
oCell.WriteNodeEnd(L"w:tcPr");
|
||
|
||
if (0 != m_oData.GetCurSize())
|
||
oCell += m_oData.GetData();
|
||
else
|
||
WriteEmptyParagraph(&oCell);
|
||
|
||
oCell.WriteNodeEnd(L"w:tc");
|
||
|
||
return oCell.GetData();
|
||
}
|