mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 14:00:32 +08:00
3343 lines
124 KiB
C++
3343 lines
124 KiB
C++
#include "htmlfile2.h"
|
||
|
||
#include <string>
|
||
#include <cwctype>
|
||
#include <map>
|
||
#include <vector>
|
||
#include <algorithm>
|
||
#include <iostream>
|
||
#include <fstream>
|
||
#include <iterator>
|
||
|
||
#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 "../DesktopEditor/raster/Metafile/svg/CSvgFile.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 SAVE_NORMALIZED_HTML 0
|
||
|
||
std::wstring rStyle = L" a area b strong bdo bdi big br center cite dfn em i var code kbd samp tt del s font img ins u mark q rt sup small sub svg input basefont button label data object noscript output abbr time ruby progress hgroup meter span acronym ";
|
||
|
||
// Ячейка таблицы
|
||
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 bAddSpaces; // Добавлять пробелы перед текстом?
|
||
bool bMergeText; // Объединять подяр идущий текст в 1?
|
||
int nLi; // Уровень списка
|
||
std::wstring sRStyle; // w:rStyle
|
||
std::wstring sPStyle; // w:pStyle
|
||
|
||
CTextSettings(bool _bBdo, bool _bPre, bool _bAddSpaces, bool _bMergeText, int _nLi, const std::wstring& _sRStyle, const std::wstring& _sPStyle) :
|
||
bBdo(_bBdo), bPre(_bPre), bAddSpaces(_bAddSpaces), bMergeText(_bMergeText), nLi(_nLi), sRStyle(_sRStyle), sPStyle(_sPStyle)
|
||
{}
|
||
|
||
CTextSettings(const CTextSettings& oTS) :
|
||
bBdo(oTS.bBdo), bPre(oTS.bPre), bAddSpaces(oTS.bAddSpaces), bMergeText(oTS.bMergeText), nLi(oTS.nLi), sRStyle(oTS.sRStyle), sPStyle(oTS.sPStyle)
|
||
{}
|
||
|
||
void AddRStyle(const std::wstring& wsStyle)
|
||
{
|
||
if (std::wstring::npos == sRStyle.find(wsStyle))
|
||
sRStyle += wsStyle;
|
||
}
|
||
|
||
void AddPStyle(const std::wstring& wsStyle)
|
||
{
|
||
if (std::wstring::npos == sPStyle.find(wsStyle))
|
||
sPStyle += wsStyle;
|
||
}
|
||
};
|
||
|
||
std::wstring CreateBorders(const NSCSS::NSProperties::CBorder& oBorder, const NSCSS::NSProperties::CIndent* pPadding = NULL)
|
||
{
|
||
if (oBorder.EqualSides() && (NULL == pPadding || pPadding->Equals()))
|
||
{
|
||
const std::wstring wsBorderStyle = NSCSS::CDocumentStyle::CalculateBorderStyle(oBorder.GetLeftBorder(), ((NULL == pPadding) ? NULL : (&(pPadding->GetLeft()))));
|
||
|
||
return L"<w:top " + wsBorderStyle + L"/>" +
|
||
L"<w:left " + wsBorderStyle + L"/>" +
|
||
L"<w:bottom " + wsBorderStyle + L"/>" +
|
||
L"<w:right " + wsBorderStyle + L"/>";
|
||
}
|
||
else
|
||
{
|
||
std::wstring wsTable;
|
||
|
||
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"/>";
|
||
|
||
return wsTable;
|
||
}
|
||
|
||
return L"";
|
||
}
|
||
|
||
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>");
|
||
}
|
||
|
||
void WriteLine(NSStringUtils::CStringBuilder* pXml, double dHeight, const std::wstring& wsColor)
|
||
{
|
||
pXml->WriteNodeBegin(L"w:pict");
|
||
pXml->WriteString(L"<v:rect style=\"width:0;height:" + std::to_wstring(dHeight) + L"pt\" o:hralign=\"center\" o:hrstd=\"t\" o:hr=\"t\" fillcolor=\"#" + wsColor + L"\" stroked=\"f\"/>");
|
||
pXml->WriteNodeEnd(L"w:pict");
|
||
}
|
||
|
||
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; });
|
||
}
|
||
|
||
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;
|
||
bool m_bHaveBorderAttribute;
|
||
|
||
std::wstring m_wsAlign;
|
||
|
||
TTableStyles()
|
||
: m_nCellSpacing(-1), m_bHaveBorderAttribute(false)
|
||
{}
|
||
|
||
bool Empty() const
|
||
{
|
||
return m_oPadding.Empty() && m_oMargin.Empty() && m_oBorder.Empty() && m_oWidth.Empty() && -1 == m_nCellSpacing && false == m_bHaveBorderAttribute && m_wsAlign.empty();
|
||
}
|
||
};
|
||
|
||
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;
|
||
}
|
||
};
|
||
|
||
class CTableCell
|
||
{
|
||
public:
|
||
CTableCell()
|
||
: m_unColspan(1), m_unRowSpan(1), m_bIsMerged(false), m_bIsEmpty(false), m_enMode(ParseModeBody)
|
||
{}
|
||
|
||
CTableCell(UINT unColspan, UINT unRowspan, bool bIsMerged, bool bIsEmpty)
|
||
: m_unColspan(unColspan), m_unRowSpan(unRowspan), m_bIsMerged(bIsMerged), m_bIsEmpty(bIsEmpty), m_enMode(ParseModeBody)
|
||
{}
|
||
|
||
CTableCell(CTableCell& oCell)
|
||
: m_unColspan(oCell.m_unColspan), m_unRowSpan(oCell.m_unRowSpan), m_bIsMerged(oCell.m_bIsMerged),
|
||
m_bIsEmpty(oCell.m_bIsEmpty), m_enMode(oCell.m_enMode), m_oStyles(oCell.m_oStyles)
|
||
{
|
||
m_oData.SetText(oCell.m_oData.GetData());
|
||
}
|
||
|
||
bool Empty()
|
||
{
|
||
return m_bIsEmpty;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
void SetMode(ERowParseMode eMode)
|
||
{
|
||
m_enMode = eMode;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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 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 TTableStyles& oTableStyles)
|
||
{
|
||
NSStringUtils::CStringBuilder oCell;
|
||
|
||
oCell.WriteNodeBegin(L"w:tc");
|
||
oCell.WriteNodeBegin(L"w:tcPr");
|
||
|
||
if (ParseModeHeader == m_enMode)
|
||
oCell += L"<w:tblHeader/>";
|
||
|
||
if (!m_oStyles.m_oWidth.Empty())
|
||
{
|
||
if (NSCSS::UnitMeasure::Percent == m_oStyles.m_oWidth.GetUnitMeasure())
|
||
oCell += L"<w:tcW w:w=\"" + std::to_wstring(m_oStyles.m_oWidth.ToInt(NSCSS::UnitMeasure::Percent, 5000)) + L"\" w:type=\"pct\"/>";
|
||
else
|
||
{
|
||
if (!m_oStyles.m_oWidth.Zero())
|
||
{
|
||
int nWidth;
|
||
if (NSCSS::UnitMeasure::None != m_oStyles.m_oWidth.GetUnitMeasure())
|
||
nWidth = m_oStyles.m_oWidth.ToInt(NSCSS::UnitMeasure::Twips);
|
||
else
|
||
nWidth = static_cast<int>(NSCSS::CUnitMeasureConverter::ConvertPx(m_oStyles.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\"/>";
|
||
|
||
if (!m_oStyles.m_oBorder.Zero() && !m_oStyles.m_oBorder.Empty())
|
||
oCell += L"<w:tcBorders>" + CreateBorders(m_oStyles.m_oBorder) + L"</w:tcBorders>";
|
||
else if (oTableStyles.m_bHaveBorderAttribute)
|
||
oCell += L"<w:tcBorders><w:top w:val=\"outset\" w:sz=\"6\" w:space=\"0\" w:color=\"auto\"/><w:left w:val=\"outset\" w:sz=\"6\" w:space=\"0\" w:color=\"auto\"/><w:bottom w:val=\"outset\" w:sz=\"6\" w:space=\"0\" w:color=\"auto\"/><w:right w:val=\"outset\" w:sz=\"6\" w:space=\"0\" w:color=\"auto\"/></w:tcBorders>";
|
||
|
||
if (!m_oStyles.m_oBackground.Empty())
|
||
{
|
||
const std::wstring wsShdFill{(NSCSS::NSProperties::ColorNone == m_oStyles.m_oBackground.GetType()) ? L"auto" : m_oStyles.m_oBackground.ToWString()};
|
||
oCell += L"<w:shd w:val=\"clear\" w:color=\"auto\" w:fill=\"" + wsShdFill + L"\"/>";
|
||
}
|
||
|
||
if (!m_oStyles.m_wsVAlign.empty())
|
||
oCell += L"<w:vAlign w:val=\"" + m_oStyles.m_wsVAlign + L"\"/>";
|
||
else
|
||
oCell += L"<w:vAlign w:val=\"center\"/>";
|
||
|
||
if (!m_oStyles.m_oPadding.Empty() && oTableStyles.m_oPadding != m_oStyles.m_oPadding)
|
||
{
|
||
const int nTopPadding = std::max(oTableStyles.m_oPadding.GetTop() .ToInt(NSCSS::UnitMeasure::Twips, DEFAULT_PAGE_HEIGHT),
|
||
m_oStyles .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),
|
||
m_oStyles .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),
|
||
m_oStyles .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),
|
||
m_oStyles .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();
|
||
}
|
||
|
||
private:
|
||
UINT m_unColspan;
|
||
UINT m_unRowSpan;
|
||
|
||
bool m_bIsMerged;
|
||
bool m_bIsEmpty;
|
||
ERowParseMode m_enMode;
|
||
|
||
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(); });
|
||
|
||
if (m_arCells.end() != itFoundEmpty)
|
||
{
|
||
--m_oStyles.m_unMaxIndex;
|
||
delete *itFoundEmpty;
|
||
*itFoundEmpty = pCell;
|
||
|
||
if (1 != pCell->GetColspan())
|
||
{
|
||
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())
|
||
{
|
||
UINT unDeleteCount = pCell->GetColspan() - 1;
|
||
while (m_arCells[nPosition]->Empty() && nPosition < m_arCells.size() && 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 TTableStyles& oTableStyles)
|
||
{
|
||
if (m_arCells.empty())
|
||
return std::wstring();
|
||
|
||
NSStringUtils::CStringBuilder oRow;
|
||
oRow.WriteNodeBegin(L"w:tr");
|
||
|
||
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 (CTableCell* pCell : m_arCells)
|
||
oRow += pCell->ConvertToOOXML(oTableStyles);
|
||
|
||
oRow.WriteNodeEnd(L"w:tr");
|
||
|
||
return oRow.GetData();
|
||
}
|
||
|
||
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 CTable
|
||
{
|
||
public:
|
||
CTable()
|
||
{}
|
||
|
||
~CTable()
|
||
{
|
||
for (CTableRow* pRow : m_arRows)
|
||
RELEASEOBJECT(pRow);
|
||
}
|
||
|
||
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();
|
||
}
|
||
|
||
UINT GetRowCount() const
|
||
{
|
||
return m_arRows.size();
|
||
}
|
||
|
||
void AddRow(CTableRow* pRow)
|
||
{
|
||
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();
|
||
}
|
||
|
||
m_arRows.push_back(pRow);
|
||
}
|
||
|
||
void AddCaption(NSStringUtils::CStringBuilder& oCaption)
|
||
{
|
||
m_oCaption += oCaption.GetData();
|
||
}
|
||
|
||
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 HaveBorderAttribute()
|
||
{
|
||
m_oStyles.m_bHaveBorderAttribute = true;
|
||
}
|
||
|
||
bool IsHaveBorderAttribute() const
|
||
{
|
||
return m_oStyles.m_bHaveBorderAttribute;
|
||
}
|
||
|
||
UINT GetMaxColumns()
|
||
{
|
||
UINT unMaxColumns = 0;
|
||
|
||
for (const CTableRow* pRow : m_arRows)
|
||
unMaxColumns = std::max(unMaxColumns, pRow->GetIndex());
|
||
|
||
return unMaxColumns;
|
||
}
|
||
|
||
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() && unIndex + pCell->GetColspan() > m_arMinColspan[unIndex])
|
||
{
|
||
pCell->SetColspan(m_arMinColspan[unIndex] - 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)
|
||
{
|
||
for (UINT unIndex = pRow->GetIndex(); unIndex < unMaxIndex; ++unIndex)
|
||
pRow->InsertCell(CTableCell::CreateEmpty(), unIndex);
|
||
}
|
||
}
|
||
|
||
std::wstring ConvertToOOXML()
|
||
{
|
||
if (m_arRows.empty())
|
||
return std::wstring();
|
||
|
||
NSStringUtils::CStringBuilder oTable;
|
||
|
||
oTable.WriteNodeBegin(L"w:tbl");
|
||
oTable.WriteNodeBegin(L"w:tblPr");
|
||
|
||
if (!m_oStyles.m_oWidth.Empty() && !m_oStyles.m_oWidth.Zero())
|
||
{
|
||
if (NSCSS::UnitMeasure::Percent == m_oStyles.m_oWidth.GetUnitMeasure())
|
||
oTable += L"<w:tblW w:w=\"" + std::to_wstring(m_oStyles.m_oWidth.ToInt(NSCSS::UnitMeasure::Percent, 5000)) + L"\" w:type=\"pct\"/>";
|
||
else
|
||
oTable += L"<w:tblInd w:w=\"" + std::to_wstring(m_oStyles.m_oWidth.ToInt(NSCSS::UnitMeasure::Twips)) + L"\" w:type=\"dxa\"/>";
|
||
}
|
||
else
|
||
oTable += 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())
|
||
oTable += L"<w:tblInd w:w=\"" + std::to_wstring(m_oStyles.m_oMargin.GetLeft().ToInt(NSCSS::UnitMeasure::Percent, 5000)) + L"\" w:type=\"pct\"/>";
|
||
else
|
||
oTable += 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())
|
||
oTable += 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)
|
||
oTable += 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())
|
||
oTable += L"<w:tblBorders>" + CreateBorders(m_oStyles.m_oBorder) + 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 ));
|
||
|
||
oTable.WriteNodeBegin(L"w:tblCellMar");
|
||
|
||
if (0 != nTopPadding)
|
||
oTable += L"<w:top w:w=\"" + std::to_wstring(nTopPadding) + L"\" w:type=\"dxa\"/>";
|
||
|
||
if (0 != nLeftPadding)
|
||
oTable += L"<w:left w:w=\"" + std::to_wstring(nLeftPadding) + L"\" w:type=\"dxa\"/>";
|
||
|
||
if (0 != nBottomPadding)
|
||
oTable += L"<w:bottom w:w=\"" + std::to_wstring(nBottomPadding) + L"\" w:type=\"dxa\"/>";
|
||
|
||
if (0 != nRightPadding)
|
||
oTable += L"<w:right w:w=\"" + std::to_wstring(nRightPadding) + L"\" w:type=\"dxa\"/>";
|
||
|
||
oTable.WriteNodeEnd(L"w:tblCellMar");
|
||
}
|
||
else
|
||
oTable += 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>";
|
||
|
||
oTable += L"<w:tblLook w:val=\"04A0\" w:noVBand=\"1\" w:noHBand=\"0\" w:lastColumn=\"0\" w:firstColumn=\"1\" w:lastRow=\"0\" w:firstRow=\"1\"/>";
|
||
oTable.WriteNodeEnd(L"w:tblPr");
|
||
|
||
if (HaveCaption())
|
||
{
|
||
oTable.WriteNodeBegin(L"w:tr");
|
||
oTable.WriteNodeBegin(L"w:tc");
|
||
oTable.WriteNodeBegin(L"w:tcPr");
|
||
oTable += L"<w:tcW w:w=\"0\" w:type=\"auto\"/>";
|
||
oTable += L"<w:gridSpan w:val=\"" + std::to_wstring(GetMaxColumns()) + L"\"/>";
|
||
oTable += 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>";
|
||
oTable += L"<w:vAlign w:val=\"center\"/>";
|
||
oTable += L"<w:hideMark/>";
|
||
oTable.WriteNodeEnd(L"w:tcPr");
|
||
oTable.WriteString(m_oCaption.GetData());
|
||
oTable.WriteNodeEnd(L"w:tc");
|
||
oTable.WriteNodeEnd(L"w:tr");
|
||
}
|
||
|
||
for (CTableRow* pRow : m_arRows)
|
||
oTable += pRow->ConvertToOOXML(m_oStyles);
|
||
|
||
oTable.WriteNodeEnd(L"w:tbl");
|
||
|
||
return oTable.GetData();
|
||
}
|
||
private:
|
||
std::vector<CTableRow*> m_arRows;
|
||
std::vector<UINT> m_arMinColspan;
|
||
|
||
NSStringUtils::CStringBuilder m_oCaption;
|
||
|
||
TTableStyles m_oStyles;
|
||
};
|
||
|
||
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 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, bool bIsAllowExternalLocalFiles)
|
||
{
|
||
if (bIsAllowExternalLocalFiles)
|
||
return true;
|
||
|
||
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; // Полный базовый адрес
|
||
|
||
NSCSS::CTree m_oTree; // Дерево body html-файла
|
||
|
||
private:
|
||
int m_nFootnoteId; // ID сноски
|
||
int m_nHyperlinkId; // ID ссылки
|
||
int m_nNumberingId; // ID списка
|
||
int m_nId; // ID остальные элементы
|
||
|
||
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
|
||
|
||
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> открыт?
|
||
|
||
TState()
|
||
: m_bInP(false), m_bInR(false), m_bInT(false), m_bWasPStyle(false), m_bWasSpace(true), m_bInHyperlink(false)
|
||
{}
|
||
} m_oState;
|
||
|
||
std::vector<std::wstring> m_arrImages; // Картинки
|
||
std::map<std::wstring, std::wstring> m_mFootnotes; // Сноски
|
||
std::map<std::wstring, UINT> m_mBookmarks; // Закладки
|
||
public:
|
||
|
||
CHtmlFile2_Private()
|
||
: m_nFootnoteId(1), m_nHyperlinkId(1), m_nNumberingId(1), m_nId(1)
|
||
{
|
||
m_oPageData.SetSize (std::to_wstring(DEFAULT_PAGE_WIDTH) + L"tw " + std::to_wstring(DEFAULT_PAGE_HEIGHT) + L"tw", 0, true);
|
||
m_oPageData.SetMargin(L"1440tw 1440tw 1440tw 1440tw", 0, true);
|
||
m_oPageData.SetFooter(L"720tw", 0, true);
|
||
m_oPageData.SetHeader(L"720tw", 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();
|
||
}
|
||
|
||
// Проверяет наличие тэга 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: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();
|
||
}
|
||
|
||
// webSettings.xml
|
||
std::wstring sWebSettings = L"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><w:webSettings xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"><w:optimizeForBrowser/></w:webSettings>";
|
||
NSFile::CFileBinary oWebWriter;
|
||
if (oWebWriter.CreateFileW(m_sDst + L"/word/webSettings.xml"))
|
||
{
|
||
oWebWriter.WriteStringUTF8(sWebSettings);
|
||
oWebWriter.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_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>";
|
||
|
||
// 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>";
|
||
}
|
||
|
||
// Читает файл
|
||
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();
|
||
}
|
||
|
||
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();
|
||
}
|
||
}
|
||
|
||
// Конвертирует 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");
|
||
}
|
||
|
||
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::FindPropety(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(m_oTree);
|
||
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(NSCSS::CTree& oTree)
|
||
{
|
||
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());
|
||
|
||
oTree.m_oNode.m_wsName = sName;
|
||
// Стиль по атрибуту
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
std::wstring sNameA = m_oLightReader.GetName();
|
||
if(sNameA == L"class")
|
||
oTree.m_oNode.m_wsClass = m_oLightReader.GetText();
|
||
else if(sNameA == L"id")
|
||
oTree.m_oNode.m_wsId = m_oLightReader.GetText();
|
||
else if(sNameA == L"style")
|
||
oTree.m_oNode.m_wsStyle += m_oLightReader.GetText();
|
||
else
|
||
oTree.m_oNode.m_mAttributes[sNameA] = m_oLightReader.GetText();
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while(m_oLightReader.ReadNextSiblingNode(nDeath))
|
||
{
|
||
if(!m_oLightReader.IsEmptyNode())
|
||
{
|
||
NSCSS::CTree oChildTree;
|
||
readStyle2(oChildTree);
|
||
oTree.m_arrChild.push_back(oChildTree);
|
||
}
|
||
}
|
||
}
|
||
|
||
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 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 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);
|
||
}
|
||
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);
|
||
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"\"/>");
|
||
*/
|
||
|
||
readStream(&m_oDocXml, sSelectors, { false, false, true, false, -1, L"", L"" });
|
||
}
|
||
|
||
bool readInside (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS, const std::wstring& sName)
|
||
{
|
||
//TODO:: обработать все варианты return'а
|
||
|
||
if(sName == L"#text")
|
||
{
|
||
std::wstring sText = m_oLightReader.GetText();
|
||
|
||
if (sText.end() == std::find_if_not(sText.begin(), sText.end(), [](wchar_t wchChar){ return iswspace(wchChar);}))
|
||
return false;
|
||
|
||
bool bInT = m_oState.m_bInT;
|
||
|
||
if (!oTS.sRStyle.empty() || oTS.bPre)
|
||
{
|
||
CloseT(oXml);
|
||
CloseR(oXml);
|
||
}
|
||
|
||
if (oTS.bAddSpaces && m_oState.m_bInP && !m_oState.m_bInR && !iswspace(sText.front()) && !m_oState.m_bWasSpace)
|
||
{
|
||
oXml->WriteString(L"<w:r><w:rPr><w:rFonts w:eastAsia=\"Times New Roman\"/></w:rPr><w:t xml:space=\"preserve\"> </w:t></w:r>");
|
||
m_oState.m_bWasSpace = true;
|
||
}
|
||
|
||
std::wstring sPStyle = wrP(oXml, sSelectors, oTS);
|
||
std::wstring sRStyle;
|
||
|
||
if (OpenR(oXml))
|
||
{
|
||
sRStyle = wrRPr(oXml, sSelectors, oTS);
|
||
OpenT(oXml);
|
||
}
|
||
|
||
if(oTS.bBdo)
|
||
std::reverse(sText.begin(), sText.end());
|
||
|
||
if(oTS.bPre)
|
||
{
|
||
size_t nAfter = sText.find_first_of(L"\n\r");
|
||
while(nAfter != std::wstring::npos)
|
||
{
|
||
oXml->WriteEncodeXmlString(sText.c_str(), nAfter);
|
||
oXml->WriteString(L"</w:t></w:r></w:p><w:p>");
|
||
if(!sPStyle.empty() || !oTS.sPStyle.empty())
|
||
{
|
||
oXml->WriteNodeBegin(L"w:pPr");
|
||
|
||
if (!sPStyle.empty())
|
||
oXml->WriteString(L"<w:pStyle w:val=\"" + sPStyle + L"\"/>");
|
||
|
||
oXml->WriteString(oTS.sPStyle);
|
||
|
||
oXml->WriteNodeEnd(L"w:pPr");
|
||
}
|
||
oXml->WriteNodeBegin(L"w:r");
|
||
if (!sRStyle.empty() || !oTS.sRStyle.empty())
|
||
{
|
||
oXml->WriteNodeBegin(L"w:rPr");
|
||
|
||
if (!sRStyle.empty())
|
||
oXml->WriteString(L"<w:rStyle w:val=\"" + sRStyle + L"\"/>");
|
||
|
||
oXml->WriteString(oTS.sRStyle);
|
||
|
||
oXml->WriteNodeEnd(L"w:rPr");
|
||
}
|
||
oXml->WriteString(L"<w:t xml:space=\"preserve\">");
|
||
sText.erase(0, nAfter + 1);
|
||
nAfter = sText.find_first_of(L"\n\r");
|
||
}
|
||
|
||
if (sText.empty())
|
||
return true;
|
||
}
|
||
else
|
||
ReplaceSpaces(sText);
|
||
|
||
if (std::iswspace(sText.front()) && m_oState.m_bWasSpace)
|
||
sText.erase(0, 1);
|
||
|
||
if (oTS.bMergeText && !m_oState.m_bWasSpace && bInT)
|
||
oXml->WriteEncodeXmlString(L" ");
|
||
|
||
if (!sText.empty())
|
||
m_oState.m_bWasSpace = std::iswspace(sText.back());
|
||
|
||
oXml->WriteEncodeXmlString(sText);
|
||
|
||
if (!oTS.bMergeText)
|
||
{
|
||
CloseT(oXml);
|
||
CloseR(oXml);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
std::wstring sNote = GetSubClass(oXml, sSelectors);
|
||
bool bResult = true;
|
||
// Ссылка
|
||
// Область ссылки
|
||
if(sName == L"a" || sName == L"area")
|
||
readA(oXml, sSelectors, oTS, sNote);
|
||
// Полужирный текст
|
||
// Акцентированный текст
|
||
else if(sName == L"b" || sName == L"strong")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:b/><w:bCs/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
// Направление текста
|
||
else if(sName == L"bdo")
|
||
{
|
||
std::wstring sDir;
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
if(m_oLightReader.GetName() == L"dir")
|
||
sDir = m_oLightReader.GetText();
|
||
m_oLightReader.MoveToElement();
|
||
|
||
CTextSettings oTSBdo(oTS);
|
||
oTSBdo.bBdo = (sDir == L"rtl");
|
||
bResult = readStream(oXml, sSelectors, oTSBdo);
|
||
}
|
||
// Отмена направления текста
|
||
else if(sName == L"bdi")
|
||
{
|
||
CTextSettings oTSBdo(oTS);
|
||
oTSBdo.bBdo = false;
|
||
bResult = readStream(oXml, sSelectors, oTSBdo);
|
||
}
|
||
// Увеличивает размер шрифта
|
||
else if(sName == L"big")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:sz w:val=\"26\"/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
// Перенос строки
|
||
else if(sName == L"br")
|
||
{
|
||
if (m_oState.m_bInP)
|
||
{
|
||
oXml->WriteString(L"<w:r>");
|
||
NSCSS::CCompiledStyle oStyle = m_oStylesCalculator.GetCompiledStyle(sSelectors);
|
||
if(oStyle.m_oText.GetAlign() == L"both")
|
||
oXml->WriteString(L"<w:tab/>");
|
||
oXml->WriteString(L"<w:br/></w:r>");
|
||
}
|
||
else
|
||
WriteEmptyParagraph(oXml, false, m_oState.m_bInP);
|
||
|
||
m_oState.m_bWasSpace = true;
|
||
}
|
||
else if(sName == L"center")
|
||
{
|
||
CTextSettings oTSP(oTS);
|
||
oTSP.AddPStyle(L"<w:jc w:val=\"center\"/>");
|
||
bResult = readStream(oXml, sSelectors, oTSP);
|
||
}
|
||
// Цитата, обычно выделяется курсивом
|
||
// Новый термин, обычно выделяется курсивом
|
||
// Акцентированный текст
|
||
// Курсивный текст
|
||
// Переменная, обычно выделяется курсивом
|
||
else if(sName == L"cite" || sName == L"dfn" || sName == L"em" || sName == L"i" || sName == L"var")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:i/><w:iCs/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
// Код
|
||
// Моноширинный шрифт, например, Consolas
|
||
// Результат скрипта
|
||
else if(sName == L"code" || sName == L"kbd" || sName == L"samp" || sName == L"tt")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:rFonts w:ascii=\"Consolas\" w:hAnsi=\"Consolas\"/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
// Зачеркнутый текст
|
||
else if(sName == L"del" || sName == L"s")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:strike/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
else if(sName == L"font")
|
||
{
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
std::wstring sAName = m_oLightReader.GetName();
|
||
if(sAName == L"color")
|
||
sSelectors.back().m_wsStyle += L"; color: " + m_oLightReader.GetText();
|
||
else if(sAName == L"face")
|
||
sSelectors.back().m_wsStyle += L"; font-family: " + m_oLightReader.GetText();
|
||
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);
|
||
}
|
||
|
||
switch (nSize)
|
||
{
|
||
case 1: nSize = 10; break;
|
||
case 2: nSize = 12; break;
|
||
case 3:
|
||
default: nSize = 14; break;
|
||
case 4: nSize = 18; break;
|
||
case 5: nSize = 24; break;
|
||
case 6: nSize = 32; break;
|
||
case 7: nSize = 48; break;
|
||
}
|
||
|
||
sSelectors.back().m_wsStyle += L"; font-size: " + std::to_wstring(nSize) + L"px";
|
||
}
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
bResult = readStream(oXml, sSelectors, oTS);
|
||
}
|
||
// Картинки
|
||
else if(sName == L"img")
|
||
readImage(oXml, sSelectors, oTS);
|
||
// Подчеркнутый
|
||
else if(sName == L"ins" || sName == L"u")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:u w:val=\"single\"/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
// Выделенный текст, обычно выделяется желтым
|
||
else if(sName == L"mark")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:highlight w:val=\"yellow\"/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
// Цитата, выделенная кавычками, обычно выделяется курсивом
|
||
else if(sName == L"q")
|
||
{
|
||
wrP(oXml, sSelectors, oTS);
|
||
oXml->WriteString(L"<w:r>");
|
||
std::wstring sRStyle = wrRPr(oXml, sSelectors, oTS);
|
||
oXml->WriteString(L"<w:t xml:space=\"preserve\">"</w:t></w:r>");
|
||
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:i/><w:iCs/>");
|
||
readStream(oXml, sSelectors, oTSR);
|
||
|
||
wrP(oXml, sSelectors, oTS);
|
||
oXml->WriteString(L"<w:r>");
|
||
if (!sRStyle.empty())
|
||
{
|
||
oXml->WriteString(L"<w:rPr><w:rStyle w:val=\"");
|
||
oXml->WriteString(sRStyle);
|
||
oXml->WriteString(L"\"/>");
|
||
oXml->WriteString(oTS.sRStyle);
|
||
oXml->WriteString(L"</w:rPr>");
|
||
}
|
||
oXml->WriteString(L"<w:t xml:space=\"preserve\">"</w:t></w:r>");
|
||
}
|
||
// Текст верхнего регистра
|
||
else if(sName == L"rt" || sName == L"sup")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:vertAlign w:val=\"superscript\"/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
// Уменьшает размер шрифта
|
||
else if(sName == L"small")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:sz w:val=\"18\"/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
// Текст нижнего регистра
|
||
else if(sName == L"sub")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:vertAlign w:val=\"subscript\"/>");
|
||
bResult = readStream(oXml, sSelectors, oTSR);
|
||
}
|
||
// Векторная картинка
|
||
else if(sName == L"svg" || (sName.length() > 3 && sName.compare(sName.length() - 3, 3, L"svg") == 0))
|
||
{
|
||
wrP(oXml, sSelectors, oTS);
|
||
if (readSVG(m_oLightReader.GetOuterXml()))
|
||
ImageRels(oXml, -1, L"", L"png");
|
||
}
|
||
else if(sName == L"input")
|
||
readInput(oXml, sSelectors, oTS);
|
||
// Игнорируются тэги выполняющие скрипт
|
||
else if(sName == L"template" || sName == L"canvas" || sName == L"video" || sName == L"math" || sName == L"rp" ||
|
||
sName == L"command" || sName == L"iframe" || sName == L"embed" || sName == L"wbr" || sName == L"audio" ||
|
||
sName == L"bgsound" || sName == L"applet" || sName == L"blink" || sName == L"keygen"|| sName == L"script" ||
|
||
sName == L"comment" || sName == L"title" || sName == L"style")
|
||
{
|
||
WriteEmptyParagraph(oXml, false, m_oState.m_bInP);
|
||
sSelectors.pop_back();
|
||
return true;
|
||
}
|
||
else if (sName == L"span")
|
||
{
|
||
if (sSelectors.back().m_wsClass == L"MsoFootnoteReference")
|
||
{
|
||
sSelectors.pop_back();
|
||
return false;
|
||
}
|
||
bResult = readStream(oXml, sSelectors, oTS);
|
||
}
|
||
else if (sName == L"nobr")
|
||
{
|
||
CTextSettings oTSPre(oTS);
|
||
oTSPre.bPre = true;
|
||
bResult = readStream(oXml, sSelectors, oTSPre);
|
||
}
|
||
// Без нового абзаца
|
||
else if(sName == L"basefont" || sName == L"button" || sName == L"label" || sName == L"data" || sName == L"object" ||
|
||
sName == L"noscript" || sName == L"output" || sName == L"abbr" || sName == L"time" || sName == L"ruby" ||
|
||
sName == L"progress" || sName == L"hgroup" || sName == L"meter" || sName == L"acronym")
|
||
bResult = readStream(oXml, sSelectors, oTS);
|
||
// С нового абзаца
|
||
else
|
||
{
|
||
NSStringUtils::CStringBuilder oXmlData;
|
||
TState oCurentState{m_oState};
|
||
|
||
CloseP(&oXmlData, sSelectors);
|
||
|
||
// Адрес
|
||
if(sName == L"address")
|
||
{
|
||
CTextSettings oTSR(oTS);
|
||
oTSR.AddRStyle(L"<w:i/><w:iCs/>");
|
||
bResult = readStream(&oXmlData, sSelectors, oTSR);
|
||
}
|
||
// Определение термина, отступ от левого края
|
||
else if(sName == L"dd")
|
||
{
|
||
CTextSettings oTSP(oTS);
|
||
oTSP.sPStyle += L"<w:ind w:left=\"567\"/>";
|
||
bResult = readStream(&oXmlData, sSelectors, oTSP);
|
||
}
|
||
// aside возможно использовать для сносок в epub
|
||
else if (sName == L"aside" || sName == L"div")
|
||
{
|
||
m_oStylesCalculator.CalculatePageStyle(m_oPageData, sSelectors);
|
||
|
||
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, sSelectors, oTS);
|
||
m_oNoteXml.WriteString(L"</w:footnote>");
|
||
}
|
||
else
|
||
bResult = readStream(&oXmlData, sSelectors, oTS);
|
||
}
|
||
// С нового абзаца
|
||
else if(sName == L"article" || sName == L"header" || sName == L"blockquote" || sName == L"main" || sName == L"dir" ||
|
||
sName == L"summary" || sName == L"footer" || sName == L"nav" || sName == L"figcaption" || sName == L"form" ||
|
||
sName == L"details" || sName == L"option" || sName == L"dt" || sName == L"p" ||
|
||
sName == L"section" || sName == L"figure" || sName == L"dl" || sName == L"legend" || sName == L"map" ||
|
||
sName == L"h1" || sName == L"h2" || sName == L"h3" || sName == L"h4" || sName == L"h5" || sName == L"h6")
|
||
bResult = readStream(&oXmlData, sSelectors, oTS);
|
||
// Горизонтальная линия
|
||
else if(sName == L"hr")
|
||
{
|
||
bool bPrint = true;
|
||
for (const NSCSS::CNode& item : sSelectors)
|
||
{
|
||
if (item.m_wsName == L"div" && item.m_wsStyle == L"mso-element:footnote-list")
|
||
{
|
||
bPrint = false;
|
||
break;
|
||
}
|
||
}
|
||
if (bPrint)
|
||
{
|
||
const bool bOpenedP = OpenP(&oXmlData);
|
||
OpenR(&oXmlData);
|
||
WriteLine(&oXmlData, 1.5, L"a0a0a0");
|
||
CloseR(&oXmlData);
|
||
if (bOpenedP)
|
||
CloseP(&oXmlData, sSelectors);
|
||
}
|
||
// oXml->WriteString(L"<w:p><w:pPr><w:pBdr><w:bottom w:val=\"single\" w:color=\"000000\" w:sz=\"8\" w:space=\"0\"/></w:pBdr></w:pPr></w:p>");
|
||
}
|
||
// Меню
|
||
// Маркированный список
|
||
else if(sName == L"menu" || sName == L"ul" || sName == L"select" || sName == L"datalist")
|
||
readLi(&oXmlData, sSelectors, oTS, true);
|
||
// Нумерованный список
|
||
else if(sName == L"ol")
|
||
readLi(&oXmlData, sSelectors, oTS, false);
|
||
// Предварительно форматированный текст
|
||
else if(sName == L"pre" || sName == L"xmp")
|
||
{
|
||
CTextSettings oTSPre(oTS);
|
||
sSelectors.back().m_wsStyle += L"; font-family:Consolas";
|
||
oTSPre.bPre = true;
|
||
bResult = readStream(&oXmlData, sSelectors, oTSPre);
|
||
}
|
||
// Таблицы
|
||
else if(sName == L"table")
|
||
ParseTable(&oXmlData, sSelectors, oTS);
|
||
// Текст с границами
|
||
else if(sName == L"textarea" || sName == L"fieldset")
|
||
{
|
||
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>");
|
||
bResult = readStream(&oXmlData, sSelectors, oTSP);
|
||
}
|
||
else if (sName == L"xml")
|
||
{
|
||
sSelectors.pop_back();
|
||
return false;
|
||
}
|
||
// Неизвестный тэг. Выделять ли его абзацем?
|
||
else
|
||
bResult = readStream(&oXmlData, sSelectors, oTS);
|
||
|
||
readNote(&oXmlData, sSelectors, sNote);
|
||
sNote = L"";
|
||
|
||
CloseP(&oXmlData, sSelectors);
|
||
|
||
if (bResult)
|
||
oXml->WriteString(oXmlData.GetData());
|
||
else
|
||
m_oState = oCurentState;
|
||
}
|
||
readNote(oXml, sSelectors, sNote);
|
||
sSelectors.pop_back();
|
||
return bResult;
|
||
}
|
||
|
||
bool readStream (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const 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(CTableCell* pCell, const std::vector<NSCSS::CNode>& arSelectors)
|
||
{
|
||
if (NULL == pCell)
|
||
return;
|
||
|
||
std::vector<NSCSS::CNode> arNewSelectors{(std::vector<NSCSS::CNode>::const_iterator)std::find_if(arSelectors.begin(), arSelectors.end(), [](const NSCSS::CNode& oNode){ return L"table" == oNode.m_wsName; }), arSelectors.cend()};
|
||
|
||
NSCSS::CCompiledStyle oStyle;
|
||
m_oStylesCalculator.GetCompiledStyle(oStyle, arNewSelectors);
|
||
|
||
pCell->SetVAlign(oStyle.m_oDisplay.GetVAlign().ToWString());
|
||
pCell->SetHAlign(oStyle.m_oDisplay.GetHAlign().ToWString());
|
||
pCell->SetBackground(oStyle.m_oBackground.GetColor());
|
||
pCell->SetHeight(oStyle.m_oDisplay.GetHeight());
|
||
pCell->SetWidth(oStyle.m_oDisplay.GetWidth());
|
||
pCell->SetPadding(oStyle.m_oPadding);
|
||
pCell->SetBorder(oStyle.m_oBorder);
|
||
|
||
if (pCell->GetStyles()->m_wsHAlign.empty())
|
||
pCell->SetHAlign(oStyle.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;
|
||
}
|
||
|
||
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, const CTextSettings& oTS, ERowParseMode eMode)
|
||
{
|
||
std::vector<TRowspanElement> arRowspanElements;
|
||
|
||
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;
|
||
|
||
pCell->SetMode(eMode);
|
||
|
||
GetSubClass(pCell->GetData(), sSelectors);
|
||
CalculateCellStyles(pCell, sSelectors);
|
||
|
||
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.sPStyle += L"<w:jc w:val=\"center\"/>";
|
||
|
||
oTSR.AddRStyle(L"<w:b/><w:bCs/>");
|
||
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) && (L"td" == m_oLightReader.GetName() || L"th" == m_oLightReader.GetName()))
|
||
{
|
||
GetSubClass(pCell->GetData(), sSelectors);
|
||
readStream(pCell->GetData(), sSelectors, oTrTS, true);
|
||
sSelectors.pop_back();
|
||
}
|
||
}
|
||
CloseP(pCell->GetData(), sSelectors);
|
||
|
||
pRow->AddCell(pCell);
|
||
|
||
sSelectors.pop_back();
|
||
|
||
++unColumnIndex;
|
||
|
||
if (pRow->GetIndex() == MAXCOLUMNSINTABLE)
|
||
break;
|
||
}
|
||
|
||
sSelectors.pop_back();
|
||
|
||
oTable.AddRow(pRow);
|
||
}
|
||
}
|
||
|
||
void ParseTable(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS)
|
||
{
|
||
if(m_oLightReader.IsEmptyNode())
|
||
return;
|
||
|
||
CTable oTable;
|
||
|
||
//Table styles
|
||
if (sSelectors.back().m_mAttributes.end() != sSelectors.back().m_mAttributes.find(L"border"))
|
||
{
|
||
const int nWidth = NSStringFinder::ToInt(sSelectors.back().m_mAttributes[L"border"]);
|
||
|
||
if (0 < nWidth)
|
||
{
|
||
sSelectors.back().m_mAttributes[L"border"] = L"outset " + std::to_wstring(nWidth) + L"px auto";
|
||
oTable.HaveBorderAttribute();
|
||
}
|
||
else
|
||
sSelectors.back().m_mAttributes[L"border"] = L"none";
|
||
}
|
||
|
||
NSCSS::CCompiledStyle oStyle;
|
||
m_oStylesCalculator.GetCompiledStyle(oStyle, sSelectors);
|
||
|
||
if (sSelectors.back().m_mAttributes.end() != sSelectors.back().m_mAttributes.find(L"cellpadding"))
|
||
oStyle.m_oPadding.SetValues(sSelectors.back().m_mAttributes[L"cellpadding"] + L"px", 0, true);
|
||
|
||
if (oStyle.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 (oStyle.m_oBorder.GetCollapse() == NSCSS::NSProperties::BorderCollapse::Separate)
|
||
oTable.SetCellSpacing(15);
|
||
|
||
oTable.SetWidth(oStyle.m_oDisplay.GetWidth());
|
||
oTable.SetBorder(oStyle.m_oBorder);
|
||
oTable.SetPadding(oStyle.m_oPadding);
|
||
oTable.SetMargin(oStyle.m_oMargin);
|
||
oTable.SetAlign(oStyle.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, oTS, ERowParseMode::ParseModeHeader);
|
||
if(sName == L"tbody")
|
||
ParseTableRows(oTable, sSelectors, oTS, ERowParseMode::ParseModeBody);
|
||
else if(sName == L"tfoot")
|
||
ParseTableRows(oTable, sSelectors, oTS, ERowParseMode::ParseModeFoother);
|
||
|
||
sSelectors.pop_back();
|
||
}
|
||
|
||
oTable.Shorten();
|
||
oTable.CompleteTable();
|
||
oXml->WriteString(oTable.ConvertToOOXML());
|
||
WriteEmptyParagraph(oXml, true);
|
||
}
|
||
|
||
void readInput (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const 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;
|
||
if(sValue.empty())
|
||
sValue = sAlt;
|
||
if(!sValue.empty())
|
||
{
|
||
wrP(oXml, sSelectors, oTS);
|
||
oXml->WriteString(L"<w:r>");
|
||
wrRPr(oXml, sSelectors, oTS);
|
||
oXml->WriteString(L"<w:t xml:space=\"preserve\">");
|
||
oXml->WriteEncodeXmlString(sValue + L' ');
|
||
oXml->WriteString(L"</w:t></w:r>");
|
||
}
|
||
|
||
readStream(oXml, sSelectors, oTS, ElementInTable(sSelectors));
|
||
}
|
||
|
||
void readLi (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS, bool bType)
|
||
{
|
||
if(m_oLightReader.IsEmptyNode())
|
||
return;
|
||
|
||
std::wstring sStart = L"1";
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
if(m_oLightReader.GetName() == L"start")
|
||
sStart = m_oLightReader.GetText();
|
||
m_oLightReader.MoveToElement();
|
||
|
||
int nDeath = m_oLightReader.GetDepth();
|
||
while(m_oLightReader.ReadNextSiblingNode(nDeath))
|
||
{
|
||
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);
|
||
oXml->WriteString(L"<w:r>");
|
||
wrRPr(oXml, sSelectors, oTS);
|
||
oXml->WriteString(L"<w:t xml:space=\"preserve\">");
|
||
oXml->WriteEncodeXmlString(m_oLightReader.GetText());
|
||
oXml->WriteString(L"</w:t></w:r>");
|
||
}
|
||
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;
|
||
}
|
||
|
||
GetSubClass(oXml, sSelectors);
|
||
while(m_oLightReader.MoveToNextAttribute())
|
||
if(m_oLightReader.GetName() == L"value")
|
||
sStart = m_oLightReader.GetText();
|
||
m_oLightReader.MoveToElement();
|
||
|
||
CloseP(oXml, sSelectors);
|
||
|
||
CTextSettings oTSLiP(oTS);
|
||
oTSLiP.nLi++;
|
||
oTSLiP.sPStyle += L"<w:numPr><w:ilvl w:val=\"" + std::to_wstring(oTSLiP.nLi) + L"\"/><w:numId w:val=\"" +
|
||
(bType ? L"1" : std::to_wstring(m_nNumberingId + 1)) + L"\"/></w:numPr>";
|
||
readStream(oXml, sSelectors, oTSLiP);
|
||
|
||
CloseP(oXml, sSelectors);
|
||
|
||
sSelectors.pop_back();
|
||
}
|
||
// Нумерованный список
|
||
if(!bType)
|
||
{
|
||
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(sStart);
|
||
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(sStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"lowerLetter\"/><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(sStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"lowerRoman\"/><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(sStart);
|
||
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(sStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"lowerLetter\"/><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(sStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"lowerRoman\"/><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(sStart);
|
||
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(sStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"lowerLetter\"/><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(sStart);
|
||
m_oNumberXml.WriteString(L"\"/><w:numFmt w:val=\"lowerRoman\"/><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>");
|
||
}
|
||
}
|
||
|
||
void readA (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const 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);
|
||
|
||
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))
|
||
{
|
||
oXml->WriteString(L"<w:r>");
|
||
wrRPr(oXml, sSelectors, oTS);
|
||
oXml->WriteString(L"<w:t xml:space=\"preserve\">");
|
||
oXml->WriteEncodeXmlString(!sAlt.empty() ? sAlt : L" ");
|
||
oXml->WriteString(L"</w:t></w:r>");
|
||
}
|
||
|
||
if (m_oState.m_bInP)
|
||
{
|
||
if (m_oState.m_bInHyperlink)
|
||
{
|
||
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++);
|
||
oXml->WriteString(L"<w:r><w:rPr><w:rStyle w:val=\"footnote\"/></w:rPr><w:footnoteReference w:id=\"");
|
||
oXml->WriteString(sFootnoteID);
|
||
oXml->WriteString(L"\"/></w:r>");
|
||
m_mFootnotes.insert(std::make_pair(sFootnote, sFootnoteID));
|
||
}
|
||
else
|
||
oXml->WriteString(L"<w:r><w:rPr><w:rStyle w:val=\"footnote\"/></w:rPr><w:footnoteRef/></w:r>");
|
||
}
|
||
|
||
CloseP(oXml, sSelectors);
|
||
}
|
||
|
||
sNote.clear();
|
||
}
|
||
|
||
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 (L"svg" == sExtention || L"svg+xml" == 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"svg" &&
|
||
sExtention != L"tga" && sExtention != L"tpic" && sExtention != L"tiff" && sExtention != L"tif" && sExtention != L"wmf" && sExtention != L"wmz";
|
||
}
|
||
|
||
void ImageAlternative(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS, const std::wstring& wsAlt, const std::wstring& wsSrc)
|
||
{
|
||
if (wsAlt.empty())
|
||
{
|
||
//TODO:: реализовать отображение того, что картинку не удалось получить
|
||
if (wsSrc.empty())
|
||
WriteEmptyParagraph(oXml, false, m_oState.m_bInP);
|
||
else
|
||
{
|
||
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, 304800, 304800);
|
||
|
||
if (bOpenedP)
|
||
CloseP(oXml, sSelectors);
|
||
}
|
||
return;
|
||
}
|
||
|
||
wrP(oXml, sSelectors, oTS);
|
||
oXml->WriteString(L"<w:r>");
|
||
wrRPr(oXml, sSelectors, oTS);
|
||
oXml->WriteString(L"<w:t xml:space=\"preserve\">");
|
||
oXml->WriteEncodeXmlString(wsAlt);
|
||
oXml->WriteString(L"</w:t></w:r>");
|
||
}
|
||
|
||
void readImage (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS)
|
||
{
|
||
std::wstring wsAlt, sSrcM;
|
||
bool bRes = false;
|
||
while (m_oLightReader.MoveToNextAttribute())
|
||
{
|
||
std::wstring wsName = m_oLightReader.GetName();
|
||
if (wsName == L"alt")
|
||
wsAlt = m_oLightReader.GetText();
|
||
else if (wsName == L"src")
|
||
sSrcM = m_oLightReader.GetText();
|
||
}
|
||
m_oLightReader.MoveToElement();
|
||
|
||
if (sSrcM.empty())
|
||
{
|
||
ImageAlternative(oXml, sSelectors, oTS, wsAlt, sSrcM);
|
||
return;
|
||
}
|
||
|
||
const bool bIsAllowExternalLocalFiles = GetStatusUsingExternalLocalFiles();
|
||
|
||
bool bIsBase64 = false;
|
||
if (sSrcM.length() > 4 && sSrcM.substr(0, 4) == L"data" && sSrcM.find(L"/", 4) != std::wstring::npos)
|
||
bIsBase64 = true;
|
||
|
||
if (!bIsBase64 && (sSrcM.length() <= 7 || L"http" != sSrcM.substr(0, 4)))
|
||
{
|
||
sSrcM = NSSystemPath::ShortenPath(sSrcM);
|
||
|
||
if (!CanUseThisPath(sSrcM, bIsAllowExternalLocalFiles))
|
||
return;
|
||
}
|
||
|
||
int nImageId = -1;
|
||
std::wstring sImageSrc, sExtention;
|
||
// Предполагаем картинку в Base64
|
||
if (bIsBase64)
|
||
bRes = readBase64(sSrcM, sExtention);
|
||
|
||
if (!bRes)
|
||
{
|
||
// Проверка расширения
|
||
sExtention = NSFile::GetFileExtention(sSrcM);
|
||
std::transform(sExtention.begin(), sExtention.end(), sExtention.begin(), tolower);
|
||
if (NotValidExtension(sExtention))
|
||
{
|
||
ImageAlternative(oXml, sSelectors, oTS, wsAlt, sSrcM);
|
||
return;
|
||
}
|
||
|
||
// Проверка на повтор
|
||
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)
|
||
{
|
||
sImageSrc = sSrcM;
|
||
std::wstring wsDst = m_sDst + L"/word/media/i" + std::to_wstring(m_arrImages.size()) + L'.' + sExtention;
|
||
|
||
// Предполагаем картинку по локальному пути
|
||
if (!((!m_sBase.empty() && m_sBase.length() > 4 && m_sBase.substr(0, 4) == L"http") || (sSrcM.length() > 4 && sSrcM.substr(0, 4) == L"http")))
|
||
{
|
||
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);
|
||
}
|
||
// Предполагаем картинку в сети
|
||
else
|
||
{
|
||
// Проверка 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);
|
||
else
|
||
{
|
||
wrP(oXml, sSelectors, oTS);
|
||
ImageRels(oXml, nImageId, sImageSrc, sExtention);
|
||
}
|
||
}
|
||
|
||
std::wstring wrP(NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const CTextSettings& oTS)
|
||
{
|
||
OpenP(oXml);
|
||
|
||
if (m_oState.m_bWasPStyle)
|
||
return L"";
|
||
|
||
std::vector<std::pair<size_t, NSCSS::CNode>> temporary;
|
||
size_t i = 0;
|
||
while(i != sSelectors.size())
|
||
{
|
||
if (sSelectors[i].Empty() && rStyle.find(L' ' + sSelectors[i].m_wsName + L' ') != std::wstring::npos)
|
||
{
|
||
temporary.push_back(std::make_pair(i, sSelectors[i]));
|
||
sSelectors.erase(sSelectors.begin() + i);
|
||
}
|
||
else
|
||
i++;
|
||
}
|
||
NSCSS::CCompiledStyle oStyleSetting = m_oStylesCalculator.GetCompiledStyle(sSelectors, true);
|
||
NSCSS::CCompiledStyle oStyle = m_oStylesCalculator.GetCompiledStyle(sSelectors);
|
||
|
||
NSCSS::CCompiledStyle::StyleEquation(oStyle, oStyleSetting);
|
||
|
||
std::wstring sPStyle = GetStyle(oStyle, true);
|
||
|
||
if (sPStyle.empty() && oTS.sPStyle.empty())
|
||
return L"";
|
||
|
||
m_oXmlStyle.WriteLitePStyle(oStyleSetting);
|
||
std::wstring sPSettings = m_oXmlStyle.GetStyle();
|
||
m_oXmlStyle.Clear();
|
||
|
||
for(int i = temporary.size() - 1; i >= 0; i--)
|
||
sSelectors.insert(sSelectors.begin() + temporary[i].first, temporary[i].second);
|
||
|
||
// Если в таблице, то игнориуются Paragraph Borders
|
||
bool bInTable = false;
|
||
for (const NSCSS::CNode& item : sSelectors)
|
||
if (item.m_wsName == L"table")
|
||
bInTable = true;
|
||
if (bInTable)
|
||
{
|
||
size_t nBdr = sPSettings.find(L"<w:pBdr>");
|
||
if (nBdr != std::wstring::npos)
|
||
{
|
||
size_t nBdrEnd = sPSettings.find(L"</w:pBdr>", nBdr);
|
||
if (nBdrEnd != std::wstring::npos)
|
||
sPSettings.erase(nBdr, nBdrEnd + 9 - nBdr);
|
||
}
|
||
}
|
||
|
||
oXml->WriteNodeBegin(L"w:pPr");
|
||
|
||
if (!sPStyle.empty())
|
||
{
|
||
oXml->WriteString(L"<w:pStyle w:val=\"");
|
||
oXml->WriteString(sPStyle);
|
||
oXml->WriteString(L"\"/>");
|
||
}
|
||
|
||
oXml->WriteString(oTS.sPStyle + L' ' + 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"";
|
||
|
||
NSCSS::CCompiledStyle oStyleSetting = m_oStylesCalculator.GetCompiledStyle(sSelectors, true);
|
||
NSCSS::CCompiledStyle oStyle = m_oStylesCalculator.GetCompiledStyle(sSelectors);
|
||
|
||
NSCSS::CCompiledStyle::StyleEquation(oStyle, oStyleSetting);
|
||
|
||
std::wstring sRStyle = GetStyle(oStyle, false);
|
||
|
||
m_oXmlStyle.WriteLiteRStyle(oStyleSetting);
|
||
const std::wstring sRSettings = m_oXmlStyle.GetStyle();
|
||
m_oXmlStyle.Clear();
|
||
|
||
if (!sRStyle.empty() || !oTS.sRStyle.empty())
|
||
{
|
||
oXml->WriteString(L"<w:rPr>");
|
||
if (!sRStyle.empty())
|
||
{
|
||
oXml->WriteString(L"<w:rStyle w:val=\"");
|
||
oXml->WriteString(sRStyle);
|
||
oXml->WriteString(L"\"/>");
|
||
}
|
||
|
||
oXml->WriteString(oTS.sRStyle + L' ' + sRSettings);
|
||
oXml->WriteString(L"</w:rPr>");
|
||
}
|
||
return sRStyle;
|
||
}
|
||
|
||
void WriteImage(NSStringUtils::CStringBuilder* pXml, int nWidth, int nHeight, const std::wstring& wsId)
|
||
{
|
||
// Пишем в document.xml
|
||
pXml->WriteString(L"<w:r><w:drawing><wp:inline distT=\"0\" distB=\"0\" distL=\"0\" distR=\"0\"><wp:extent cx=\"");
|
||
pXml->WriteString(std::to_wstring(nWidth));
|
||
pXml->WriteString(L"\" cy=\"");
|
||
pXml->WriteString(std::to_wstring(nHeight));
|
||
pXml->WriteString(L"\"/><wp:docPr id=\"");
|
||
pXml->WriteString(wsId);
|
||
pXml->WriteString(L"\" name=\"\"/><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=\"\"/><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(nWidth));
|
||
pXml->WriteString(L"\" cy=\"");
|
||
pXml->WriteString(std::to_wstring(nHeight));
|
||
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></w:r>");
|
||
}
|
||
|
||
void WriteEmptyImage(NSStringUtils::CStringBuilder* pXml, int nWidth, int nHeight)
|
||
{
|
||
pXml->WriteString(L"<w:r><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"\" name=\"\"/>");
|
||
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\" name=\"\"/><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></w:r>");
|
||
}
|
||
|
||
void ImageRels (NSStringUtils::CStringBuilder* oXml, int nImageId, const std::wstring& sImageSrc, const std::wstring& sExtention)
|
||
{
|
||
bool bNew = nImageId < 0;
|
||
if (bNew)
|
||
nImageId = m_arrImages.size();
|
||
|
||
std::wstring sImageId = std::to_wstring(nImageId);
|
||
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"\"/>");
|
||
}
|
||
|
||
// Получаем размеры картинки
|
||
int nHy = oBgraFrame.get_Height();
|
||
int nWx = oBgraFrame.get_Width();
|
||
if (nWx > nHy)
|
||
{
|
||
int nW = nWx * 9525;
|
||
nW = (nW > 7000000 ? 7000000 : nW);
|
||
nHy = (int)((double)nHy * (double)nW / (double)nWx);
|
||
nWx = nW;
|
||
}
|
||
else
|
||
{
|
||
int nH = nHy * 9525;
|
||
nH = (nH > 8000000 ? 8000000 : nH);
|
||
int nW = (int)((double)nWx * (double)nH / (double)nHy);
|
||
if (nW > 7000000)
|
||
{
|
||
nW = 7000000;
|
||
nHy = (int)((double)nHy * (double)nW / (double)nWx);
|
||
}
|
||
else
|
||
nHy = nH;
|
||
nWx = nW;
|
||
}
|
||
|
||
WriteImage(oXml, nWx, nHy, sImageId);
|
||
}
|
||
|
||
void readNote (NSStringUtils::CStringBuilder* oXml, std::vector<NSCSS::CNode>& sSelectors, const 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:r><w:r><w:t xml:space=\"preserve\">");
|
||
m_oNoteXml.WriteEncodeXmlString(sNote);
|
||
m_oNoteXml.WriteString(L"</w:t></w:r></w:p></w:footnote>");
|
||
}
|
||
|
||
bool readSVG (const std::wstring& wsSvg)
|
||
{
|
||
if (wsSvg.empty())
|
||
return false;
|
||
|
||
CSvgFile oSvgReader;
|
||
|
||
NSFonts::IApplicationFonts* pFonts = NSFonts::NSApplication::Create();
|
||
NSFonts::IFontManager* pFontManager = pFonts->GenerateFontManager();
|
||
NSFonts::IFontsCache* pFontCache = NSFonts::NSFontCache::Create();
|
||
|
||
pFontCache->SetStreams(pFonts->GetStreams());
|
||
pFontManager->SetOwnerCache(pFontCache);
|
||
|
||
oSvgReader.SetFontManager(pFontManager);
|
||
|
||
if (!oSvgReader.ReadFromWString(wsSvg))
|
||
{
|
||
RELEASEINTERFACE(pFontManager);
|
||
pFonts->Release();
|
||
return false;
|
||
}
|
||
|
||
NSGraphics::IGraphicsRenderer* pGrRenderer = NSGraphics::Create();
|
||
pGrRenderer->SetFontManager(pFontManager);
|
||
|
||
double dX, dY, dW, dH;
|
||
oSvgReader.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);
|
||
|
||
oSvgReader.SetWorkingDirectory(m_sSrc);
|
||
oSvgReader.Draw(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(pFontManager);
|
||
RELEASEINTERFACE(pGrRenderer);
|
||
|
||
if (pBgraData)
|
||
free(pBgraData);
|
||
|
||
pFonts->Release();
|
||
|
||
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 = sFolder;
|
||
}
|
||
|
||
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();
|
||
|
||
m_internal->m_oStylesCalculator.SetBodyTree(m_internal->m_oTree);
|
||
|
||
// Переходим в начало
|
||
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();
|
||
|
||
m_internal->m_oStylesCalculator.SetBodyTree(m_internal->m_oTree);
|
||
|
||
// Переходим в начало
|
||
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();
|
||
|
||
m_internal->m_oStylesCalculator.SetBodyTree(m_internal->m_oTree);
|
||
|
||
// Переходим в начало
|
||
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.Clear();
|
||
}
|
||
|
||
m_internal->write();
|
||
return S_OK;
|
||
}
|