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

538 lines
18 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 <boost/foreach.hpp>
#include "docx_package.h"
#include "docx_conversion_context.h"
#include "headers_footers.h"
namespace cpdoccore {
namespace oox {
namespace package {
docx_content_types_file::docx_content_types_file()
{
content()->add_default(L"rels", L"application/vnd.openxmlformats-package.relationships+xml");
content()->add_default(L"xml", L"application/xml");
//
content()->add_default(L"jpg", L"image/jpeg");
content()->add_default(L"png", L"image/png");
//
content()->add_override(L"/word/document.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml");
content()->add_override(L"/word/settings.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml");
content()->add_override(L"/word/styles.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml");
content()->add_override(L"/word/fontTable.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml");
//content()->add_override(L"/word/_rels/document.xml.rels", L"application/vnd.openxmlformats-package.relationships+xml");
//content()->add_override(L"/_rels/.rels", L"application/vnd.openxmlformats-package.relationships+xml");
content()->add_override(L"/docProps/app.xml", L"application/vnd.openxmlformats-officedocument.extended-properties+xml");
content()->add_override(L"/docProps/core.xml", L"application/vnd.openxmlformats-package.core-properties+xml");
}
////////////////////////////////////////////////////////////////////////////////////////
word_files::word_files()
{
rels_file_ptr relFile = rels_file_ptr( new rels_file(L"document.xml.rels") );
rels_files_.add_rel_file( relFile );
}
void word_files::write(const std::wstring & RootPath)
{
std::wstring path = RootPath + FILE_SEPARATOR_STR + L"word";
NSDirectory::CreateDirectory(path.c_str());
if (document_)
document_->write( path );
if (styles_)
{
rels_files_.add( relationship(L"rId1", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", L"styles.xml" ) );
styles_->write( path );
}
if (fontTable_)
{
rels_files_.add( relationship(L"rId2", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable", L"fontTable.xml" ) );
fontTable_->write( path );
}
if (numbering_)
{
rels_files_.add( relationship(L"rId3", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering", L"numbering.xml" ) );
numbering_->write( path );
}
if (media_)
{
media_->write( path );
}
if (embeddings_)
{
embeddings_->write( path );
}
if (drawings_)
{
drawings_->set_main_document(get_main_document());
drawings_->write( path );
}
if (headers_footers_)
{
headers_footers_->write( path );
}
if (settings_)
{
rels_files_.add( relationship(L"rId4", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings", L"settings.xml" ) );
settings_->write( path );
}
if (comments_)
{
rels_files_.add( relationship(L"rId5", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", L"comments.xml" ) );
comments_->write( path );
}
{
charts_files_.set_main_document(get_main_document());
charts_files_.write(path);
}
if (jsaProject_)
{
rels_files_.add( relationship(L"jsaId", L"http://schemas.onlyoffice.com/jsaProject", L"jsaProject.bin" ) );
jsaProject_->write( path );
}
if (notes_)
{
notes_->write( path );
}
rels_files_.write(path);
}
void word_files::update_rels(docx_conversion_context & Context)
{
Context.get_mediaitems()->dump_rels(rels_files_.get_rel_file()->get_rels(), oox::document_place);
Context.dump_hyperlinks (rels_files_.get_rel_file()->get_rels(), oox::document_place);
Context.dump_headers_footers(rels_files_.get_rel_file()->get_rels());
Context.dump_notes (rels_files_.get_rel_file()->get_rels());
}
void word_files::set_media(mediaitems_ptr & _mediaitems)
{
if (_mediaitems->count_image + _mediaitems->count_media > 0)
{
media_ = element_ptr( new media(_mediaitems, _mediaitems->applicationFonts()) );
}
if (_mediaitems->count_object > 0)
{
embeddings_ = element_ptr( new embeddings(_mediaitems) );
embeddings_->set_main_document( get_main_document() );
}
}
void word_files::set_styles(element_ptr Element)
{
styles_ = Element;
}
void word_files::set_document(element_ptr Element)
{
document_ = Element;
}
void word_files::set_fontTable(element_ptr Element)
{
fontTable_ = Element;
}
void word_files::set_numbering(element_ptr Element)
{
numbering_ = Element;
}
void word_files::set_settings(element_ptr Element)
{
settings_ = Element;
}
void word_files::add_charts(chart_content_ptr chart)
{
charts_files_.add_chart(chart);
}
bool word_files::has_numbering()
{
return numbering_ ? true : false;
}
void word_files::add_jsaProject(const std::string &content)
{
jsaProject_ = package::simple_element::create(L"jsaProject.bin", content);
}
void word_files::set_drawings(element_ptr Element)
{
drawings_ = Element;
}
void word_files::set_headers_footers(headers_footers & HeadersFooters)
{
headers_footers_elements * elm = new headers_footers_elements(HeadersFooters);
elm->set_main_document( get_main_document() );
headers_footers_ = element_ptr( elm );
}
void word_files::set_notes(notes_context & notesContext)
{
notes_elements * elm = new notes_elements(notesContext);
elm->set_main_document( get_main_document() );
notes_ = element_ptr( elm );
}
void word_files::set_comments(comments_context & commentsContext)
{
if (commentsContext.comments_.size()<1)return;
comments_elements * elm = new comments_elements(commentsContext);
elm->set_main_document( get_main_document() );
comments_ = element_ptr( elm );
}
void word_files::add_rels(relationship const & r)
{
rels_files_.add(r);
}
//----------------------------------------------------------
int customXml_files::add_customXml(customXml_content_ptr customXml)
{
customXmls_.push_back(customXml);
return customXmls_.size();
}
void customXml_files::write(const std::wstring & RootPath)
{
std::wstring path = RootPath + FILE_SEPARATOR_STR + L"customXml";
NSDirectory::CreateDirectory(path.c_str());
std::wstring path_rels = path + FILE_SEPARATOR_STR + L"_rels";
NSDirectory::CreateDirectory(path_rels.c_str());
for (size_t i = 0 ; i < customXmls_.size(); i++)
{
if (!customXmls_[i]) continue;
const std::wstring fileNameItem = std::wstring(L"item") + std::to_wstring(i+1) + L".xml";
const std::wstring fileNameProps = std::wstring(L"itemProps") + std::to_wstring(i+1) + L".xml";
content_type * contentTypes = get_main_document()->get_content_types_file().content();
contentTypes->add_override(std::wstring(L"/customXml/") + fileNameProps,
L"application/vnd.openxmlformats-officedocument.customXmlProperties+xml");
package::simple_element(fileNameItem, customXmls_[i]->item()).write(path);
package::simple_element(fileNameProps, customXmls_[i]->props()).write(path);
rels_file_ptr rels_file = rels_file::create(fileNameItem + L".rels");
rels_file->get_rels().add(relationship(L"rId1",
L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps",
fileNameProps));
rels_file->write(path_rels);
}
}
//----------------------------------------------------------
void docx_charts_files::add_chart(chart_content_ptr chart)
{
charts_.push_back(chart);
}
void docx_charts_files::write(const std::wstring & RootPath)
{
std::wstring path = RootPath + FILE_SEPARATOR_STR + L"charts";
NSDirectory::CreateDirectory(path.c_str());
size_t count = 0;
for (size_t i = 0 ; i < charts_.size(); i++)
{
if (!charts_[i]) continue;
count++;
const std::wstring fileName = std::wstring(L"chart") + std::to_wstring(count) + L".xml";
const std::wstring kWSConType = L"application/vnd.openxmlformats-officedocument.drawingml.chart+xml";
content_type * contentTypes = get_main_document()->get_content_types_file().content();
contentTypes->add_override(std::wstring(L"/word/charts/") + fileName, kWSConType);
package::simple_element(fileName, charts_[i]->str()).write(path);
rels_files relFiles;
charts_[i]->get_rel_file()->set_file_name(fileName + L".rels");
relFiles.add_rel_file(charts_[i]->get_rel_file());
relFiles.write(path);
}
}
///////////////////////////
headers_footers_elements::headers_footers_elements(headers_footers & HeadersFooters) : headers_footers_(HeadersFooters)
{
}
void headers_footers_elements::write(const std::wstring & RootPath)
{
BOOST_FOREACH(const headers_footers::instances_map::value_type & instAr, headers_footers_.instances())
{
BOOST_FOREACH(const headers_footers::instance_ptr & inst, instAr.second)
{
if (inst->type_ == headers_footers::none) continue;
simple_element(inst->name_, inst->content_).write(RootPath);
if (document * doc = this->get_main_document())
{
const std::wstring ContentType
= (inst->type_ == headers_footers::header || inst->type_ == headers_footers::headerLeft || inst->type_ == headers_footers::headerFirst) ?
L"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml" :
L"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml";
doc->get_content_types_file().content()->add_override(std::wstring(L"/word/") + inst->name_, ContentType);
}
//нужно сформировать релсы с объектов
if (!inst->rels_.empty())
{
rels_files relFiles;
rels_file_ptr rels_elem = rels_file::create(inst->name_ + L".rels");
relFiles.add_rel_file(rels_elem);
BOOST_FOREACH(relationship const & r, inst->rels_.relationships())
{
relFiles.add(r);
}
relFiles.write(RootPath);
}
}
}
}
///////////////////
notes_elements::notes_elements(notes_context & notesContext) : notes_context_(notesContext)
{
}
namespace
{
void process_notes(const notes_context::instances_map & Instances,
const std::wstring & Node,
const std::wstring & Name,
const std::wstring & ContentType,
const std::wstring & RootPath,
rels & Rels,
document * doc
)
{
if (Instances.size())
{
std::wstringstream content;
// внимание! L"s - это не ошибка
content << L"<w:" << Node << L"s \
xmlns:o=\"urn:schemas-microsoft-com:office:office\" \
xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" \
xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" \
xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" \
xmlns:w10=\"urn:schemas-microsoft-com:office:word\" \
xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" \
xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" \
xmlns:wp14=\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\" \
xmlns:wpi=\"http://schemas.microsoft.com/office/word/2010/wordprocessingInk\" \
xmlns:wpg=\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\" \
xmlns:wps=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\" \
xmlns:wpc=\"http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas\" \
xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" \
xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\" \
xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" \
xmlns:a14=\"http://schemas.microsoft.com/office/drawing/2010/main\" >";
//mc:Ignorable=\"w14 wp14\"
//xmlns:v=\"urn:schemas-microsoft-com:vml\"
BOOST_FOREACH(const notes_context::instances_map::value_type & elm, Instances)
{
content << L"<w:" << Node << L" w:id=\"" << elm.second->id << L"\">";
content << elm.second->content;
content << L"</w:" << Node << L">";
}
content << L"</w:" << Node << L"s>";
simple_element(Name, content.str()).write(RootPath);
if (doc)
{
doc->get_content_types_file().content()->add_override(std::wstring(L"/word/") + Name, ContentType);
}
if (false == Rels.relationships().empty())
{
rels_files relFiles;
rels_file_ptr rels_elem = rels_file::create( Node + L"s.xml.rels");
relFiles.add_rel_file(rels_elem);
BOOST_FOREACH(relationship & r, Rels.relationships())
{
relFiles.add(r);
}
relFiles.write(RootPath);
}
}
}
}
void notes_elements::write(const std::wstring & RootPath)
{
process_notes(notes_context_.footnotes(),
L"footnote",
L"footnotes.xml",
L"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml",
RootPath,
notes_context_.footnotesRels(),
get_main_document());
process_notes(notes_context_.endnotes(),
L"endnote",
L"endnotes.xml",
L"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml",
RootPath,
notes_context_.endnotesRels(),
get_main_document());
}
///////////////////
comments_elements::comments_elements(comments_context & commentsContext) : comments_context_(commentsContext)
{
}
void comments_elements::write(const std::wstring & RootPath)
{
if (comments_context_.comments_.size())
{
std::wstringstream content;
content << L"<w:comments xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" " <<
L"xmlns:w10=\"urn:schemas-microsoft-com:office:word\" " <<
L"xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" " <<
L"xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" " <<
L"xmlns:o=\"urn:schemas-microsoft-com:office:office\" " <<
L">";
BOOST_FOREACH(const comments_context::_comment_desc & elm, comments_context_.comments_)
{
content << L"<w:comment w:id=\"" << elm.id << "\" ";
if (elm.author.length()>0)
content << L"w:author=\""<< XmlUtils::EncodeXmlString(elm.author) << "\" ";
if (elm.date.length()>0)
content << L"w:date=\""<< elm.date << "\" ";
content<< L">";
content << elm.content;
content << L"</w:comment>";
}
content << L"</w:comments>";
simple_element(L"comments.xml", content.str()).write(RootPath);
if (get_main_document())
get_main_document()->get_content_types_file().content()->add_override(L"/word/comments.xml", L"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml");
}
if (!comments_context_.get_rels().empty())
{
rels_files relFiles;
rels_file_ptr rels_elem = rels_file::create(L"comments.xml.rels");
relFiles.add_rel_file(rels_elem);
BOOST_FOREACH(relationship const & r, comments_context_.get_rels().relationships())
{
relFiles.add(r);
}
relFiles.write(RootPath);
}
}
////////////////////////////////////////////////////////////////////////////////////////
docx_document::docx_document()
{
this->set_main_document(this);
word_files_.set_main_document(this);
customXml_files_.set_main_document(this);
rels_file_ptr relFile = rels_file_ptr( new rels_file(L".rels") );
relFile->get_rels().relationships().push_back(
relationship(L"rId1", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties", L"docProps/app.xml" )
);
relFile->get_rels().relationships().push_back(
relationship(L"rId2", L"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", L"docProps/core.xml" )
);
relFile->get_rels().relationships().push_back(
relationship(L"rId3", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", L"word/document.xml" )
);
get_rels_files().add_rel_file( relFile );
}
int docx_document::add_customXml(customXml_content_ptr customXml)
{
return customXml_files_.add_customXml(customXml);
}
void docx_document::write(const std::wstring & RootPath)
{
if (word_files_.has_numbering())
{
content_type_file_.content()->get_override().push_back( override_content_type(L"/word/numbering.xml",
L"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml") );
}
customXml_files_.write (RootPath);
word_files_.write (RootPath);
get_rels_files().write (RootPath);
get_docProps_files().write (RootPath);
content_type_file_.write(RootPath);
}
}
}
}