Files
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

432 lines
14 KiB
C++

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "VmlDrawing.h"
#include <boost/lexical_cast.hpp>
#include "../../DesktopEditor/common/StringBuilder.h"
namespace OOX
{
//в файле VmlDrawing могут быть как отобразительная часть комментариев Xlsx, так и просто обычные объекты
void CVmlDrawing::ClearShapeTypes()
{
for ( size_t i = 0; i < m_arrShapeTypes.size(); ++i)
{
if ( m_arrShapeTypes[i].pElement ) delete m_arrShapeTypes[i].pElement;
}
m_arrShapeTypes.clear();
}
void CVmlDrawing::read(std::wstring & fileContent)
{
XmlUtils::CXmlLiteReader oReader;
if ( !oReader.FromString( fileContent))
return;
if ( !oReader.ReadNextNode() )
return;
std::wstring sName1 = XmlUtils::GetNameNoNS(oReader.GetName());
if ( L"xml" == sName1 )
{
ReadAttributes( oReader );
std::wstring elementContent;
bool bReadyElement = false;//собираем все до нахождения собственно элемента
if ( !oReader.IsEmptyNode() )
{
int nStylesDepth = oReader.GetDepth();
while ( oReader.ReadNextSiblingNode( nStylesDepth ) )//
{
std::wstring NodeContent = oReader.GetOuterXml();
std::wstring strXml = L"<xml xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" \
xmlns:p=\"urn:schemas-microsoft-com:office:powerpoint\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" xmlns:oa=\"urn:schemas-microsoft-com:office:activation\">";
strXml += NodeContent;
strXml += L"</xml>";
XmlUtils::CXmlLiteReader oSubReader;//нам нужны xml и сами объекты
if (oSubReader.FromString(strXml) == false) continue;
oSubReader.ReadNextNode();
OOX::WritingElement *pItem = NULL;
int nStylesDepth1 = oSubReader.GetDepth();
while ( oSubReader.ReadNextSiblingNode( nStylesDepth1 ) )//
{
std::wstring sName = oSubReader.GetName();
switch (sName[0])// вынесены только объекты ..
{
case 'v':
{
wchar_t wChar2 = sName[2]; // v:_
switch ( wChar2 )
{
case 'a':
if ( L"v:arc" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CArc, oSubReader)
bReadyElement = true;
}
break;
case 'c':
if ( L"v:curve" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CCurve, oSubReader)
bReadyElement = true;
}
break;
case 'g':
if ( L"v:group" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CGroup, oSubReader)
bReadyElement = true;
}
break;
case 'i':
if ( L"v:image" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CImage, oSubReader)
bReadyElement = true;
}
break;
case 'l':
if ( L"v:line" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CLine, oSubReader)
bReadyElement = true;
}
break;
case 'o':
if ( L"v:oval" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::COval, oSubReader)
bReadyElement = true;
}
break;
case 'p':
if ( L"v:polyline" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CPolyLine, oSubReader)
bReadyElement = true;
}
break;
case 'r':
if ( L"v:rect" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CRect, oSubReader)
bReadyElement = true;
}
else if ( L"v:roundrect" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CRoundRect, oSubReader)
bReadyElement = true;
}
break;
case 's':
if ( L"v:shape" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CShape, oSubReader)
bReadyElement = true;
}
else if ( L"v:shapetype" == sName )
{
AssignPtrXmlContent(pItem, OOX::Vml::CShapeType, oSubReader)
}
break;
}
}break;
}
}
elementContent += NodeContent;
if ( pItem )
{
m_arrItems.push_back( pItem );
OOX::Vml::CVmlCommonElements* common = dynamic_cast<OOX::Vml::CVmlCommonElements*>(pItem);
std::wstring sSpid;
bool bComment = false;
if (common)
{
if (common->m_sSpId.IsInit()) sSpid = *common->m_sSpId;
else if (common->m_sId.IsInit())sSpid = *common->m_sId;
bComment = common->m_bComment;
}
else
{
OOX::Vml::CGroup *group = dynamic_cast<OOX::Vml::CGroup*>(pItem);
if (group)
{
if (group->m_sSpId.IsInit()) sSpid = *group->m_sSpId;
else if (group->m_sId.IsInit()) sSpid = *group->m_sId;
}
}
if (bReadyElement)
{
if (!sSpid.empty())
{
_vml_shape element;
element.nId = (int)m_arrItems.size()-1;
element.sXml = elementContent;
element.pElement = pItem;
element.bComment = bComment;
m_mapShapes.insert(std::make_pair(sSpid, element));
}
elementContent.clear();
bReadyElement = false;
bComment = false;
}
else
{
_vml_shape element;
element.nId = -1;
element.sXml = elementContent;
element.pElement = pItem;
element.bUsed = false;
m_arrShapeTypes.push_back(element);
}
}
}
}
}
}
void CVmlDrawing::read(const CPath& oRootPath, const CPath& oPath)
{
m_oReadPath = oPath;
IFileContainer::Read( oRootPath, oPath );
//так как это не совсем xml - поправим
NSFile::CFileBinary file;
if (file.OpenFile(oPath.GetPath()))
{
DWORD DataSize = file.GetFileSize();
BYTE* Data = new BYTE[DataSize];
if (Data)
{
file.ReadFile(Data, DataSize, DataSize);
m_sFileContent = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(Data,DataSize);
delete []Data;
}
file.CloseFile();
}
if (false == m_sFileContent.empty())
{
// элементы вида <br> без </br>
// test_vml4.xlsx
XmlUtils::replace_all(m_sFileContent, L"<br>", L"");
// элементы вида <![if ...]>, <![endif]>
// Zigmunds.pptx
while(true)
{
size_t res1 = m_sFileContent.find(L"<![");
if (res1 == std::wstring::npos) break;
size_t res2 = m_sFileContent.find(L">", res1);
if (res1 != std::wstring::npos && res2 != std::wstring::npos)
{
m_sFileContent = m_sFileContent.erase(res1, res2 - res1 + 1);
}
}
read(m_sFileContent);
}
}
void CVmlDrawing::write(const CPath& oPath, const CPath& oDirectory, CContentTypes& oContent) const
{
if ((!m_mapComments || m_mapComments->empty()) && m_arObjectXml.empty() && m_arControlXml.empty())
{
if (false == m_sFileContent.empty())
{
NSFile::CFileBinary::SaveToFile(oPath.GetPath(), m_sFileContent);
oContent.AddDefault(oPath.GetExtention(false));
IFileContainer::Write(oPath, oDirectory, oContent);
}
return;
}
//for Comment SpreadsheetML & others vml (hf, objects, ...) !!
NSStringUtils::CStringBuilder sXml;
sXml.WriteString(L"<xml \
xmlns:v=\"urn:schemas-microsoft-com:vml\" \
xmlns:o=\"urn:schemas-microsoft-com:office:office\" \
xmlns:x=\"urn:schemas-microsoft-com:office:excel\">");
for (size_t i = 0; i < m_arObjectXml.size(); ++i)
{
sXml.WriteString(m_arObjectXml[i]);
}
if (false == m_arControlXml.empty() || ((NULL != m_mapComments) && (false == m_mapComments->empty())))
{
int data = (int)((m_lObjectIdVML + 4096) / 1024);
sXml.WriteString(L"<o:shapelayout v:ext=\"edit\"><o:idmap v:ext=\"edit\" data=\"" + std::to_wstring(data) + L"\"/></o:shapelayout>");
}
if (false == m_arControlXml.empty())
{
sXml.WriteString(L"<v:shapetype id=\"_x0000_t201\" coordsize=\"21600,21600\" o:spt=\"201\"");
sXml.WriteString(L" path=\"m,l,21600r21600,l21600,xe\"><v:stroke joinstyle=\"miter\"/>");
sXml.WriteString(L"<v:path shadowok=\"f\" o:extrusionok=\"f\" strokeok=\"f\" fillok=\"f\" o:connecttype=\"rect\"/>");
sXml.WriteString(L"<o:lock v:ext=\"edit\" shapetype=\"t\"/></v:shapetype>");
for (size_t i = 0; i < m_arControlXml.size(); ++i)
{
sXml.WriteString(m_arControlXml[i]);
}
}
long nIndex = 4096 + m_lObjectIdVML;
if ((NULL != m_mapComments) && (false == m_mapComments->empty()))
{
sXml.WriteString(L"<v:shapetype id=\"_x0000_t202\" coordsize=\"21600,21600\" o:spt=\"202\"");
sXml.WriteString(L" path=\"m,l,21600r21600,l21600,xe\">");
sXml.WriteString(L"<v:stroke joinstyle=\"miter\"/><v:path gradientshapeok=\"t\" o:connecttype=\"rect\"/></v:shapetype>");
for (std::map<std::wstring, OOX::Spreadsheet::CCommentItem*>::const_iterator it = m_mapComments->begin(); it != m_mapComments->end(); ++it)
{
OOX::Spreadsheet::CCommentItem* comment = it->second;
std::wstring sStyle;
if(comment->m_dLeftMM.IsInit())
{
SimpleTypes::CPoint oPoint; oPoint.FromMm(comment->m_dLeftMM.get());
sStyle += L"margin-left:" + XmlUtils::ToString(oPoint.ToPoints()) + L"pt;";
}
if(comment->m_dTopMM.IsInit())
{
SimpleTypes::CPoint oPoint; oPoint.FromMm(comment->m_dTopMM.get());
sStyle += L"margin-top:" + XmlUtils::ToString(oPoint.ToPoints()) + L"pt;";
}
if(comment->m_dWidthMM.IsInit())
{
SimpleTypes::CPoint oPoint; oPoint.FromMm(comment->m_dWidthMM.get());
sStyle += L"width:" + XmlUtils::ToString(oPoint.ToPoints()) + L"pt;";
}
if(comment->m_dHeightMM.IsInit())
{
SimpleTypes::CPoint oPoint; oPoint.FromMm(comment->m_dHeightMM.get());
sStyle += L"height:" + XmlUtils::ToString(oPoint.ToPoints()) + L"pt;";
}
std::wstring sClientData = L"<x:ClientData ObjectType=\"Note\">";
if(comment->m_bMove.IsInit() && true == comment->m_bMove.get())
sClientData += L"<x:MoveWithCells/>";
if(comment->m_bSize.IsInit() && true == comment->m_bSize.get())
sClientData += L"<x:SizeWithCells/>";
if( comment->m_nLeft.IsInit() && comment->m_nLeftOffset.IsInit() &&
comment->m_nTop.IsInit() && comment->m_nTopOffset.IsInit() &&
comment->m_nRight.IsInit() && comment->m_nRightOffset.IsInit() &&
comment->m_nBottom.IsInit() && comment->m_nBottomOffset.IsInit())
{
sClientData += L"<x:Anchor>";
sClientData += std::to_wstring(comment->m_nLeft.get()) + L",";
sClientData += std::to_wstring(comment->m_nLeftOffset.get()) + L",";
sClientData += std::to_wstring(comment->m_nTop.get()) + L",";
sClientData += std::to_wstring(comment->m_nTopOffset.get()) + L",";
sClientData += std::to_wstring(comment->m_nRight.get()) + L",";
sClientData += std::to_wstring(comment->m_nRightOffset.get()) + L",";
sClientData += std::to_wstring(comment->m_nBottom.get()) + L",";
sClientData += std::to_wstring(comment->m_nBottomOffset.get());
sClientData += L"</x:Anchor>";
}
sClientData += L"<x:AutoFill>False</x:AutoFill>";
if(comment->m_nRow.IsInit())
sClientData += L"<x:Row>" + std::to_wstring(comment->m_nRow.get()) + L"</x:Row>";
if(comment->m_nCol.IsInit())
sClientData += L"<x:Column>" + std::to_wstring(comment->m_nCol.get()) + L"</x:Column>";
sClientData += L"</x:ClientData>";
std::wstring sGfxdata;
if(comment->m_sGfxdata.IsInit())
sGfxdata = L"o:gfxdata=\"" + *comment->m_sGfxdata + L"\"";
std::wstring sShape;
sShape += L"<v:shape id=\"_x0000_s" + std::to_wstring(nIndex++) + L" \" type=\"#_x0000_t202\" style='position:absolute;";
sShape += sStyle;
sShape += L"z-index:4;visibility:hidden' ";
sShape += sGfxdata;
sShape += L" fillcolor=\"#ffffe1\" o:insetmode=\"auto\"><v:fill color2=\"#ffffe1\"/><v:shadow on=\"t\" color=\"black\" obscured=\"t\"/><v:path o:connecttype=\"none\"/><v:textbox style='mso-direction-alt:auto'><div style='text-align:left'></div></v:textbox>";
sShape += sClientData;
sShape += L"</v:shape>";
sXml.WriteString(sShape);
}
}
sXml.WriteString(L"</xml>");
NSFile::CFileBinary::SaveToFile( oPath.GetPath(), sXml.GetData() );
oContent.AddDefault( oPath.GetExtention(false) );
IFileContainer::Write(oPath, oDirectory, oContent);
}
bool CVmlDrawing::IsEmpty()
{
return m_arObjectXml.empty() && m_arControlXml.empty() && (!m_mapComments || ((m_mapComments) && (m_mapComments->empty())));
}
smart_ptr<OOX::WritingElement> CVmlDrawing::FindVmlObject(const std::wstring &spid)
{
smart_ptr<OOX::WritingElement> oElement;
std::map<std::wstring, OOX::CVmlDrawing::_vml_shape>::iterator pFind = m_mapShapes.find(spid);
if (pFind != m_mapShapes.end())
{
oElement.reset(pFind->second.pElement);
oElement.AddRef();
}
return oElement;
}
} // namespace OOX