#include "Converter2OOXML.h"
#include "../../../DesktopEditor/common/File.h"
#include "../../../DesktopEditor/common/Directory.h"
#include "../../../DesktopEditor/common/SystemUtils.h"
#include "../../../DesktopEditor/raster/BgraFrame.h"
#include "../../../OfficeUtils/src/OfficeUtils.h"
#include "../../../DesktopEditor/graphics/pro/Graphics.h"
#include "../Paragraph/ParaText.h"
#include "../Paragraph/CtrlTable.h"
#include "../Paragraph/CtrlEqEdit.h"
#include "../HWPElements/HWPRecordParaShape.h"
#include "../HWPElements/HWPRecordCharShape.h"
#include "Transform.h"
#define DEFAULT_FONT_FAMILY std::wstring(L"Arial")
#define DEFAULT_FONT_SIZE 18
#define DEFAULT_LANGUAGE std::wstring(L"en")
#define PARA_SPACING_SCALE 0.85
#define SPACING_SCALE_MS_WORD 1.21
namespace HWP
{
enum class EShapeObjectType
{
Arc,
Curve,
Ellipse,
Line,
Ole,
Picture,
Polygon,
Rectangle,
Unknown
};
EShapeObjectType GetShapeObjectType(const std::wstring& wsID)
{
if (L"cra$" == wsID)
return EShapeObjectType::Arc;
if (L"ruc$" == wsID)
return EShapeObjectType::Curve;
if (L"lle$" == wsID)
return EShapeObjectType::Ellipse;
if (L"nil$" == wsID || L"loc$" == wsID)
return EShapeObjectType::Line;
if (L"elo$" == wsID)
return EShapeObjectType::Ole;
if (L"cip$" == wsID)
return EShapeObjectType::Picture;
if (L"lop$" == wsID)
return EShapeObjectType::Polygon;
if (L"cer$" == wsID)
return EShapeObjectType::Rectangle;
return EShapeObjectType::Unknown;
}
CConverter2OOXML::CConverter2OOXML()
: m_pContext(nullptr), m_ushShapeCount(0), m_ushPageCount(1), m_ushTableCount(0), m_ushEquationCount(0)
{}
CConverter2OOXML::~CConverter2OOXML()
{}
void CConverter2OOXML::SetContext(CWriterContext* pContext)
{
m_pContext = pContext;
}
void CConverter2OOXML::SetTempDirectory(const HWP_STRING& sTempDirectory)
{
m_sTempDirectory = sTempDirectory;
m_oOleConverter.SetTempDir(m_sTempDirectory);
}
void CConverter2OOXML::CreateEmptyFiles()
{
NSDirectory::CreateDirectory(m_sTempDirectory + L"/_rels");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/docProps");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/_rels");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/media");
NSDirectory::CreateDirectory(m_sTempDirectory + L"/word/theme");
// theme1.xml
std::wstring wsTheme = L"";
NSFile::CFileBinary oThemeWriter;
if (oThemeWriter.CreateFileW(m_sTempDirectory + L"/word/theme/theme1.xml"))
{
oThemeWriter.WriteStringUTF8(wsTheme);
oThemeWriter.CloseFile();
}
// app.xml
std::wstring wsApplication = NSSystemUtils::GetEnvVariable(NSSystemUtils::gc_EnvApplicationName);
if (wsApplication.empty())
wsApplication = NSSystemUtils::gc_EnvApplicationNameDefault;
std::wstring wsApp = L"";
wsApp += wsApplication;
wsApp += L"0falsefalsefalsefalse";
NSFile::CFileBinary oAppWriter;
if (oAppWriter.CreateFileW(m_sTempDirectory + L"/docProps/app.xml"))
{
oAppWriter.WriteStringUTF8(wsApp);
oAppWriter.CloseFile();
}
// .rels
std::wstring wsRels = L"";
NSFile::CFileBinary oRelsWriter;
if (oRelsWriter.CreateFileW(m_sTempDirectory + L"/_rels/.rels"))
{
oRelsWriter.WriteStringUTF8(wsRels);
oRelsWriter.CloseFile();
}
// fontTable.xml
std::wstring wsFontTable = L"";
NSFile::CFileBinary oFontTableWriter;
if (oFontTableWriter.CreateFileW(m_sTempDirectory + L"/word/fontTable.xml"))
{
oFontTableWriter.WriteStringUTF8(wsFontTable);
oFontTableWriter.CloseFile();
}
// settings.xml
std::wstring wsSettings = L"";
NSFile::CFileBinary oSettingsWriter;
if (oSettingsWriter.CreateFileW(m_sTempDirectory + L"/word/settings.xml"))
{
oSettingsWriter.WriteStringUTF8(wsSettings);
oSettingsWriter.CloseFile();
}
// core.xml
std::wstring wsCore = L"";
wsCore += L"";
NSFile::CFileBinary oCoreWriter;
if (oCoreWriter.CreateFileW(m_sTempDirectory + L"/docProps/core.xml"))
{
oCoreWriter.WriteStringUTF8(wsCore);
oCoreWriter.CloseFile();
}
FillDefaultData();
}
void CConverter2OOXML::FillDefaultData()
{
// Заполняем начало файлов
AddRelationship(L"styles", L"styles.xml");
AddRelationship(L"settings", L"settings.xml");
AddRelationship(L"webSettings", L"webSettings.xml");
AddRelationship(L"fontTable", L"fontTable.xml");
AddRelationship(L"theme", L"theme/theme1.xml");
AddContentType(L"document.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml");
AddContentType(L"styles.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml");
AddContentType(L"settings.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml");
AddContentType(L"webSettings.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml");
AddContentType(L"fontTable.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml");
AddContentType(L"theme/theme1.xml", L"application/vnd.openxmlformats-officedocument.theme+xml");
m_oNoteXmlRels.WriteString(L"");
m_oDocXml .WriteString(L"");
m_oWebSettings.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
m_oStylesXml.WriteString(L"");
}
void CConverter2OOXML::Close()
{
// Дописываем концы файлов
m_oDocXml.WriteString(L"");
NSFile::CFileBinary oDocumentWriter;
if (oDocumentWriter.CreateFileW(m_sTempDirectory + L"/word/document.xml"))
{
oDocumentWriter.WriteStringUTF8(m_oDocXml.GetData());
oDocumentWriter.CloseFile();
}
if (m_oFootnoteConverter.SaveToFile(m_sTempDirectory + FILE_SEPARATOR_STR + L"word" + FILE_SEPARATOR_STR))
{
AddRelationship(L"footnotes", L"footnotes.xml");
AddRelationship(L"endnotes", L"endnotes.xml");
AddContentType(L"footnotes.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml");
AddContentType(L"endnotes.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml");
}
// styles.xml
m_oStylesXml.WriteString(L"");
NSFile::CFileBinary oStylesWriter;
if (oStylesWriter.CreateFileW(m_sTempDirectory + L"/word/styles.xml"))
{
oStylesWriter.WriteStringUTF8(m_oStylesXml.GetData());
oStylesWriter.CloseFile();
}
// numbering.xml
if (m_oNumberingConverter.SaveToFile(m_sTempDirectory + FILE_SEPARATOR_STR + L"word" + FILE_SEPARATOR_STR))
{
AddRelationship(L"numbering", L"numbering.xml");
AddContentType(L"numbering.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml");
}
// webSettings.xml
m_oWebSettings.WriteString(L"");
NSFile::CFileBinary oWebSettingsWriter;
if (oWebSettingsWriter.CreateFileW(m_sTempDirectory + L"/word/webSettings.xml"))
{
oWebSettingsWriter.WriteStringUTF8(m_oWebSettings.GetData());
oWebSettingsWriter.CloseFile();
}
// [Content_Types].xml
NSFile::CFileBinary oContentTypeWriter;
if (oContentTypeWriter.CreateFileW(m_sTempDirectory + L"/[Content_Types].xml"))
{
oContentTypeWriter.WriteStringUTF8(L"");
oContentTypeWriter.WriteStringUTF8(L"");
for (const TContentType& oContentType : m_arDefaultContentType)
oContentTypeWriter.WriteStringUTF8(L"");
for (const TContentType& oContentType : m_arContentTypes)
oContentTypeWriter.WriteStringUTF8(L"");
oContentTypeWriter.WriteStringUTF8(L"");
oContentTypeWriter.WriteStringUTF8(L"");
oContentTypeWriter.WriteStringUTF8(L"");
oContentTypeWriter.CloseFile();
}
NSFile::CFileBinary oRelsWriter;
if (oRelsWriter.CreateFileW(m_sTempDirectory + L"/word/_rels/document.xml.rels"))
{
oRelsWriter.WriteStringUTF8(L"");
for (const TRelationship& oRelationship : m_arRelationships)
oRelsWriter.WriteStringUTF8(L"");
oRelsWriter.WriteStringUTF8(L"");
oRelsWriter.CloseFile();
}
}
void CConverter2OOXML::Convert()
{
if (nullptr == m_pContext)
return;
TConversionState oState;
std::vector arSetcions{m_pContext->GetSections()};
for (const CHWPSection* pSection : arSetcions)
{
const bool bIsLastSection = pSection == arSetcions.back();
for (const CHWPPargraph *pPara : pSection->GetParagraphs())
WriteParagraph(pPara, m_oDocXml, oState);
if (!bIsLastSection)
m_oDocXml.WriteString(L"");
WriteSectionSettings(oState);
if (!bIsLastSection)
m_oDocXml.WriteString(L"");
++oState.m_ushSecdIndex;
}
}
bool CConverter2OOXML::IsRasterFormat(const HWP_STRING& sFormat)
{
return L"png" == sFormat || L"jpg" == sFormat || L"jpeg" == sFormat || L"bmp" == sFormat;
}
void CConverter2OOXML::WriteCharacter(const CCtrlCharacter* pCharacter, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pCharacter)
return;
switch (pCharacter->GetType())
{
case ECtrlCharType::PARAGRAPH_BREAK:
{
if (oState.m_bOpenedP)
{
oState.m_bOpenedP = false;
oBuilder.WriteString(L"");
}
else
WriteText(L"", shParaShapeID, pCharacter->GetCharShapeId(), oBuilder, oState);
break;
}
case ECtrlCharType::LINE_BREAK:
{
oState.m_eBreakType = TConversionState::EBreakType::TextWrapping;
break;
}
case ECtrlCharType::HARD_HYPHEN:
case ECtrlCharType::HARD_SPACE:
break;
}
}
void CConverter2OOXML::WriteShape(const CCtrlGeneralShape* pShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pShape)
return;
switch (pShape->GetShapeType())
{
case EShapeType::Arc:
case EShapeType::Ellipse:
case EShapeType::Rect:
case EShapeType::Line:
{
WriteGeometryShape(pShape, oBuilder, oState);
break;
}
case EShapeType::Pic:
{
WritePicture((const CCtrlShapePic*)pShape, oBuilder, oState);
break;
}
case EShapeType::EqEdit:
{
WriteEqEditShape((const CCtrlEqEdit*)pShape, oBuilder, oState);
break;
}
case EShapeType::Ole:
{
WriteOleShape((const CCtrlShapeOle*)pShape, oBuilder, oState);
break;
}
case EShapeType::Video:
{
WriteVideo((const CCtrlShapeVideo*)pShape, oBuilder, oState);
break;
}
case EShapeType::GeneralShape:
case EShapeType::ConnectLine:
case EShapeType::Container:
case EShapeType::Polygon:
case EShapeType::TextArt:
case EShapeType::Curve:
break;
}
}
void CConverter2OOXML::WriteNote(const CCtrlNote* pNote, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
oBuilder.WriteString(L"");
WriteRunnerStyle(oState.m_ushLastCharShapeId, oBuilder, oState, L"");
oBuilder.WriteString(m_oFootnoteConverter.CreateNote((const CCtrlNote*)pNote, *this));
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteParagraph(const CHWPPargraph* pParagraph, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pParagraph)
return;
if (0 < pParagraph->GetBreakType())
{
if ((0x04 == (pParagraph->GetBreakType() & 0x04)) && (0 < oState.m_unParaIndex))
{
if (oState.m_bOpenedP)
oBuilder.WriteString(L"");
OpenParagraph(pParagraph->GetShapeID(), oBuilder, oState);
oBuilder.WriteString(L"");
oState.m_bOpenedP = true;
++m_ushPageCount;
}
else if (0x08 == (pParagraph->GetBreakType() & 0x08))
{
if (oState.m_bOpenedP)
oBuilder.WriteString(L"");
OpenParagraph(pParagraph->GetShapeID(), oBuilder, oState);
oBuilder.WriteString(L"");
oState.m_bOpenedP = true;
}
}
++oState.m_unParaIndex;
std::vector arNotes;
for (const CCtrl* pCtrl : pParagraph->GetCtrls())
{
switch (pCtrl->GetCtrlType())
{
case ECtrlObjectType::ParaText:
{
WriteText(((const CParaText*)pCtrl)->GetText(), pParagraph->GetShapeID(), ((const CParaText*)pCtrl)->GetCharShapeID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Character:
{
WriteCharacter((const CCtrlCharacter*)pCtrl, pParagraph->GetShapeID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Shape:
{
WriteShape((const CCtrlGeneralShape*)pCtrl, oBuilder, oState);
break;
}
case ECtrlObjectType::Table:
{
WriteTable((const CCtrlTable*)pCtrl, pParagraph->GetShapeID(), oBuilder, oState);
break;
}
case ECtrlObjectType::Note:
{
arNotes.push_back((const CCtrlNote*)pCtrl);
break;
}
case ECtrlObjectType::SectionDef:
{
oState.m_pSectionDef = (const CCtrlSectionDef*)pCtrl;
break;
}
case ECtrlObjectType::ColumnDef:
{
oState.m_pColumnDef = (const CCtrlColumnDef*)(pCtrl);
break;
}
case ECtrlObjectType::AutoNumber:
{
WriteAutoNumber((const CCtrlAutoNumber*)pCtrl, pParagraph->GetShapeID(), ((const CParaText*)pCtrl)->GetCharShapeID(), oBuilder, oState);
break;
}
default:
break;
}
if (!arNotes.empty() && ECtrlObjectType::Note != pCtrl->GetCtrlType() && oState.m_bOpenedP)
{
for (const CCtrlNote* pNote: arNotes)
WriteNote(pNote, pParagraph->GetShapeID(), oBuilder, oState);
arNotes.clear();
}
}
if (oState.m_bOpenedP && !arNotes.empty())
{
for (const CCtrlNote* pNote: arNotes)
WriteNote(pNote, pParagraph->GetShapeID(), oBuilder, oState);
}
CloseParagraph(oBuilder, oState);
}
void CConverter2OOXML::WriteParagraphProperties(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
oBuilder.WriteString(L"");
WriteParaShapeProperties(shParaShapeID, oBuilder, oState);
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteParaShapeProperties(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == m_pContext)
return;
const CHWPRecordParaShape* pParaShape = dynamic_cast(m_pContext->GetParaShape(shParaShapeID));
if (nullptr == pParaShape)
return;
if (pParaShape->GetPageBreakBefore())
oState.m_eBreakType = TConversionState::EBreakType::Page;
oBuilder.WriteString(L"KeepWithNext()) ? L"true" : L"false") + L"\"/>");
switch(pParaShape->GetHorizantalAlign())
{
case EHorizontalAlign::JUSTIFY: oBuilder.WriteString(L""); break;
case EHorizontalAlign::LEFT: oBuilder.WriteString(L""); break;
case EHorizontalAlign::RIGHT: oBuilder.WriteString(L""); break;
case EHorizontalAlign::CENTER: oBuilder.WriteString(L""); break;
case EHorizontalAlign::DISTRIBUTE:
case EHorizontalAlign::DISTRIBUTE_SPACE: oBuilder.WriteString(L""); break;
}
switch(pParaShape->GetVerticalAlign())
{
case EVerticalAlign::BOTTOM: oBuilder.WriteString(L""); break;
case EVerticalAlign::TOP: oBuilder.WriteString(L""); break;
case EVerticalAlign::CENTER: oBuilder.WriteString(L""); break;
case EVerticalAlign::BASELINE:
break;
}
int nLineSpacing = 240;
HWP_STRING sType = L"auto";
switch(pParaShape->GetLineSpacingType())
{
case 0x0:
{
sType = L"auto";
nLineSpacing = static_cast(240. * (double)pParaShape->GetLineSpacing() / 100.); // TODO:: в hwp изначально межстрочный интервал меньше. Множитель 1 в hwp ≈ 0.65 MS
break;
}
case 0x01:
{
sType = L"exact";
nLineSpacing = static_cast((double)pParaShape->GetLineSpacing() / 2. * 20)/*0.352778*/; //(1pt=0.352778mm) //TODO:: проверить, как найдется пример
break;
break;
}
case 0x02:
case 0x03:
default:
{
sType = L"atLeast";
nLineSpacing = static_cast((double)pParaShape->GetLineSpacing()); //TODO:: проверить, как найдется пример
break;
}
}
oBuilder.WriteString(L"((double)pParaShape->GetMarginPrev() / 10.)) +
L"\" w:after=\"" + std::to_wstring(static_cast((double)pParaShape->GetMarginNext() / 10.)) + L"\"/>");
switch (pParaShape->GetHeadingType())
{
case EHeadingType::NUMBER:
case EHeadingType::BULLET:
{
const int nNumId = m_oNumberingConverter.CreateNumbering(dynamic_cast(m_pContext->GetNumbering(pParaShape->GetHeadingIdRef())), pParaShape->GetHeadingType());
if (0 == nNumId)
break;
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
break;
}
case EHeadingType::OUTLINE:
case EHeadingType::NONE:
break;
}
}
void CConverter2OOXML::WriteTable(const CCtrlTable* pTable, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pTable || pTable->Empty())
return;
++m_ushTableCount;
oBuilder.WriteString(L"");
WriteTableProperties(pTable, shParaShapeID, oBuilder, oState);
std::vector>> m_arrCells(pTable->GetRows());
for (unsigned int unRowIndex = 0; unRowIndex < pTable->GetRows(); ++unRowIndex)
{
m_arrCells[unRowIndex].resize(pTable->GetCols());
for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex)
m_arrCells[unRowIndex][unColIndex] = std::make_pair(ECellCreator::NOT_CREATED, nullptr);
}
for (unsigned int unCellIndex = 0; unCellIndex < pTable->GetCountCells(); ++unCellIndex)
{
const CTblCell* pCell = pTable->GetCell(unCellIndex);
if (nullptr == pCell || pCell->GetRowAddr() >= pTable->GetRows() || pCell->GetColAddr() >= pTable->GetCols())
continue;
m_arrCells[pCell->GetRowAddr()][pCell->GetColAddr()] = std::make_pair(ECellCreator::FILE, pCell);
}
for (unsigned int unRowIndex = 0; unRowIndex < pTable->GetRows(); ++unRowIndex)
{
for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex)
{
std::pair oValue = m_arrCells[unRowIndex][unColIndex];
if (ECellCreator::NOT_CREATED == oValue.first)
continue;
if (ECellCreator::FILE == oValue.first)
{
if (1 != oValue.second->GetRowSpan())
{
for (unsigned int unIndex = 1; unIndex < oValue.second->GetRowSpan() && unRowIndex + unIndex < pTable->GetRows(); ++unIndex)
m_arrCells[unRowIndex + unIndex][unColIndex] = std::make_pair(ECellCreator::EMPTY, oValue.second);
}
}
unColIndex += oValue.second->GetColSpan() - 1;
}
}
//TODO:: в случаях, когда есть пустые столбцы необходимо добавить возможность удаления данных столбцов
// Например для матрицы 3x2, у которой значения есть только в 2x2, необходимо удалить последний столбец
for (unsigned int unRowIndex = 0; unRowIndex < pTable->GetRows(); ++unRowIndex)
{
oBuilder.WriteString(L"");
int nHeight = 0;
for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex)
{
std::pair oValue = m_arrCells[unRowIndex][unColIndex];
if (ECellCreator::FILE == oValue.first && 1 == oValue.second->GetRowSpan())
nHeight = (std::max)(nHeight, oValue.second->GetHeight());
}
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
for (unsigned int unColIndex = 0; unColIndex < pTable->GetCols(); ++unColIndex)
{
std::pair oValue = m_arrCells[unRowIndex][unColIndex];
WriteCell(oValue.second, oBuilder, oState, oValue.first);
}
oBuilder.WriteString(L"");
}
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteTableProperties(const CCtrlTable* pTable, short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pTable)
return;
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
WriteParaShapeProperties(shParaShapeID, oBuilder, oState);
const CHWPRecordBorderFill* pBorderFill = nullptr;
if (nullptr != m_pContext)
pBorderFill = dynamic_cast(m_pContext->GetBorderFill(pTable->GetBorderFillID()));
if (nullptr == pBorderFill)
{
oBuilder.WriteString(L"");
return;
}
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteCell(const CTblCell* pCell, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, ECellCreator eCellCreator)
{
if (nullptr == pCell)
return;
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"GetWidth())) + L"\" w:type=\"dxa\"/>");
if (1 != pCell->GetColSpan())
oBuilder.WriteString(L"GetColSpan()) + L"\"/>");
if (1 != pCell->GetRowSpan())
oBuilder.WriteString(L"");
WriteCellProperties(pCell->GetBorderFillID(), oBuilder);
switch(pCell->GetVertAlign())
{
case EVertAlign::TOP: oBuilder.WriteString(L""); break;
case EVertAlign::CENTER: oBuilder.WriteString(L""); break;
case EVertAlign::BOTTOM: oBuilder.WriteString(L""); break;
case EVertAlign::INSIDE:
case EVertAlign::OUTSIDE:
break;
}
oBuilder.WriteString(L"");
if (ECellCreator::FILE == eCellCreator && !pCell->GetParagraphs().empty())
{
for (const CHWPPargraph* pParagraph : pCell->GetParagraphs())
{
TConversionState oCellState;
// Так как даже в пустой ячейки нужен параграф, то открываем его заранее, чтобы он 100% был (закроется он автоматически в WriteParagraph)
OpenParagraph(pParagraph->GetShapeID(), oBuilder, oCellState);
WriteParagraph(pParagraph, oBuilder, oCellState);
}
}
else
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteCellProperties(short shBorderFillID, NSStringUtils::CStringBuilder& oBuilder)
{
const CHWPRecordBorderFill* pBorderFill = nullptr;
if (nullptr != m_pContext)
pBorderFill = dynamic_cast(m_pContext->GetBorderFill(shBorderFillID));
if (nullptr == pBorderFill)
return;
if (nullptr != pBorderFill->GetFill() && pBorderFill->GetFill()->ColorFill())
oBuilder.WriteString(L"GetFill()->GetFaceColor()) + L"\"/>");
oBuilder.WriteString(L"");
WriteCellBorder(pBorderFill->GetTopBorder(), L"top", oBuilder);
WriteCellBorder(pBorderFill->GetLeftBorder(), L"left", oBuilder);
WriteCellBorder(pBorderFill->GetBottomBorder(), L"bottom", oBuilder);
WriteCellBorder(pBorderFill->GetRightBorder(), L"right", oBuilder);
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteCellBorder(const TBorder& oBorder, const HWP_STRING& sBorderName, NSStringUtils::CStringBuilder& oBuilder)
{
if (0x00 == oBorder.m_chWidth || sBorderName.empty())
return;
HWP_STRING sType;
//TODO:: проверить стиль линий
switch(oBorder.m_eStyle)
{
case ELineStyle2::NONE: oBuilder.WriteString(L""); return;
case ELineStyle2::SOLID: sType = L"single"; break;
case ELineStyle2::DASH: sType = L"dashed"; break;
case ELineStyle2::DOT: sType = L"dotted"; break;
case ELineStyle2::DASH_DOT: sType = L"dotDash"; break;
case ELineStyle2::DASH_DOT_DOT: sType = L"dotDotDash"; break;
case ELineStyle2::LONG_DASH: sType = L"dashed"; break;
case ELineStyle2::CIRCLE: sType = L"dashed"; break;
case ELineStyle2::DOUBLE_SLIM: sType = L"thickThinMediumGap"; break;
case ELineStyle2::SLIM_THICK: sType = L"thickThinMediumGap"; break;
case ELineStyle2::THICK_SLIM: sType = L"thickThinMediumGap"; break;
case ELineStyle2::SLIM_THICK_SLIM: sType = L"thickThinMediumGap"; break;
break;
}
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteGeometryShape(const CCtrlGeneralShape* pGeneralShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pGeneralShape)
return;
EShapeObjectType eShapeType = GetShapeObjectType(pGeneralShape->GetID());
if (EShapeObjectType::Unknown == eShapeType)
return;
const std::wstring wsWidth = std::to_wstring(Transform::HWPUINT2OOXML(pGeneralShape->GetWidth()));
const std::wstring wsHeight = std::to_wstring(Transform::HWPUINT2OOXML(pGeneralShape->GetHeight()));
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
OpenDrawingNode(pGeneralShape, oBuilder);
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
switch (eShapeType)
{
case EShapeObjectType::Arc:
{
oBuilder.WriteString(L"");
break;
}
case EShapeObjectType::Ellipse:
{
oBuilder.WriteString(L"");
break;
}
case EShapeObjectType::Line:
{
oBuilder.WriteString(L"");
break;
}
case EShapeObjectType::Rectangle:
{
oBuilder.WriteString(L"");
break;
}
case EShapeObjectType::Curve:
case EShapeObjectType::Ole:
case EShapeObjectType::Picture:
case EShapeObjectType::Polygon:
case EShapeObjectType::Unknown:
break;
}
const CFill *pFill = pGeneralShape->GetFill();
if (nullptr == pFill || pFill->NoneFill())
oBuilder.WriteString(L"");
else if (pFill->ColorFill())
oBuilder.WriteString(L"GetFaceColor()) + L"\"/>");
else if (pFill->ImageFill())
{
const HWP_STRING sPictureId = SavePicture(pFill->GetBinItemID());
if (!sPictureId.empty())
oBuilder.WriteString(L"");
else
oBuilder.WriteString(L"");
}
WriteLineSettings(pGeneralShape, oBuilder);
oBuilder.WriteString(L"");
unsigned int nCountParagraphs = pGeneralShape->GetCountParagraphs();
if (0 < nCountParagraphs)
{
oBuilder.WriteString(L"");
TConversionState oShapeState;
for (unsigned int unParaIndex = 0; unParaIndex < nCountParagraphs; ++unParaIndex)
WriteParagraph(pGeneralShape->GetParagraphs(unParaIndex), oBuilder, oShapeState);
oBuilder.WriteString(L"");
}
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
CloseDrawingNode(pGeneralShape, oBuilder);
oBuilder.WriteString(L"");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteEqEditShape(const CCtrlEqEdit* pEqEditShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
//TODO:: добавить конвертацию eqn формулы в ooxml
++m_ushEquationCount;
if (!oState.m_bOpenedP)
{
oBuilder.WriteString(L"");
oState.m_bOpenedP = true;
}
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteEncodeXmlString(pEqEditShape->GetEqn());
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteOleShape(const CCtrlShapeOle* pOleShape, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
//TODO:: добавить конвертацию hwp ole -> ooxml chart
//TODO:: необходимо добавить поддержку формата "Hwp Document File Formats - Charts" (для случаев, когда нет ooxml представления)
// Пока можем вытащить лишь ooxml представление данных
// Реализовать с использованием pole.h?
if (nullptr == m_pContext)
return;
CHWPStream oBuffer;
HWP_STRING sFileName;
if (!m_pContext->GetBinBytes(pOleShape->GetBinDataID(), oBuffer, sFileName))
return;
m_oOleConverter.CreateChart(oBuffer);
const unsigned int unChartIndex = m_oOleConverter.GetChartsCount();
if (0 == unChartIndex)
return;
const std::wstring wsWidth = std::to_wstring(Transform::HWPUINT2OOXML(pOleShape->GetWidth()));
const std::wstring wsHeight = std::to_wstring(Transform::HWPUINT2OOXML(pOleShape->GetHeight()));
const std::wstring wsRelID = AddRelationship(L"chart", L"charts/chart" + std::to_wstring(unChartIndex) + L".xml");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
OpenDrawingNode(pOleShape, oBuilder);
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
CloseDrawingNode(pOleShape, oBuilder);
oBuilder.WriteString(L"");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"");
AddContentType(L"charts/chart" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.openxmlformats-officedocument.drawingml.chart+xml");
AddContentType(L"charts/style" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.ms-office.chartstyle+xml");
AddContentType(L"charts/colors" + std::to_wstring(unChartIndex) + L".xml", L"application/vnd.ms-office.chartcolorstyle+xml");
}
void CConverter2OOXML::WriteSectionSettings(TConversionState& oState)
{
m_oDocXml.WriteString(L"");
if (nullptr != oState.m_pSectionDef)
{
for (const CCtrlHeadFoot* pCtrlHeadFoot : oState.m_pSectionDef->GetHeaderFooters())
{
const std::wstring wsID = m_oFootnoteConverter.CreateHeadOrFoot((const CCtrlHeadFoot*)pCtrlHeadFoot, *this);
if (!wsID.empty() && wsID.length() > 6)
{
const std::wstring wsType = wsID.substr(0, 6);
AddContentType(wsID, L"application/vnd.openxmlformats-officedocument.wordprocessingml." + wsType + L"+xml");
m_oDocXml.WriteString(L"");
}
}
}
if (nullptr != oState.m_pColumnDef && 1 < oState.m_pColumnDef->GetColCount())
{
//TODO:: Добавить поддержку остальный свойств
m_oDocXml.WriteString(L"GetColCount()) + L"\" w:space=\"454\" w:equalWidth=\"true\"");
if (ELineStyle2::NONE != oState.m_pColumnDef->GetColLineStyle())
m_oDocXml.WriteString(L" w:sep=\"true\"");
m_oDocXml.WriteString(L"/>");
}
const CPage *pPage = (nullptr != oState.m_pSectionDef) ? oState.m_pSectionDef->GetPage() : nullptr;
if (nullptr == pPage)
{
//DEFAULT_VALUE
m_oDocXml.WriteString(L"");
m_oDocXml.WriteString(L"");
}
else
{
m_oDocXml.WriteString(L"GetWidth())) + L"\" w:h=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetHeight())) + L"\"/>");
m_oDocXml.WriteString(L"GetMarginTop())) + L"\" w:right=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginRight())) + L"\" w:bottom=\"" +
std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginBottom())) + L"\" w:left=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginRight())) + L"\" w:header=\"" +
std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginHeader())) + L"\" w:footer=\"" + std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginFooter())) + L"\" w:gutter=\"" +
std::to_wstring(Transform::HWPUINT2Twips(pPage->GetMarginGutter())) + L"\"/>");
}
m_oDocXml.WriteString(L"");
m_oDocXml.WriteString(L"");
m_oDocXml.WriteString(L"");
}
void CConverter2OOXML::WritePicture(const CCtrlShapePic* pCtrlPic, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState)
{
if (nullptr == pCtrlPic)
return;
HWP_STRING sPictureID = SavePicture(pCtrlPic->GetBinDataID());
if (sPictureID.empty())
return;
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
OpenDrawingNode(pCtrlPic, oBuilder);
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"GetFinalWidth())) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlPic->GetFinalHeight())) + L"\"/>");
oBuilder.WriteString(L"");
WriteBorderSettings(pCtrlPic, oBuilder);
oBuilder.WriteString(L"");
CloseDrawingNode(pCtrlPic, oBuilder);
oBuilder.WriteString(L"");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteVideo(const CCtrlShapeVideo* pCtrlVideo, NSStringUtils::CStringBuilder& oBuilder, const TConversionState& oState)
{
if (nullptr == pCtrlVideo)
return;
HWP_STRING sPictureID = SavePicture(pCtrlVideo->GetThumnailBinID());
if (sPictureID.empty())
return;
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
OpenDrawingNode(pCtrlVideo, oBuilder);
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"GetThumnailBinID() + L"\" name=\"Video " + pCtrlVideo->GetThumnailBinID() + L"\"/>");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
oBuilder.WriteString(L"GetFinalWidth())) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlVideo->GetFinalHeight())) + L"\"/>");
oBuilder.WriteString(L"");
CloseDrawingNode(pCtrlVideo, oBuilder);
oBuilder.WriteString(L"");
if (!oState.m_bOpenedP)
oBuilder.WriteString(L"");
}
bool CConverter2OOXML::SaveSVGFile(const HWP_STRING& sSVG, HWP_STRING& sFileName)
{
if (sSVG.empty())
return false;
NSFonts::IApplicationFonts* pFonts = NSFonts::NSApplication::Create();
pFonts->Initialize();
MetaFile::IMetaFile* pSvgReader = MetaFile::Create(pFonts);
if (!pSvgReader->LoadFromString(sSVG))
{
RELEASEINTERFACE(pSvgReader);
RELEASEINTERFACE(pFonts);
return false;
}
NSGraphics::IGraphicsRenderer* pGrRenderer = NSGraphics::Create();
pGrRenderer->SetFontManager(pSvgReader->get_FontManager());
double dX, dY, dW, dH;
pSvgReader->GetBounds(&dX, &dY, &dW, &dH);
if (dW < 0) dW = -dW;
if (dH < 0) dH = -dH;
double dOneMaxSize = (double)1000.;
if (dW > dH && dW > dOneMaxSize)
{
dH *= (dOneMaxSize / dW);
dW = dOneMaxSize;
}
else if (dH > dW && dH > dOneMaxSize)
{
dW *= (dOneMaxSize / dH);
dH = dOneMaxSize;
}
int nWidth = static_cast(dW + 0.5);
int nHeight = static_cast(dH + 0.5);
double dWidth = 25.4 * nWidth / 96;
double dHeight = 25.4 * nHeight / 96;
unsigned char* pBgraData = (unsigned char*)malloc(nWidth * nHeight * 4);
if (!pBgraData)
{
double dKoef = 2000.0 / (nWidth > nHeight ? nWidth : nHeight);
nWidth = (int)(dKoef * nWidth);
nHeight = (int)(dKoef * nHeight);
dWidth = 25.4 * nWidth / 96;
dHeight = 25.4 * nHeight / 96;
pBgraData = (unsigned char*)malloc(nWidth * nHeight * 4);
}
if (!pBgraData)
return false;
unsigned int alfa = 0xffffff;
//дефолтный тон должен быть прозрачным, а не белым
//memset(pBgraData, 0xff, nWidth * nHeight * 4);
for (int i = 0; i < nWidth * nHeight; i++)
{
((unsigned int*)pBgraData)[i] = alfa;
}
CBgraFrame oFrame;
oFrame.put_Data(pBgraData);
oFrame.put_Width(nWidth);
oFrame.put_Height(nHeight);
oFrame.put_Stride(-4 * nWidth);
pGrRenderer->CreateFromBgraFrame(&oFrame);
pGrRenderer->SetSwapRGB(false);
pGrRenderer->put_Width(dWidth);
pGrRenderer->put_Height(dHeight);
pSvgReader->SetTempDirectory(m_sTempDirectory);
pSvgReader->DrawOnRenderer(pGrRenderer, 0, 0, dWidth, dHeight);
oFrame.SaveFile(m_sTempDirectory + L"/word/media/" + sFileName, 4);
oFrame.put_Data(NULL);
RELEASEINTERFACE(pGrRenderer);
if (pBgraData)
free(pBgraData);
RELEASEINTERFACE(pSvgReader);
RELEASEINTERFACE(pFonts);
return true;
}
HWP_STRING CConverter2OOXML::SavePicture(const HWP_STRING& sBinItemId)
{
if (nullptr == m_pContext)
return HWP_STRING();
//TODO:: добавить поддержку устновки размеров изображения из свойств шейпа
CHWPStream oBuffer;
HWP_STRING sFileName;
if (!m_pContext->GetBinBytes(sBinItemId, oBuffer, sFileName))
return HWP_STRING();
oBuffer.MoveToStart();
if (IsRasterFormat(NSFile::GetFileExtention(sFileName)))
{
NSFile::CFileBinary oFile;
oFile.CreateFileW(m_sTempDirectory + L"/word/media/" + sFileName);
if (!oFile.WriteFile((unsigned char*)oBuffer.GetCurPtr(), oBuffer.GetSize()))
{
oFile.CloseFile();
return HWP_STRING();
}
oFile.CloseFile();
}
else if (L"svg" == NSFile::GetFileExtention(sFileName))
{
std::string sSVG(oBuffer.GetCurPtr(), oBuffer.GetSize());
if (!SaveSVGFile(UTF8_TO_U(sSVG), sFileName))
return HWP_STRING();
}
AddContentType(L"media/" + sFileName, L"image/" + NSFile::GetFileExtention(sFileName));
return AddRelationship(L"image", L"media/" + sFileName);
}
void CConverter2OOXML::WriteRunnerStyle(short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState, const HWP_STRING& sExternStyles)
{
if (nullptr == m_pContext)
return;
const CHWPRecordCharShape* pCharShape = dynamic_cast(m_pContext->GetCharShape(shCharShapeID));
if (nullptr == pCharShape)
return;
oState.m_ushLastCharShapeId = shCharShapeID;
oBuilder.WriteString(L"");
HWP_STRING sFontFamily = pCharShape->GetFontName(ELang::LATIN);
HWP_STRING sFontFamilyAsian = pCharShape->GetFontName(ELang::HANGUL);
if (sFontFamilyAsian.empty() && !sFontFamily.empty())
sFontFamilyAsian = sFontFamily;
else if (!sFontFamilyAsian.empty() && sFontFamily.empty())
sFontFamily = sFontFamilyAsian;
if (!sFontFamily.empty() && !sFontFamilyAsian.empty())
{
oBuilder.WriteString(L"");
}
if (pCharShape->Bold())
oBuilder.WriteString(L"");
if (pCharShape->Italic())
oBuilder.WriteString(L"");
const int nHeight = static_cast(((double)(std::abs)(pCharShape->GetHeight()) * ((double)pCharShape->GetRelSize(ELang::LATIN) / 100.) / 100.) * 2.);
oBuilder.WriteString(L"");
oBuilder.WriteString(L"GetTextColor()) + L"\"/>");
bool bStrike = false;
if (pCharShape->Underline())
{
EUnderline eUnderlineType = pCharShape->GetUnderlineType();
ELineStyle1 eUnderlineStyle = pCharShape->GetUnderlineStyle();
if (EUnderline::BOTTOM == eUnderlineType)
{
oBuilder.WriteString(L"GetUnderlineColor()) + L"\"/>");
}
else if (EUnderline::CENTER == eUnderlineType)
{
if (eUnderlineStyle == ELineStyle1::DOUBLE_SLIM ||
eUnderlineStyle == ELineStyle1::DOUBLE_WAVE)
oBuilder.WriteString(L"");
else
oBuilder.WriteString(L"");
bStrike = true;
}
}
if (!bStrike && pCharShape->StrikeOut())
oBuilder.WriteString(L"");
double dSpacing = ((double)pCharShape->GetHeight() / 100.) * ((double)pCharShape->GetSpacing(ELang::HANGUL) / 100) * 0.8 + 0.4;
dSpacing *= 20; // pt to twips (20 = 1440 / 72)
oBuilder.WriteString(L"");
oBuilder.WriteString(sExternStyles);
oBuilder.WriteString(L"");
switch(oState.m_eBreakType)
{
case TConversionState::EBreakType::Page:
oBuilder.WriteString(L""); break;
case TConversionState::EBreakType::Column:
oBuilder.WriteString(L""); break;
case TConversionState::EBreakType::TextWrapping:
oBuilder.WriteString(L""); break;
case TConversionState::EBreakType::None:
break;
}
oState.m_eBreakType = TConversionState::EBreakType::None;
}
void CConverter2OOXML::OpenDrawingNode(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
oBuilder.WriteString(L"");
if (pCtrlShape->GetTreatAsChar())
{
oBuilder.WriteString(L"GetTopMargin() / 10)) +
L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomMargin() / 10)) +
L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftMargin() / 10)) +
L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightMargin() / 10)) +
L"\">");
WriteShapeExtent(pCtrlShape, oBuilder);
}
else
{
oBuilder.WriteString(L"GetTextWrap() ? L"1" : L"0")) +
L"\" relativeHeight=\"" + std::to_wstring(pCtrlShape->GetZOrder()) +
L"\" distT=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetTopMargin() / 10)) +
L"\" distB=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetBottomMargin() / 10)) +
L"\" distL=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetLeftMargin() / 10)) +
L"\" distR=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetRightMargin() / 10)) +
L"\" simplePos=\"0\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">");
WriteShapePosition(pCtrlShape, oBuilder);
WriteShapeExtent(pCtrlShape, oBuilder);
WriteShapeWrapMode(pCtrlShape, oBuilder);
}
WriteShapeProperty(pCtrlShape, oBuilder);
}
void CConverter2OOXML::CloseDrawingNode(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
if (pCtrlShape->GetTreatAsChar())
oBuilder.WriteString(L"");
else
{
oBuilder.WriteString(L"00");
oBuilder.WriteString(L"");
}
oBuilder.WriteString(L"");
}
HWP_STRING GetVRelativeFrom(EVRelTo eRelTo)
{
switch (eRelTo)
{
case EVRelTo::PARA:
return L"paragraph";
case EVRelTo::PAPER:
case EVRelTo::PAGE:
return L"page";
}
}
HWP_STRING GetHRelativeFrom(EHRelTo eRelTo)
{
switch (eRelTo)
{
case EHRelTo::PAPER:
case EHRelTo::PAGE:
return L"page";
case EHRelTo::COLUMN:
return L"column";
case EHRelTo::PARA:
return L"character";
}
}
void CConverter2OOXML::WriteShapeProperty(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
oBuilder.WriteString(L"GetDesc());
oBuilder.WriteString(L"\"/>");
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteShapePosition(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
oBuilder.WriteString(L"");
oBuilder.WriteString(L"GetHorzRelTo()) + L"\">" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetHorzOffset())) + L"");
oBuilder.WriteString(L"GetVertRelTo()) + L"\">" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetVertOffset())) + L"");
}
void CConverter2OOXML::WriteShapeExtent(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
oBuilder.WriteString(L"GetWidth())) + L"\" cy=\"" + std::to_wstring(Transform::HWPUINT2OOXML(pCtrlShape->GetHeight())) + L"\"/>");
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteShapeWrapMode(const CCtrlCommon* pCtrlShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlShape)
return;
switch (pCtrlShape->GetTextWrap())
{
case ETextWrap::SQUARE:
{
oBuilder.WriteString(L"GetTextFlow())
{
case 0x0: default: oBuilder.WriteString(L"bothSides"); break;
case 0x1: oBuilder.WriteString(L"left"); break;
case 0x2: oBuilder.WriteString(L"right"); break;
case 0x3: oBuilder.WriteString(L"largest"); break;
}
oBuilder.WriteString(L"\"/>");
break;
}
case ETextWrap::TOP_AND_BOTTOM:
{
oBuilder.WriteString(L"");
break;
}
case ETextWrap::BEHIND_TEXT:
case ETextWrap::IN_FRONT_OF_TEXT:
{
oBuilder.WriteString(L"");
break;
}
}
}
void CConverter2OOXML::OpenParagraph(short shParaShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (oState.m_bOpenedP)
return;
oBuilder.WriteString(L"");
oState.m_bOpenedP = true;
WriteParagraphProperties(shParaShapeID, oBuilder, oState);
}
void CConverter2OOXML::CloseParagraph(NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (!oState.m_bOpenedP)
return;
oBuilder.WriteString(L"");
oState.m_bOpenedP = false;
}
std::vector SplitText(const std::wstring& wsText)
{
if (wsText.empty())
return std::vector{L""};
std::vector arTexts;
std::wstring wsCurrentText;
bool bWasLetter = iswalpha(wsText[0]);
wsCurrentText.push_back(wsText[0]);
for (unsigned int unIndex = 1; unIndex < wsText.length(); ++unIndex)
{
bool bCurrentIsLetter = iswalnum(wsText[unIndex]);
if (bCurrentIsLetter != bWasLetter)
{
arTexts.push_back(wsCurrentText);
wsCurrentText.clear();
bWasLetter = bCurrentIsLetter;
}
wsCurrentText.push_back(wsText[unIndex]);
}
if (!wsCurrentText.empty())
arTexts.push_back(wsCurrentText);
return arTexts;
}
void CConverter2OOXML::WriteText(const std::wstring& wsText, short shParaShapeID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
OpenParagraph(shParaShapeID, oBuilder, oState);
if (wsText.empty())
{
oBuilder.WriteString(L"");
WriteRunnerStyle(shCharShapeID, oBuilder, oState);
oBuilder.WriteString(L"");
return;
}
oBuilder.WriteString(L"");
WriteRunnerStyle(shCharShapeID, oBuilder, oState);
oBuilder.WriteString(L"");
oBuilder.WriteEncodeXmlString(wsText);
oBuilder.WriteString(L"");
return;
for (const std::wstring& wsTextElement : SplitText(wsText))
{
oBuilder.WriteString(L"");
WriteRunnerStyle(shCharShapeID, oBuilder, oState);
if (!wsTextElement.empty())
{
oBuilder.WriteString(L"");
oBuilder.WriteEncodeXmlString(wsTextElement);
oBuilder.WriteString(L"");
}
oBuilder.WriteString(L"");
}
}
void CConverter2OOXML::WriteLineSettings(const CCtrlGeneralShape* pCtrlGeneralShape, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlGeneralShape)
return;
WriteLineSettings(pCtrlGeneralShape->GetLineStyle(), pCtrlGeneralShape->GetLineColor(), pCtrlGeneralShape->GetLineThick(), 1, oBuilder);
}
void CConverter2OOXML::WriteLineSettings(ELineStyle2 eLineStyle, int nColor, int nThick, HWP_BYTE nCompoundLineType, NSStringUtils::CStringBuilder& oBuilder)
{
if (ELineStyle2::NONE == eLineStyle || 0 >= nThick)
{
oBuilder.WriteString(L"");
return;
}
oBuilder.WriteString(L"");
oBuilder.WriteString(L"");
switch (eLineStyle)
{
case ELineStyle2::DASH:
{
oBuilder.WriteString(L"");
break;
}
case ELineStyle2::DOT:
{
oBuilder.WriteString(L"");
break;
}
case ELineStyle2::DASH_DOT:
{
oBuilder.WriteString(L"");
break;
}
case ELineStyle2::DASH_DOT_DOT:
{
oBuilder.WriteString(L"");
break;
}
case ELineStyle2::LONG_DASH:
{
oBuilder.WriteString(L"");
break;
}
case ELineStyle2::CIRCLE:
{
oBuilder.WriteString(L"");
break;
}
default:
break;
}
switch (nCompoundLineType)
{
case 0x00:
{
oBuilder.WriteString(L"");
break;
}
case 0x01:
{
oBuilder.WriteString(L"");
break;
}
}
oBuilder.WriteString(L"");
}
void CConverter2OOXML::WriteBorderSettings(const CCtrlShapePic* pCtrlPic, NSStringUtils::CStringBuilder& oBuilder)
{
if (nullptr == pCtrlPic)
return;
WriteLineSettings(pCtrlPic->GetBorderLineStyle(), pCtrlPic->GetBorderColor(), pCtrlPic->GetBorderThick(), pCtrlPic->GetBorderCompoundLineType(), oBuilder);
}
void CConverter2OOXML::WriteAutoNumber(const CCtrlAutoNumber* pAutoNumber,short shParaShapeID, short shCharShapeID, NSStringUtils::CStringBuilder& oBuilder, TConversionState& oState)
{
if (nullptr == pAutoNumber)
return;
unsigned short ushValue = 0;
//TODO:: лучше перейти не на ручной подсчет, а на автоматический в word (но там есть свои проблемы)
switch (pAutoNumber->GetNumType())
{
case ENumType::PAGE:
case ENumType::TOTAL_PAGE:
ushValue = m_ushPageCount; break;
case ENumType::FOOTNOTE:
ushValue = m_oFootnoteConverter.GetFootnoteCount(); break;
case ENumType::ENDNOTE:
ushValue = m_oFootnoteConverter.GetEndnoteCount(); break;
case ENumType::FIGURE:
ushValue = m_ushShapeCount; break;
case ENumType::TABLE:
ushValue = m_ushTableCount; break;
case ENumType::EQUATION:
ushValue = m_ushEquationCount; break;
}
if (0 == ushValue)
return;
WriteText(std::to_wstring(ushValue), shParaShapeID, shCharShapeID, oBuilder, oState);
}
HWP_STRING CConverter2OOXML::AddRelationship(const HWP_STRING& wsType, const HWP_STRING& wsTarget)
{
if (wsType.empty() || wsTarget.empty())
return HWP_STRING();
VECTOR::const_iterator itFound = std::find_if(m_arRelationships.cbegin(), m_arRelationships.cend(), [wsTarget](const TRelationship& oRelationship){ return wsTarget == oRelationship.m_wsTarget; });
if (m_arRelationships.cend() != itFound)
return itFound->m_wsID;
m_arRelationships.push_back({L"rId" + std::to_wstring(m_arRelationships.size() + 1), wsType, wsTarget});
return m_arRelationships.back().m_wsID;
}
void CConverter2OOXML::AddContentType(const HWP_STRING& wsName, const HWP_STRING& wsType)
{
if (wsName.empty() || wsType.empty())
return;
VECTOR::const_iterator itFound = std::find_if(m_arContentTypes.cbegin(), m_arContentTypes.cend(), [wsName](const TContentType& oContentType){ return wsName == oContentType.m_wsName; });
if (m_arContentTypes.cend() != itFound)
return;
AddDefaultContentType(NSFile::GetFileExtention(wsName));
m_arContentTypes.push_back({wsName, wsType});
}
void CConverter2OOXML::AddDefaultContentType(const HWP_STRING& wsName)
{
if (wsName.empty())
return;
VECTOR::const_iterator itFound = std::find_if(m_arDefaultContentType.cbegin(), m_arDefaultContentType.cend(), [wsName](const TContentType& oContentType){ return wsName == oContentType.m_wsName; });
if (m_arDefaultContentType.cend() != itFound)
return;
if (IsRasterFormat(wsName))
m_arDefaultContentType.push_back({wsName, L"image/" + wsName});
else if (L"xml" == wsName)
m_arDefaultContentType.push_back({wsName, L"application/xml"});
}
bool CConverter2OOXML::ConvertToFile(const HWP_STRING& sFilePath)
{
if (nullptr == m_pContext || sFilePath.empty())
return false;
CreateEmptyFiles();
Convert();
Close();
COfficeUtils oZip;
oZip.CompressFileOrDirectory(m_sTempDirectory, sFilePath);
return true;
}
bool CConverter2OOXML::ConvertToDir(const HWP_STRING& sDirectoryPath)
{
if (nullptr == m_pContext || sDirectoryPath.empty())
return false;
HWP_STRING sCurrentTempDir{m_sTempDirectory};
SetTempDirectory(sDirectoryPath);
CreateEmptyFiles();
Convert();
Close();
SetTempDirectory(sCurrentTempDir);
return true;
}
HWP_STRING CConverter2OOXML::GetTempDirectory() const
{
return m_sTempDirectory;
}
TConversionState::TConversionState()
: m_bOpenedP(false), m_bOpenedR(false), m_ushLastCharShapeId(-1), m_ushSecdIndex(0), m_unParaIndex(0),
m_pSectionDef(nullptr), m_pColumnDef(nullptr), m_eBreakType(EBreakType::None)
{}
}