Files
core/ASCOfficeDocFile/DocDocxConverter/DocumentMapping.cpp
2018-04-16 17:59:44 +03:00

1901 lines
57 KiB
C++
Executable File

/*
* (c) Copyright Ascensio System SIA 2010-2018
*
* 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 Lubanas st. 125a-25, Riga, Latvia,
* EU, LV-1021.
*
* 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 "DocumentMapping.h"
#include "ParagraphPropertiesMapping.h"
#include "CommentsMapping.h"
#include "TablePropertiesMapping.h"
#include "MainDocumentMapping.h"
#include "DrawingPrimitives.h"
#include "../Common/TextMark.h"
#include "../Common/FormatUtils.h"
#include <boost/algorithm/string.hpp>
namespace DocFileFormat
{
DocumentMapping::DocumentMapping(ConversionContext* context, IMapping* caller) : _skipRuns(0), _lastValidPapx(NULL), _lastValidSepx(NULL),
AbstractOpenXmlMapping( new XMLTools::CStringXmlWriter() ), _sectionNr(0), _footnoteNr(0),
_endnoteNr(0), _commentNr(0), _caller(caller)
{
m_document = NULL;
m_context = context;
m_bInternalXmlWriter = false;
_writeWebHidden = false;
_isSectionPageBreak = 0;
_isTextBoxContent = false;
//--------------------------------------------
_embeddedObject = false;
}
DocumentMapping::DocumentMapping(ConversionContext* context, XMLTools::CStringXmlWriter* writer, IMapping* caller):_skipRuns(0), _lastValidPapx(NULL), _lastValidSepx(NULL),
AbstractOpenXmlMapping(writer), _sectionNr(0), _footnoteNr(0), _endnoteNr(0),
_commentNr(0), _caller(caller)
{
m_document = NULL;
m_context = context;
m_bInternalXmlWriter = false;
_writeWebHidden = false;
_isSectionPageBreak = 0;
_isTextBoxContent = false;
_embeddedObject = false;
_cacheListNum = -1;
}
DocumentMapping::~DocumentMapping()
{
if (m_bInternalXmlWriter)
{
RELEASEOBJECT(m_pXmlWriter);
}
}
// Looks into the section table to find out if this CP is the end & current of a sections
int DocumentMapping::getCurrentSection(int cp)
{
//if cp is the last char of a section, the next section will start at cp +1
size_t current = 0;
for (std::vector<int>::iterator iter = m_document->SectionPlex->CharacterPositions.begin() + 1; iter != m_document->SectionPlex->CharacterPositions.end(); ++iter)
{
if (cp < *iter)
{
break;
}
current++;
}
if (current + 1 >= m_document->SectionPlex->CharacterPositions.size())
current = m_document->SectionPlex->CharacterPositions.size() - 2;
return m_document->SectionPlex->CharacterPositions[current + 1];
}
int DocumentMapping::getListNumCache(int fc, int fc_end)
{
if ( !m_document->ListPlex ) return -1;
for (size_t i = 1; i < m_document->ListPlex->CharacterPositions.size(); i++)
{
if ((fc >= m_document->ListPlex->CharacterPositions[i-1]) && (fc_end <= m_document->ListPlex->CharacterPositions[i]))
{
ListNumCache* listNum = dynamic_cast<ListNumCache*> (m_document->ListPlex->Elements[i-1]);
return listNum->value;
}
}
return -1;
}
bool DocumentMapping::isSectionEnd(int cp)
{
bool result = false;
//if cp is the last char of a section, the next section will start at cp +1
int search = cp + 1;
for (std::vector<int>::iterator iter = m_document->SectionPlex->CharacterPositions.begin(); iter != m_document->SectionPlex->CharacterPositions.end(); ++iter)
{
if (*iter == search)
{
result = true;
break;
}
}
return result;
}
// Writes a Paragraph that starts at the given cp and
// ends at the next paragraph end mark or section end mark
int DocumentMapping::writeParagraph(int cp)
{
//search the paragraph end
int cpParaEnd = cp;
if ((m_document->Text) && (cpParaEnd < (int)m_document->Text->size()))
{
while ( ( m_document->Text->at( cpParaEnd ) != TextMark::ParagraphEnd ) &&
( m_document->Text->at( cpParaEnd ) != TextMark::CellOrRowMark ) &&
!(( m_document->Text->at( cpParaEnd ) == TextMark::PageBreakOrSectionMark )&&
isSectionEnd( cpParaEnd ) ) )
{
if (cpParaEnd >= (int)m_document->Text->size()-1) break;
cpParaEnd++;
}
if (TextMark::PageBreakOrSectionMark == m_document->Text->at(cpParaEnd))
{
// there is a page break OR section mark,
// write the section only if it's a section mark
bool sectionEnd = isSectionEnd(cpParaEnd);
cpParaEnd++;
return writeParagraph(cp, cpParaEnd, sectionEnd);
}
else
{
cpParaEnd++;
return writeParagraph(cp, cpParaEnd, false);
}
}
return cpParaEnd;
}
// Writes a Paragraph that starts at the given cpStart and
// ends at the given cpEnd
int DocumentMapping::writeParagraph (int initialCp, int cpEnd, bool sectionEnd, bool lastBad)
{
int cp = initialCp;
int fc = m_document->FindFileCharPos(cp);
int fcEnd = m_document->FindFileCharPos(cpEnd);
if (fc < 0 || fcEnd < 0)
return 0;
ParagraphPropertyExceptions* papx = findValidPapx(fc);
// get all CHPX between these boundaries to determine the count of runs
std::list<CharacterPropertyExceptions*>* chpxs = m_document->GetCharacterPropertyExceptions(fc, fcEnd);
std::vector<int>* chpxFcs = m_document->GetFileCharacterPositions(fc, fcEnd);
CharacterPropertyExceptions* paraEndChpx = NULL;
if (chpxFcs)
{
chpxFcs->push_back(fcEnd);
}
if (chpxs)
{
// the last of these CHPX formats the paragraph end mark
paraEndChpx = *(chpxs->rbegin());
}
// start paragraph
m_pXmlWriter->WriteNodeBegin(L"w:p", true);
writeParagraphRsid(papx);
// ----------- check for section properties
bool isBidi = false;
SectionPropertyExceptions* currentSection = findValidSepx(getCurrentSection(cp));
if (currentSection)
{
isBidi = currentSection->isBidi;
}
//-----------------------------------------------------------
//_cacheListNum = getListNumCache(fc, fcEnd);
_isSectionPageBreak = 0;
if (sectionEnd)
{
// this is the last paragraph of this section
// write properties with section properties
if (papx)
{
ParagraphPropertiesMapping oMapping(m_pXmlWriter, m_context, m_document, paraEndChpx, isBidi, findValidSepx(cpEnd), _sectionNr);
papx->Convert(&oMapping);
_isSectionPageBreak = oMapping.get_section_page_break();
}
++_sectionNr;
}
else
{
// write properties
if (papx)
{
ParagraphPropertiesMapping oMapping(m_pXmlWriter, m_context, m_document, paraEndChpx, isBidi);
papx->Convert(&oMapping);
}
}
if ((chpxs != NULL) && (chpxFcs != NULL) && !chpxFcs->empty())//? второе
{
int i = 0;
// write a runs for each CHPX
std::list<CharacterPropertyExceptions*>::iterator cpeIter_last = chpxs->end(); cpeIter_last--;
for (std::list<CharacterPropertyExceptions*>::iterator cpeIter = chpxs->begin(); cpeIter != chpxs->end(); ++cpeIter)
{
//get the FC range for this run
int fcChpxStart = chpxFcs ? chpxFcs->at(i) : fc;
int fcChpxEnd = chpxFcs ? chpxFcs->at(i + 1) : fcEnd;
//? if (lastBad && cpeIter == cpeIter_last)
//? {
//? fcChpxEnd = fcEnd;
//? }
//it's the first chpx and it starts before the paragraph
if ( ( i == 0 ) && ( fcChpxStart < fc ) )
{
//so use the FC of the paragraph
fcChpxStart = fc;
}
//it's the last chpx and it exceeds the paragraph
if ( ( i == ( chpxs->size() - 1 ) ) && ( fcChpxEnd > fcEnd ) )//todooo убрать обращение к size() !!!
{
//so use the FC of the paragraph
fcChpxEnd = fcEnd;
}
//read the chars that are formatted via this CHPX
std::vector<wchar_t>* chpxChars = m_document->GetChars(fcChpxStart, fcChpxEnd, cp);
//search for bookmarks in the chars
std::vector<int> annot = searchAnnot(chpxChars, cp);
if (!annot.empty())
{
std::list<std::vector<wchar_t>>* runs = splitCharList(chpxChars, &annot);
if (runs)
{
for (std::list<std::vector<wchar_t> >::iterator iter = runs->begin(); iter != runs->end(); ++iter)
{
if (writeAnnotations(cp))
{
cp = writeRun(&(*iter), *cpeIter, cp);
}
}
RELEASEOBJECT(runs);
}
}
else
{
//search for bookmarks in the chars
std::vector<int> bookmarks = searchBookmarks(chpxChars, cp);
//if there are bookmarks in this run, split the run into several runs
if (!bookmarks.empty())
{
std::list<std::vector<wchar_t>>* runs = splitCharList(chpxChars, &bookmarks);
if (runs)
{
for (std::list<std::vector<wchar_t> >::iterator iter = runs->begin(); iter != runs->end(); ++iter)
{
if (writeBookmarks(cp))
{
cp = writeRun(&(*iter), *cpeIter, cp);
}
}
RELEASEOBJECT(runs);
}
}
else
{
cp = writeRun(chpxChars, *cpeIter, cp);
}
}
RELEASEOBJECT(chpxChars);
i++;
}
//end paragraph
m_pXmlWriter->WriteNodeEnd(L"w:p");
}
else
{
//end paragraph
m_pXmlWriter->WriteNodeEnd(L"w:p");
}
RELEASEOBJECT(chpxFcs);
RELEASEOBJECT(chpxs);
return cpEnd++;
}
void DocumentMapping::writeParagraphRsid (const ParagraphPropertyExceptions* papx)
{
if (papx)
{
for (std::list<SinglePropertyModifier>::const_iterator iter = papx->grpprl->begin(); iter != papx->grpprl->end(); ++iter)
{
// rsid for paragraph property enditing (write to parent element)
if (DocFileFormat::sprmPRsid == iter->OpCode)
{
std::wstring id = FormatUtils::IntToFormattedWideString(FormatUtils::BytesToInt32(iter->Arguments, 0, iter->argumentsSize), L"%08x");
m_context->AddRsid(id);
m_pXmlWriter->WriteAttribute(L"w:rsidP", id);
break;
}
}
}
m_pXmlWriter->WriteNodeEnd(L"", true, false);
}
// Writes a run with the given characters and CHPX
int DocumentMapping::writeRun (std::vector<wchar_t>* chars, CharacterPropertyExceptions* chpx, int initialCp)
{
int cp = initialCp;
int result_cp = cp + (int)chars->size();
if ((_skipRuns <= 0) && (chars->size() > 0))
{
RevisionData rev = RevisionData(chpx);
if (Deleted == rev.Type)
{
//If it's a deleted run
m_pXmlWriter->WriteNodeBegin(L"w:del", true);
m_pXmlWriter->WriteAttribute(L"w:author", L"[b2x: could not retrieve author]");
m_pXmlWriter->WriteAttribute(L"w:date", L"[b2x: could not retrieve date]");
m_pXmlWriter->WriteNodeEnd(L"", true, false);
}
else if ( rev.Type == Inserted )
{
WideString* author = dynamic_cast<WideString*>(m_document->RevisionAuthorTable->operator[](rev.Isbt));
//if it's a inserted run
m_pXmlWriter->WriteNodeBegin(L"w:ins", true);
m_pXmlWriter->WriteAttribute(L"w:author", FormatUtils::XmlEncode(*author));
m_pXmlWriter->WriteNodeEnd(L"", true, false);
//rev.Dttm.Convert(new DateMapping(m_pXmlWriter));
}
//start run
m_pXmlWriter->WriteNodeBegin(L"w:r", true);
//append rsids
if (0 != rev.Rsid)
{
std::wstring rsid = FormatUtils::IntToFormattedWideString(rev.Rsid, L"%08x");
m_pXmlWriter->WriteAttribute(L"w:rsidR", rsid);
m_context->AddRsid(rsid);
}
if (0 != rev.RsidDel)
{
std::wstring rsidDel = FormatUtils::IntToFormattedWideString(rev.RsidDel, L"%08x");
m_pXmlWriter->WriteAttribute(L"w:rsidDel", rsidDel);
m_context->AddRsid(rsidDel);
}
if (0 != rev.RsidProp)
{
std::wstring rsidProp = FormatUtils::IntToFormattedWideString(rev.RsidProp, L"%08x");
m_pXmlWriter->WriteAttribute(L"w:rsidRPr", rsidProp);
m_context->AddRsid(rsidProp);
}
m_pXmlWriter->WriteNodeEnd(L"", true, false);
/// <w:rPr>
CharacterPropertiesMapping* rPr = new CharacterPropertiesMapping(m_pXmlWriter, m_document, &rev, _lastValidPapx, false);
if (rPr)
{
rPr->_webHidden = _writeWebHidden;
chpx->Convert(rPr);
RELEASEOBJECT(rPr);
}
if (Deleted == rev.Type)
{
writeText(chars, cp, chpx, true);
}
else
{
int new_result_cp = writeText(chars, cp, chpx, false);
if (new_result_cp > result_cp)
result_cp = new_result_cp;
}
//end run
m_pXmlWriter->WriteNodeEnd(L"w:r");
if (Deleted == rev.Type)
{
m_pXmlWriter->WriteNodeEnd(L"w:del");
}
else if (Inserted == rev.Type)
{
m_pXmlWriter->WriteNodeEnd(L"w:ins");
}
if (!_writeAfterRun.empty())
{
m_pXmlWriter->WriteString(_writeAfterRun);
_writeAfterRun.clear();
}
}
else
{
--_skipRuns;
}
return result_cp;
}
// Writes the given text to the document
int DocumentMapping::writeText(std::vector<wchar_t>* chars, int initialCp, CharacterPropertyExceptions* chpx, bool writeDeletedText)
{
int cp = initialCp;
bool fSpec = isSpecial (chpx);
//detect text type
std::wstring textType = L"t";
std::wstring text;
if (writeDeletedText)
{
textType = std::wstring(L"delText");
}
else if ((!_fieldLevels.empty()) && (_fieldLevels.back().bBegin && !_fieldLevels.back().bSeparate))
{
textType = std::wstring(L"instrText");
}
//write text
for (unsigned int i = 0; i < chars->size(); ++i)
{
wchar_t c = chars->at(i), code = c;
if (TextMark::Tab == code)
{
writeTextElement(text, textType);
text.clear();
XMLTools::XMLElement elem(L"w:tab");
m_pXmlWriter->WriteString(elem.GetXMLString());
}
else if (TextMark::HardLineBreak == code)
{
writeTextElement(text, textType);
text.clear();
XMLTools::XMLElement elem(L"w:br");
elem.AppendAttribute(L"w:type", L"textWrapping");
elem.AppendAttribute(L"w:clear", L"all");
m_pXmlWriter->WriteString(elem.GetXMLString());
}
else if (TextMark::ParagraphEnd == code)
{
//do nothing
}
else if (TextMark::PageBreakOrSectionMark == code)
{
//write page break, section breaks are written by writeParagraph() method
if (/*!isSectionEnd(c)*/_isSectionPageBreak == 0)
{
writeTextElement(text, textType);
text.clear();
XMLTools::XMLElement elem(L"w:br");
elem.AppendAttribute(L"w:type", L"page");
m_pXmlWriter->WriteString(elem.GetXMLString());
}
}
else if (TextMark::ColumnBreak == code)
{
writeTextElement(text, textType);
text.clear();
XMLTools::XMLElement elem(L"w:br");
elem.AppendAttribute(L"w:type", L"column");
m_pXmlWriter->WriteString(elem.GetXMLString());
}
else if (TextMark::FieldBeginMark == code)
{
_fieldLevels.push_back(fieldLevels());
int cpFieldStart = initialCp + i;
int cpFieldEnd = searchNextTextMark( m_document->Text, cpFieldStart, TextMark::FieldEndMark );
std::wstring f, sFieldString;
if (cpFieldEnd < (int)m_document->Text->size())
sFieldString = std::wstring( ( m_document->Text->begin() + cpFieldStart ), ( m_document->Text->begin() + cpFieldEnd + 1 ) );
std::vector<std::wstring> arField;
boost::algorithm::split(arField, sFieldString, boost::algorithm::is_any_of(L"\\"), boost::algorithm::token_compress_on);
std::wstring EMBED ( L" EMBED" );
std::wstring LINK ( L" LINK" );
std::wstring FORM ( L" FORM" );
std::wstring Excel ( L" Excel" );
std::wstring Word ( L" Word" );
std::wstring opendocument(L" opendocument" );
std::wstring Equation ( L" Equation" );
std::wstring MERGEFORMAT( L" MERGEFORMAT" );
std::wstring QUOTE ( L" QUOTE" );
std::wstring chart ( L"Chart" );
std::wstring PBrush ( L" PBrush" );
std::wstring TOC ( L" TOC" );
std::wstring HYPERLINK ( L" HYPERLINK" );
std::wstring PAGEREF ( L" PAGEREF" );
std::wstring PAGE ( L"PAGE" );
if (arField.empty() == false)
f = arField[0];
else
f = sFieldString;
bool bChart = search( f.begin(), f.end(), chart.begin(), chart.end()) != f.end();
bool bEMBED = search( f.begin(), f.end(), EMBED.begin(), EMBED.end()) != f.end();
bool bLINK = search( f.begin(), f.end(), LINK.begin(), LINK.end()) != f.end();
bool bOpendocument = search( f.begin(), f.end(), opendocument.begin(), opendocument.end()) != f.end();
bool bFORM = search( f.begin(), f.end(), FORM.begin(), FORM.end()) != f.end();
bool bMERGEFORMAT = search( f.begin(), f.end(), MERGEFORMAT.begin(), MERGEFORMAT.end()) != f.end();
bool bExcel = search( f.begin(), f.end(), Excel.begin(), Excel.end()) != f.end();
bool bWord = search( f.begin(), f.end(), Word.begin(), Word.end()) != f.end();
bool bHYPERLINK = search( f.begin(), f.end(), HYPERLINK.begin(), HYPERLINK.end()) != f.end();
bool bQUOTE = search( f.begin(), f.end(), QUOTE.begin(), QUOTE.end()) != f.end();
bool bEquation = search( f.begin(), f.end(), Equation.begin(), Equation.end()) != f.end();
bool bPAGE = search( f.begin(), f.end(), PAGE.begin(), PAGE.end()) != f.end();
bool bTOC = search( f.begin(), f.end(), TOC.begin(), TOC.end()) != f.end();
bool bPAGEREF = false;
if (bHYPERLINK && arField.size() > 1)
{
std::wstring f1 = arField[1];
bPAGEREF = search( f1.begin(), f1.end(), PAGEREF.begin(), PAGEREF.end()) != f1.end();
}
if (bTOC)
_bContentWrite = true;
if ( bFORM )
{
std::wstring FORMTEXT ( L" FORMTEXT" );
std::wstring FORMCHECKBOX ( L" FORMCHECKBOX" );
std::wstring FORMDROPDOWN ( L" FORMDROPDOWN" );
m_pXmlWriter->WriteNodeBegin( L"w:fldChar" , true );
m_pXmlWriter->WriteAttribute( L"w:fldCharType" , L"begin" );
m_pXmlWriter->WriteNodeEnd( L"", true, false );
bool bFORMTEXT = search( f.begin(), f.end(), FORMTEXT.begin(), FORMTEXT.end()) != f.end();
bool bFORMCHECKBOX = search( f.begin(), f.end(), FORMCHECKBOX.begin(), FORMCHECKBOX.end()) != f.end();
bool bFORMDROPDOWN = search( f.begin(), f.end(), FORMDROPDOWN.begin(), FORMDROPDOWN.end()) != f.end();
if (bFORMTEXT || bFORMCHECKBOX || bFORMDROPDOWN)
{
int cpPic = searchNextTextMark( m_document->Text, cpFieldStart, TextMark::Picture );
if (cpPic < cpFieldEnd)
{
int fcPic = m_document->FindFileCharPos( cpPic );
std::list<CharacterPropertyExceptions*>* chpxs = m_document->GetCharacterPropertyExceptions(fcPic, fcPic + 1);
if (chpxs)
{
CharacterPropertyExceptions* chpxSep = chpxs->front();
FormFieldData ffdata (2, chpxSep, m_document->DataStream, false);
FormFieldDataMapping data_mapping(m_pXmlWriter, m_context, _caller);
ffdata.Convert(&data_mapping);
RELEASEOBJECT( chpxs );
}
}
}
m_pXmlWriter->WriteNodeEnd( L"w:fldChar" );
_fieldLevels.back().bBegin = true;
}
else if ( ( bMERGEFORMAT || bExcel || bWord || bOpendocument )
&&
( ( bEMBED || bLINK ) && bChart) )
{
m_pXmlWriter->WriteNodeBegin( L"w:fldChar", true );
m_pXmlWriter->WriteAttribute( L"w:fldCharType", L"begin" );
m_pXmlWriter->WriteNodeEnd( L"", true, false );
int cpPic = searchNextTextMark( m_document->Text, cpFieldStart, TextMark::Picture );
m_pXmlWriter->WriteNodeEnd( L"w:fldChar" );
_fieldLevels.back().bBegin = true;
}
else if (bHYPERLINK && bPAGEREF)
{
int cpFieldSep2 = cpFieldStart, cpFieldSep1 = cpFieldStart;
std::vector<std::wstring> toc;
if (arField.size() > 1)
f = arField[1];
if ( _bContentWrite )
{
m_pXmlWriter->WriteNodeBegin( L"w:fldChar", true );
m_pXmlWriter->WriteAttribute( L"w:fldCharType", L"begin" );
m_pXmlWriter->WriteNodeEnd( L"", true );
_fieldLevels.back().bBegin = true;
}
else
{
//while ( cpFieldSep2 < cpFieldEnd)
//{
// cpFieldSep2 = searchNextTextMark(m_document->Text, cpFieldSep1 + 1, TextMark::FieldSeparator);
// std::wstring f1( ( m_document->Text->begin() + cpFieldSep1 ), ( m_document->Text->begin() + cpFieldSep2 + 1 ) );
// toc.push_back(f1);
//
// if (search( f1.begin(), f1.end(), PAGEREF.begin(), PAGEREF.end()) != f1.end())
for (size_t i = 1; i < arField.size(); i++)
{
std::wstring f1 = arField[1];
int d = (int)f1.find(PAGEREF);
if (d > 0)
{
_writeWebHidden = true;
std::wstring _writeTocLink =f1.substr(d + 9);
d = (int)_writeTocLink.find(L" ");
_writeTocLink = _writeTocLink.substr(0, d);
_writeAfterRun = std::wstring (L"<w:hyperlink w:anchor = \"");
_writeAfterRun += _writeTocLink;
_writeAfterRun += std::wstring (L"\" w:history=\"1\">");
break;
//cp = cpFieldSep1;
}
//cpFieldSep1 = cpFieldSep2;
}
_skipRuns = 5; //with separator
}
}
//else if ( bHYPERLINK )
//{//todooo - выделение гиперссылки отдельно
// std::vector<std::wstring> arRefs;
// boost::algorithm::split(arRefs, f, boost::algorithm::is_any_of(L" "), boost::algorithm::token_compress_on);
//
// std::wstring sLink = arRefs[2];
// m_pXmlWriter->WriteNodeBegin( L"w:hyperlink", true );
// int relID = m_context->_docx->RegisterHyperlink(_caller, sLink);
// m_pXmlWriter->WriteAttribute( L"r:id", L"rId"+ FormatUtils::IntToWideString( relID ) );
// m_pXmlWriter->WriteAttribute( L"w:history", 1 );
// m_pXmlWriter->WriteNodeEnd( L"", true, false );
// if (arRefs.size() > 2)
// {
// writeTextElement(arRefs[3].substr(1, arRefs[3].length() - 2), textType);
// }
// m_pXmlWriter->WriteNodeEnd( L"w:hyperlink", false, true );
// _skipRuns = 1;
//}
else if ( bEMBED || (bLINK && !bHYPERLINK)|| bQUOTE)
{
int cpPic = searchNextTextMark(m_document->Text, cpFieldStart, TextMark::Picture);
int cpFieldSep = searchNextTextMark(m_document->Text, cpFieldStart, TextMark::FieldSeparator);
if (cpPic < cpFieldEnd)
{
int fcPic = m_document->FindFileCharPos( cpPic );
std::list<CharacterPropertyExceptions*>* chpxs = m_document->GetCharacterPropertyExceptions(fcPic, fcPic + 1);
CharacterPropertyExceptions* chpxObj = chpxs->front();
RevisionData oData = RevisionData(chpxObj);
CharacterPropertiesMapping* rPr = new CharacterPropertiesMapping(m_pXmlWriter, m_document, &oData, _lastValidPapx, false);
if(rPr)
{
chpxObj->Convert(rPr);
RELEASEOBJECT(rPr);
}
XMLTools::CStringXmlWriter oleWriter;
XMLTools::CStringXmlWriter oleObjectWriter;
VMLPictureMapping oVmlMapper (m_context, &oleWriter, true, _caller);
if (!m_shapeIdOwner.empty()) //4571833.doc
oVmlMapper.m_shapeId = m_shapeIdOwner;
if (m_document->bOlderVersion)
{
OleObject ole ( chpxObj, m_document->GetStorage(), m_document->bOlderVersion);
oleWriter.WriteNodeBegin (L"w:object", true);
oleWriter.WriteAttribute( L"w:dxaOrig", FormatUtils::IntToWideString( ( ole.pictureDesciptor.dxaGoal + ole.pictureDesciptor.dxaOrigin ) ));
oleWriter.WriteAttribute( L"w:dyaOrig", FormatUtils::IntToWideString( ( ole.pictureDesciptor.dyaGoal + ole.pictureDesciptor.dyaOrigin ) ));
oleWriter.WriteNodeEnd( L"", true, false );
ole.pictureDesciptor.Convert(&oVmlMapper);
OleObjectMapping oleObjectMapping( &oleObjectWriter, m_context, &ole.pictureDesciptor, _caller, oVmlMapper.m_shapeId);
ole.Convert( &oleObjectMapping );
_lastOLEObject = oleObjectWriter.GetXmlString();
}
else
{
PictureDescriptor pic(chpxObj, m_document->DataStream, 0x7fffffff, m_document->bOlderVersion);
oleWriter.WriteNodeBegin (L"w:object", true);
oleWriter.WriteAttribute( L"w:dxaOrig", FormatUtils::IntToWideString( ( pic.dxaGoal + pic.dxaOrigin ) ) );
oleWriter.WriteAttribute( L"w:dyaOrig", FormatUtils::IntToWideString( ( pic.dyaGoal + pic.dyaOrigin ) ) );
oleWriter.WriteNodeEnd( L"", true, false );
pic.Convert(&oVmlMapper);
RELEASEOBJECT(chpxs);
if ( cpFieldSep < cpFieldEnd && m_document->m_PieceTable)
{
int fcFieldSep = m_document->m_PieceTable->FileCharacterPositions->operator []( cpFieldSep );
int fcFieldSep1 = m_document->FindFileCharPos( cpFieldSep );
std::list<CharacterPropertyExceptions*>* chpxs = m_document->GetCharacterPropertyExceptions( fcFieldSep, ( fcFieldSep + 1 ) );
CharacterPropertyExceptions* chpxSep = chpxs->front();
OleObject ole ( chpxSep, m_document->GetStorage(), m_document->bOlderVersion);
OleObjectMapping oleObjectMapping( &oleObjectWriter, m_context, &pic, _caller, oVmlMapper.m_shapeId );
if (oVmlMapper.m_isEmbedded)
{
ole.isEquation = oVmlMapper.m_isEquation;
ole.isEmbedded = oVmlMapper.m_isEmbedded;
ole.emeddedData = oVmlMapper.m_embeddedData;
}
ole.Convert( &oleObjectMapping );
_lastOLEObject = oleObjectWriter.GetXmlString();
RELEASEOBJECT( chpxs );
}
}
oleWriter.WriteString( _lastOLEObject );
oleWriter.WriteNodeEnd( L"w:object" );
if (!oVmlMapper.m_isEmbedded && oVmlMapper.m_isEquation)
{
//нельзя в Run писать oMath
//m_pXmlWriter->WriteString(oVmlMapper.m_equationXml);
_writeAfterRun = oVmlMapper.m_equationXml;
}
else
{
m_pXmlWriter->WriteString(oleWriter.GetXmlString());
}
}
_skipRuns = 3;
_embeddedObject = true;
}
else
{
m_pXmlWriter->WriteNodeBegin( L"w:fldChar", true );
m_pXmlWriter->WriteAttribute( L"w:fldCharType", L"begin" );
m_pXmlWriter->WriteNodeEnd( L"", true );
_fieldLevels.back().bBegin = true;
}
}
else if (TextMark::FieldSeparator == code)
{
if (!_fieldLevels.empty())
{
_fieldLevels.back().bSeparate = true;
XMLTools::XMLElement elem( L"w:fldChar" );
elem.AppendAttribute( L"w:fldCharType", L"separate" );
m_pXmlWriter->WriteString( elem.GetXMLString() );
}
if (_embeddedObject) _skipRuns += 2;
}
else if (TextMark::FieldEndMark == code)
{
if (!_fieldLevels.empty())
{
if (!text.empty())
{
writeTextElement(text, textType);
text.clear();
}
if (_fieldLevels.back().bBegin)
{
_fieldLevels.back().bEnd = true;
XMLTools::XMLElement elem( L"w:fldChar" );
elem.AppendAttribute( L"w:fldCharType", L"end" );
m_pXmlWriter->WriteString( elem.GetXMLString());
}
_fieldLevels.pop_back();
}
if (_writeWebHidden)
{
_writeAfterRun = std::wstring (L"</w:hyperlink>");
}
_writeWebHidden = false;
_embeddedObject = false;
if (_fieldLevels.empty())
_bContentWrite = false;
}
else if ((TextMark::Symbol == code) && fSpec)
{
Symbol s = getSymbol( chpx );
//m_pXmlWriter->WriteNodeBegin(L"w:sym", true);
//m_pXmlWriter->WriteAttribute(L"w:font", FormatUtils::XmlEncode(s.FontName));
//m_pXmlWriter->WriteAttribute(L"w:char", FormatUtils::XmlEncode(s.HexValue));
//m_pXmlWriter->WriteNodeEnd(L"", true);
}
else if ((TextMark::DrawnObject == code) && fSpec)
{
Spa* pSpa = NULL;
if (typeid(*this) == typeid(MainDocumentMapping))
{
pSpa = static_cast<Spa*>(m_document->OfficeDrawingPlex->GetStruct(cp));
}
else if ((typeid(*this) == typeid(HeaderMapping) ) || ( typeid(*this) == typeid(FooterMapping)))
{
int headerCp = ( cp - m_document->FIB->m_RgLw97.ccpText - m_document->FIB->m_RgLw97.ccpFtn );
pSpa = static_cast<Spa*>(m_document->OfficeDrawingPlexHeader->GetStruct(headerCp));
}
if (pSpa)
{
PictureDescriptor pictDiscr(chpx, m_document->WordDocumentStream, 0x7fffffff, m_document->bOlderVersion);
ShapeContainer* pShape = m_document->GetOfficeArt()->GetShapeContainer(pSpa->GetShapeID());
if (pShape)
{
VMLShapeMapping oVmlWriter (m_context, m_pXmlWriter, pSpa, &pictDiscr, _caller);
m_pXmlWriter->WriteNodeBegin (L"w:pict");
pShape->Convert(&oVmlWriter);
m_pXmlWriter->WriteNodeEnd (L"w:pict");
}
if (!pSpa->primitives.empty())
{
m_pXmlWriter->WriteNodeBegin (L"w:pict");
VMLShapeMapping oVmlWriter (m_context, m_pXmlWriter, pSpa, &pictDiscr, _caller);
pSpa->primitives.Convert(&oVmlWriter);
m_pXmlWriter->WriteNodeEnd (L"w:pict");
}
}
}
else if ((TextMark::Picture == code) && fSpec )
{
PictureDescriptor oPicture (chpx, m_document->bOlderVersion ? m_document->WordDocumentStream : m_document->DataStream, 0x7fffffff, m_document->bOlderVersion);
bool isInline = _isTextBoxContent;
if (oPicture.embeddedData && oPicture.embeddedDataSize > 0)
{
m_pXmlWriter->WriteNodeBegin (L"w:pict");
VMLPictureMapping oVmlMapper(m_context, m_pXmlWriter, false, _caller, isInline);
oPicture.Convert (&oVmlMapper);
m_pXmlWriter->WriteNodeEnd (L"w:pict");
}
else if ((oPicture.mfp.mm > 98) && (NULL != oPicture.shapeContainer))
{
bool bFormula = false;
XMLTools::CStringXmlWriter pictWriter;
pictWriter.WriteNodeBegin (L"w:pict");
bool picture = true;
if (oPicture.shapeContainer)
{
int shape_type = oPicture.shapeContainer->getShapeType();
if (shape_type != msosptPictureFrame) picture = false;//шаблон 1.doc картинка в колонтитуле
}
if (picture)
{
VMLPictureMapping oVmlMapper(m_context, &pictWriter, false, _caller, isInline);
oPicture.Convert (&oVmlMapper);
if (oVmlMapper.m_isEmbedded)
{
OleObject ole ( chpx, m_document->GetStorage(), m_document->bOlderVersion);
OleObjectMapping oleObjectMapping( &pictWriter, m_context, &oPicture, _caller, oVmlMapper.m_shapeId );
ole.isEquation = oVmlMapper.m_isEquation;
ole.isEmbedded = oVmlMapper.m_isEmbedded;
ole.emeddedData = oVmlMapper.m_embeddedData;
ole.Convert( &oleObjectMapping );
}
else if (oVmlMapper.m_isEquation)
{
//нельзя в Run писать oMath
//m_pXmlWriter->WriteString(oVmlMapper.m_equationXml);
_writeAfterRun = oVmlMapper.m_equationXml;
bFormula = true;
}
}else
{
VMLShapeMapping oVmlMapper(m_context, &pictWriter, NULL, &oPicture, _caller, isInline);
oPicture.shapeContainer->Convert(&oVmlMapper);
}
pictWriter.WriteNodeEnd (L"w:pict");
if (!bFormula)
m_pXmlWriter->WriteString(pictWriter.GetXmlString());
}
}
else if ((TextMark::AutoNumberedFootnoteReference == code) && fSpec)
{
if ((m_document->FootnoteReferenceCharactersPlex != NULL) && (m_document->FootnoteReferenceCharactersPlex->IsCpExists(cp)))
{
m_pXmlWriter->WriteNodeBegin( L"w:footnoteReference", true );
m_pXmlWriter->WriteAttribute( L"w:id", FormatUtils::IntToWideString(_footnoteNr++ ) );
m_pXmlWriter->WriteNodeEnd( L"", true );
}
else if ((m_document->IndividualFootnotesPlex != NULL) && (m_document->IndividualFootnotesPlex->IsCpExists(cp - m_document->FIB->m_RgLw97.ccpText)))
{
m_pXmlWriter->WriteNodeBegin( L"w:footnoteRef", true );
m_pXmlWriter->WriteNodeEnd( L"", true );
}
else if ((m_document->EndnoteReferenceCharactersPlex != NULL) && (m_document->EndnoteReferenceCharactersPlex->IsCpExists(cp)))
{
m_pXmlWriter->WriteNodeBegin( L"w:endnoteReference", true );
m_pXmlWriter->WriteAttribute( L"w:id", FormatUtils::IntToWideString(_endnoteNr++ ));
m_pXmlWriter->WriteNodeEnd( L"", true );
}
else if ((m_document->IndividualEndnotesPlex != NULL) &&
(m_document->IndividualEndnotesPlex->IsCpExists(cp - m_document->FIB->m_RgLw97.ccpAtn - m_document->FIB->m_RgLw97.ccpHdr - m_document->FIB->m_RgLw97.ccpFtn - m_document->FIB->m_RgLw97.ccpText)))
{
m_pXmlWriter->WriteNodeBegin( L"w:endnoteRef", true );
m_pXmlWriter->WriteNodeEnd( L"", true );
}
}
else if (TextMark::AnnotationReference == code)
{
if (typeid(*this) == typeid(CommentsMapping))
{
m_pXmlWriter->WriteNodeBegin( L"w:annotationRef", true );
m_pXmlWriter->WriteNodeEnd( L"", true );
}
else
{
m_pXmlWriter->WriteNodeBegin( L"w:commentReference", true );
m_pXmlWriter->WriteAttribute( L"w:id", FormatUtils::IntToWideString( _commentNr ));
m_pXmlWriter->WriteNodeEnd( L"", true );
}
}
else if (!FormatUtils::IsControlSymbol(c) && ((int)c != 0xFFFF))
{
text += FormatUtils::GetXMLSymbol(c);
}
cp++;
}
if (!text.empty())
{
//bool preserve_space = (text.find(L"\x20")) != text.npos) ? true : false;
writeTextStart(textType, true/*preserve_space*/);
m_pXmlWriter->WriteString(text);
writeTextEnd(textType);
}
return cp;
}
void DocumentMapping::writeTextElement(const std::wstring& text, const std::wstring& textType)
{
if ( !text.empty() )
{
bool preserve_space = true;//(text.find(L"\x20")) != text.npos) ? true : false;
if (textType == L"instrText")
preserve_space = false;
writeTextStart( textType, preserve_space );
m_pXmlWriter->WriteString( text);
writeTextEnd( textType );
}
}
void DocumentMapping::writeTextStart(const std::wstring& textType, bool preserve_space)
{
std::wstring str = ( L"w:" + textType );
m_pXmlWriter->WriteNodeBegin( str, true );
if (preserve_space)
{
m_pXmlWriter->WriteAttribute( L"xml:space", L"preserve" );
}
m_pXmlWriter->WriteNodeEnd( L"", true, false );
}
void DocumentMapping::writeTextEnd(const std::wstring& textType)
{
std::wstring str = ( std::wstring( L"w:" ) + textType );
m_pXmlWriter->WriteNodeEnd( str );
}
// Searches for bookmarks in the list of characters.
std::vector<int> DocumentMapping::searchBookmarks(std::vector<wchar_t>* chars, int initialCp)
{
std::vector<int> ret;
if (m_document->BookmarkStartPlex->IsValid())
{
int cp = initialCp;
size_t count = chars->size();
for (size_t i = 0; i < count; ++i)
{
if ((m_document->BookmarkStartPlex->IsCpExists(cp)) || (m_document->BookmarkEndPlex->IsCpExists(cp)))
{
ret.push_back(i);
}
++cp;
}
}
return ret;
}
// Searches for bookmarks in the list of characters.
std::vector<int> DocumentMapping::searchAnnot(std::vector<wchar_t>* chars, int initialCp)
{
std::vector<int> ret;
if (m_document->AnnotStartPlex->IsValid())
{
int cp = initialCp;
size_t count = chars->size();
for (size_t i = 0; i < count; ++i)
{
if ((m_document->AnnotStartPlex->IsCpExists(cp)) || (m_document->AnnotEndPlex->IsCpExists(cp)))
{
ret.push_back(i);
}
++cp;
}
}
return ret;
}
ParagraphPropertyExceptions* DocumentMapping::findValidPapx(int fc)
{
ParagraphPropertyExceptions* ret = NULL;
std::vector<int>* pVector = m_document->AllPapxVector;
int nMin = 0;
int nMax = (int)pVector->size();
if( nMax > 0 )
{
while( nMin + 1 < nMax )
{
int nCurPos = (nMax + nMin) / 2;
int nCurVal = pVector->at(nCurPos);
if( nCurVal > fc )
nMax = nCurPos;
else if( nCurVal < fc )
nMin = nCurPos;
else
{
nMin = nCurPos;
break;
}
}
int nMinVal = pVector->at(nMin);
if ( fc >= nMinVal )
{
ret = m_document->AllPapx->find(nMinVal)->second;
_lastValidPapx = ret;
}
}
return ret;
}
std::list<std::vector<wchar_t> >* DocumentMapping::splitCharList(std::vector<wchar_t>* chars, std::vector<int>* splitIndices)
{
std::list<std::vector<wchar_t> >* ret = new std::list<std::vector<wchar_t> >();
std::vector<wchar_t> wcharVector;
int startIndex = 0;
// add the parts
for (unsigned int i = 0; i < splitIndices->size(); ++i)
{
int cch = splitIndices->at( i ) - startIndex;
if ( cch > 0 )
{
wcharVector = std::vector<wchar_t>( cch );
copy( chars->begin() + startIndex, chars->begin() + startIndex + cch, wcharVector.begin() );
ret->push_back( wcharVector );
}
wcharVector.clear();
startIndex += cch;
}
//add the last part
wcharVector = std::vector<wchar_t>( chars->size() - startIndex );
copy( chars->begin() + startIndex, chars->end(), wcharVector.begin() );
ret->push_back( wcharVector );
wcharVector.clear();
return ret;
}
// Writes the table starts at the given cp value
int DocumentMapping::writeTable(int initialCp, unsigned int nestingLevel)
{
int cp = initialCp;
int fc2 = m_document->FindFileCharPos( cp );
int fc = m_document->m_PieceTable->FileCharacterPositions->operator []( cp );
ParagraphPropertyExceptions* papx = findValidPapx( fc );
TableInfo tai( papx );
//build the table grid
std::vector<short> grid;
buildTableGrid( cp, nestingLevel, grid);
//find first row end
int fcRowEnd = findRowEndFc( cp, nestingLevel );
TablePropertyExceptions row1Tapx( findValidPapx( fcRowEnd ), m_document->DataStream, m_document->bOlderVersion);
//start table
m_pXmlWriter->WriteNodeBegin( L"w:tbl" );
//Convert it
TablePropertiesMapping *tpMapping = new TablePropertiesMapping( m_pXmlWriter, m_document->Styles, &grid);
row1Tapx.Convert( tpMapping );
RELEASEOBJECT( tpMapping );
//convert all rows
if ( nestingLevel > 1 )
{
//It's an inner table
//only convert the cells with the given nesting level
while ( tai.iTap == nestingLevel )
{
cp = writeTableRow( cp, &grid, nestingLevel );
//?fc = m_document->FindFileCharPos(cp );
fc = m_document->m_PieceTable->FileCharacterPositions->operator []( cp );
papx = findValidPapx( fc );
tai = TableInfo( papx );
}
}
else
{
//It's a outer table (nesting level 1)
//convert until the end of table is reached
while ( tai.fInTable )
{
cp = writeTableRow( cp, &grid, nestingLevel );
fc = m_document->FindFileCharPos( cp );
papx = findValidPapx( fc );
tai = TableInfo( papx );
}
}
//close w:tbl
m_pXmlWriter->WriteNodeEnd( L"w:tbl" );
return cp;
}
// Builds a list that contains the width of the several columns of the table.
bool DocumentMapping::buildTableGrid(int initialCp, unsigned int nestingLevel, std::vector<short>& grid)
{
ParagraphPropertyExceptions* backup = _lastValidPapx;
std::map<short, short> boundaries;
int cp = initialCp;
int fc = m_document->FindFileCharPos( cp );
ParagraphPropertyExceptions* papx = findValidPapx( fc );
TableInfo tai( papx );
int fcRowEnd = findRowEndFc( cp, cp, nestingLevel );
ParagraphPropertyExceptions* papx_prev = NULL;
short max_boundary = -1;
short count_column = 0;
while ( tai.fInTable )
{
short current_count_column = 0;
//check all SPRMs of this TAPX
for ( std::list<SinglePropertyModifier>::iterator iter = papx->grpprl->begin(); iter != papx->grpprl->end(); iter++ )
{
//find the tDef SPRM
DWORD code = iter->OpCode;
switch(iter->OpCode)
{
case sprmTDefTable:
case sprmOldTDefTable:
{
//SprmTDefTable tdef(iter->Arguments, iter->argumentsSize);
//int itcMac = tdef.numberOfColumns;
unsigned char itcMac = iter->Arguments[0];
short boundary1, boundary2;
for (unsigned char i = 0; i < itcMac; i++)
{
boundary1 = FormatUtils::BytesToInt16( iter->Arguments + 1, i * 2 , iter->argumentsSize );
boundary2 = FormatUtils::BytesToInt16( iter->Arguments + 1, ( i + 1 ) * 2, iter->argumentsSize );
AddBoundary(boundary1, boundary2, boundaries);
}
if (max_boundary < boundary2)
max_boundary = boundary2;
AddBoundary(boundary2, max_boundary, boundaries);
}break;
}
}
if (current_count_column > count_column)
count_column = current_count_column;
//get the next papx
papx = findValidPapx( fcRowEnd );
tai = TableInfo( papx );
fcRowEnd = findRowEndFc( cp, cp, nestingLevel );
if (papx_prev && papx_prev == papx )
break;//file(12).doc
papx_prev = papx;
}
if ( !boundaries.empty() )
{
for ( std::map<short, short>::iterator it = boundaries.begin(); it != boundaries.end(); ++it)
{
grid.push_back( it->second );
}
}
_lastValidPapx = backup;
return true;
}
void DocumentMapping::AddBoundary(short boundary1, short boundary2, std::map<short, short> &boundaries)
{
if (boundary2 - boundary1 < 10)
return;
std::map<short, short>::iterator pFind = boundaries.find(boundary1);
while(true)
{
if (pFind == boundaries.end())
{
boundaries.insert(std::make_pair(boundary1, boundary2 - boundary1));
break;
}
else if (pFind->second != boundary2 - boundary1)
{
if (pFind->second > boundary2 - boundary1)
{
short new_size = boundary2 - boundary1;
boundary1 = boundary2;
boundary2 = pFind->second + pFind->first;
pFind->second = new_size;
}
else
{
boundary1 = pFind->second + pFind->first;
}
pFind = boundaries.find(boundary1);
}
else
break;
}
}
// Finds the FC of the next row end mark.
int DocumentMapping::findRowEndFc(int initialCp, int& rowEndCp, unsigned int nestingLevel )
{
int cp = initialCp;
int fc = m_document->FindFileCharPos( cp );
ParagraphPropertyExceptions* papx = findValidPapx( fc );
TableInfo tai( papx );
if ( nestingLevel > 1 )
{
//Its an inner table.
//Search the "inner table trailer paragraph"
while ( ( tai.fInnerTtp == false ) && ( tai.fInTable == true ) )
{
while ( m_document->Text->at( cp ) != TextMark::ParagraphEnd )
{
cp++;
}
fc = m_document->FindFileCharPos( cp );
papx = findValidPapx( fc );
tai = TableInfo( papx );
cp++;
}
}
else
{
//Its an outer table.
//Search the "table trailer paragraph"
while ( ( tai.fTtp == false ) && ( tai.fInTable == true ) )
{
while ( true )
{
if (cp >= m_document->Text->size())
break;
if (m_document->Text->at( cp ) == TextMark::CellOrRowMark)
break;
cp++;
}
fc = m_document->FindFileCharPos( cp );
papx = findValidPapx( fc );
tai = TableInfo( papx );
cp++;
}
}
rowEndCp = cp;
return fc;
}
// Finds the FC of the next row end mark.
int DocumentMapping::findRowEndFc(int initialCp, unsigned int nestingLevel )
{
if ( initialCp > m_document->Text->size() - 1)
return initialCp;
int cp = initialCp;
int fc = m_document->FindFileCharPos( cp );
ParagraphPropertyExceptions* papx = findValidPapx( fc );
TableInfo tai( papx );
if ( nestingLevel > 1 )
{
//Its an inner table.
//Search the "inner table trailer paragraph"
while ( ( tai.fInnerTtp == false ) && ( tai.fInTable == true ) )
{
while ( true )
{
if (cp > m_document->Text->size() - 1 )
break;
if (m_document->Text->at( cp ) == TextMark::ParagraphEnd)
break;
cp++;
}
fc = m_document->FindFileCharPos( cp );
papx = findValidPapx( fc );
tai = TableInfo( papx );
cp++;
}
}
else
{
//Its an outer table.
//Search the "table trailer paragraph"
while ( ( tai.fTtp == false ) && ( tai.fInTable == true ) )
{
while (true)
{
if (cp > m_document->Text->size() - 1 )
break;
if (m_document->Text->at( cp ) == TextMark::CellOrRowMark)
break;
cp++;
}
fc = m_document->FindFileCharPos( cp );
papx = findValidPapx( fc );
tai = TableInfo( papx );
cp++;
}
}
return fc;
}
/// Writes the table row that starts at the given cp value and ends at the next row end mark
int DocumentMapping::writeTableRow(int initialCp, std::vector<short>* grid, unsigned int nestingLevel)
{
int cp = initialCp;
int fc = m_document->FindFileCharPos( cp );
ParagraphPropertyExceptions* papx = findValidPapx( fc );
TableInfo tai( papx );
//start w:tr
m_pXmlWriter->WriteNodeBegin( L"w:tr" );
//convert the properties
int fcRowEnd = findRowEndFc( cp, nestingLevel );
TablePropertyExceptions tapx( findValidPapx( fcRowEnd ), m_document->DataStream, m_document->bOlderVersion);
std::list<CharacterPropertyExceptions*>* chpxs = m_document->GetCharacterPropertyExceptions( fcRowEnd, fcRowEnd + 1 );
TableRowPropertiesMapping* trpMapping = new TableRowPropertiesMapping( m_pXmlWriter, *(chpxs->begin()) );
tapx.Convert( trpMapping );
RELEASEOBJECT( trpMapping );
int gridIndex = 0;
int cellIndex = 0;
if ( nestingLevel > 1 )
{
//It's an inner table.
//Write until the first "inner trailer paragraph" is reached
while ( !( ( m_document->Text->at( cp ) == TextMark::ParagraphEnd ) && ( tai.fInnerTtp ) ) && tai.fInTable )
{
cp = writeTableCell( cp, &tapx, grid, gridIndex, cellIndex, nestingLevel );
cellIndex++;
//each cell has it's own PAPX
fc = m_document->FindFileCharPos(cp );
papx = findValidPapx( fc );
tai = TableInfo( papx );
}
}
else
{
//It's a outer table
//Write until the first "row end trailer paragraph" is reached
while ( !( ( m_document->Text->at( cp ) == TextMark::CellOrRowMark ) && ( tai.fTtp ) )
&& tai.fInTable )
{
cp = writeTableCell( cp, &tapx, grid, gridIndex, cellIndex, nestingLevel );
cellIndex++;
//each cell has it's own PAPX
fc = m_document->FindFileCharPos( cp );
papx = findValidPapx( fc );
tai = TableInfo( papx );
}
}
//end w:tr
m_pXmlWriter->WriteNodeEnd( L"w:tr" );
//skip the row end mark
cp++;
RELEASEOBJECT( chpxs );
return cp;
}
/// Writes the table cell that starts at the given cp value and ends at the next cell end mark
int DocumentMapping::writeTableCell(int initialCp, TablePropertyExceptions* tapx, std::vector<short>* grid, int& gridIndex, int cellIndex, unsigned int nestingLevel )
{
int cp = initialCp;
int cpCellEnd = findCellEndCp( initialCp, nestingLevel );
//start w:tc
m_pXmlWriter->WriteNodeBegin( L"w:tc" );
TableCellPropertiesMapping* tcpMapping = new TableCellPropertiesMapping( m_pXmlWriter, grid, gridIndex, cellIndex );
if ( tapx != NULL )
{
tapx->Convert( tcpMapping );
}
gridIndex = gridIndex + tcpMapping->GetGridSpan();
RELEASEOBJECT( tcpMapping );
//write the paragraphs of the cell
while ( cp < cpCellEnd )
{
//cp = writeParagraph(cp);
int fc = m_document->FindFileCharPos( cp );
ParagraphPropertyExceptions* papx = findValidPapx( fc );
TableInfo tai( papx );
//cp = writeParagraph(cp);
//!!!TODO: Inner Tables!!!
if ( tai.iTap > nestingLevel )
{
//write the inner table if this is not a inner table (endless loop)
cp = writeTable( cp, tai.iTap );
//after a inner table must be at least one paragraph
/*if ( cp >= cpCellEnd )
{
m_pXmlWriter->WriteNodeBegin( L"w:p" );
m_pXmlWriter->WriteNodeEnd( L"w:p" );
}*/
}
else
{
//this PAPX is for a normal paragraph
cp = writeParagraph( cp );
}
}
//end w:tc
m_pXmlWriter->WriteNodeEnd( L"w:tc" );
return cp;
}
int DocumentMapping::findCellEndCp(int initialCp, unsigned int nestingLevel)
{
int cpCellEnd = initialCp;
if ( nestingLevel > 1 )
{
int fc = m_document->FindFileCharPos( initialCp );
ParagraphPropertyExceptions* papx = findValidPapx( fc );
TableInfo tai( papx );
while ( !tai.fInnerTableCell )
{
cpCellEnd++;
fc = m_document->FindFileCharPos( cpCellEnd );
papx = findValidPapx( fc );
tai = TableInfo( papx );
}
cpCellEnd++;
}
else
{
while ( m_document->Text->at( cpCellEnd ) != TextMark::CellOrRowMark )
{
cpCellEnd++;
}
cpCellEnd++;
}
return cpCellEnd;
}
bool DocumentMapping::writeBookmarks(int cp)
{
bool result = true;
int count = (int)m_document->BookmarkStartEndCPs.size();
for (int b = 0; b < count; ++b)
{
if (m_document->BookmarkStartEndCPs[b].first == cp)
{
result = writeBookmarkStart(b);
}
if (m_document->BookmarkStartEndCPs[b].second == cp)
{
result = writeBookmarkEnd(b);
}
}
return result;
}
bool DocumentMapping::writeAnnotations(int cp)
{
bool result = true;
for (size_t i = 0; i < m_document->AnnotStartEndCPs.size(); i++)
{
if (m_document->AnnotStartEndCPs[i].first == cp)
{
result = writeAnnotationStart(i + 1);
_commentNr = i + 1;
}
if (m_document->AnnotStartEndCPs[i].second == cp)
{
result = writeAnnotationEnd(i + 1);
_commentNr = i + 1;
}
}
return result;
}
bool DocumentMapping::writeBookmarkStart(short id)
{
// write bookmark start
WideString* bookmarkName = static_cast<WideString*>(m_document->BookmarkNames->operator [](id));
if ((bookmarkName != NULL) && (*bookmarkName != L"_PictureBullets"))
{
XMLTools::XMLElement bookmarkElem(L"w:bookmarkStart");
bookmarkElem.AppendAttribute(L"w:id", FormatUtils::IntToWideString(id));
bookmarkElem.AppendAttribute(L"w:name", *bookmarkName);
m_pXmlWriter->WriteString(bookmarkElem.GetXMLString());
return true;
}
return false;
}
bool DocumentMapping::writeBookmarkEnd(short id)
{
WideString* bookmarkName = static_cast<WideString*>( m_document->BookmarkNames->operator [] ( id ) );
if ( ( bookmarkName != NULL ) && ( *bookmarkName != L"_PictureBullets" ) )
{
XMLTools::XMLElement bookmarkElem( L"w:bookmarkEnd" );
bookmarkElem.AppendAttribute( L"w:id", FormatUtils::IntToWideString( id ));
m_pXmlWriter->WriteString( bookmarkElem.GetXMLString());
return true;
}
return false;
}
bool DocumentMapping::writeAnnotationStart(short id)
{
XMLTools::XMLElement bookmarkElem(L"w:commentRangeStart");
bookmarkElem.AppendAttribute(L"w:id", FormatUtils::IntToWideString(id));
m_pXmlWriter->WriteString(bookmarkElem.GetXMLString());
return true;
}
bool DocumentMapping::writeAnnotationEnd(short id)
{
XMLTools::XMLElement bookmarkElem( L"w:commentRangeEnd" );
bookmarkElem.AppendAttribute( L"w:id", FormatUtils::IntToWideString( id ));
m_pXmlWriter->WriteString( bookmarkElem.GetXMLString());
return true;
}
// Checks if the CHPX is special
bool DocumentMapping::isSpecial(CharacterPropertyExceptions* chpx)
{
/*
for (list<SinglePropertyModifier>::iterator iter = chpx->grpprl->begin(); iter != chpx->grpprl->end(); ++iter)
{
short value = FormatUtils::BytesToInt16 (iter->Arguments, 0, iter->argumentsSize);
int c = 0;
}
*/
for (std::list<SinglePropertyModifier>::iterator iter = chpx->grpprl->begin(); iter != chpx->grpprl->end(); ++iter)
{
if ((sprmCPicLocation == iter->OpCode) || (sprmCHsp == iter->OpCode)) // PICTURE
{
return true;
}
else if ( sprmCSymbol == iter->OpCode ||
sprmOldCSymbol == iter->OpCode) // SYMBOL
{
return true;
}
else if ( sprmOldCFSpec == iter->OpCode ||
sprmCFSpec == iter->OpCode) // SPECIAL OBJECT
{
return ((0 != iter->Arguments[0]) ? true : false);
}
}
return false;
}
Symbol DocumentMapping::getSymbol(const CharacterPropertyExceptions* chpx)
{
Symbol ret;
for (std::list<SinglePropertyModifier>::const_iterator iter = chpx->grpprl->begin(); iter != chpx->grpprl->end(); ++iter)
{
if (DocFileFormat::sprmCSymbol == iter->OpCode)
{
short fontIndex = FormatUtils::BytesToInt16( iter->Arguments, 0, iter->argumentsSize );
short code = FormatUtils::BytesToInt16( iter->Arguments, 2, iter->argumentsSize );
FontFamilyName* ffn = static_cast<FontFamilyName*>( m_document->FontTable->operator [] ( fontIndex ) );
ret.FontName = ffn->xszFtn;
ret.HexValue = FormatUtils::IntToFormattedWideString( code, L"%04x" );
break;
}
else if (DocFileFormat::sprmOldCSymbol == iter->OpCode)
{
short fontIndex = FormatUtils::BytesToInt16( iter->Arguments, 0, iter->argumentsSize ) ;
short code = FormatUtils::BytesToUChar( iter->Arguments, 2, iter->argumentsSize );
FontFamilyName* ffn = static_cast<FontFamilyName*>( m_document->FontTable->operator [] ( fontIndex ) );
ret.FontName = ffn->xszFtn;
ret.HexValue = L"f0" + FormatUtils::IntToFormattedWideString( code, L"%02x" );//-123 - ShortToFormattedWideString
break;
}
}
if (ret.HexValue.length() > 4)
{
ret.HexValue = ret.HexValue.substr(ret.HexValue.length() - 4, 4);
}
return ret;
}
/// Finds the SEPX that is valid for the given CP.
SectionPropertyExceptions* DocumentMapping::findValidSepx (int cp)
{
SectionPropertyExceptions* ret = NULL;
try
{
ret = m_document->AllSepx->operator [](cp);
_lastValidSepx = ret;
}
///!!!TODO!!!
catch ( ... )
{
//there is no SEPX at this position,
//so the previous SEPX is valid for this cp
int lastKey = m_document->SectionPlex->CharacterPositions[1];
for (std::map<int, SectionPropertyExceptions*>::iterator iter = m_document->AllSepx->begin(); iter != m_document->AllSepx->end(); ++iter)
{
if ( ( cp > lastKey ) && ( cp < iter->first ) )
{
ret = m_document->AllSepx->operator []( lastKey );
break;
}
else
{
lastKey = iter->first;
}
}
}
return ret;
}
// Searches the given vector for the next FieldEnd character.
int DocumentMapping::searchNextTextMark (std::vector<wchar_t>* chars, int initialCp, wchar_t mark)
{
int ret = initialCp;
size_t count = chars->size();
for (size_t i = initialCp; i < count; ++i)
{
if (chars->at(i) == mark)
{
ret = i;
break;
}
}
return ret;
}
}