4#include "Stroika/Frameworks/StroikaPreComp.h"
12#if qStroika_Platform_Windows
13#include "Stroika/Foundation/Characters/Platform/Windows/CodePage.h"
19#include "Stroika/Foundation/DataExchange/BadFormatException.h"
20#if qStroika_Platform_Windows
21#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
24#include "Stroika/Frameworks/Led/Config.h"
26#include "Stroika/Frameworks/Led/Support.h"
28#include "StyledTextIO_RTF.h"
30#define qUseCompiledSetHack_ true
35using namespace Stroika::Frameworks;
36using namespace Stroika::Frameworks::Led;
37using namespace Stroika::Frameworks::Led::StyledTextIO;
39#if qStroika_Platform_Windows
44 inline int ConvertReadSingleHexDigit_ (
char digit)
46 if (isupper (digit)) {
47 digit =
static_cast<char> (tolower (digit));
49 if (isdigit (digit)) {
52 else if (islower (digit)) {
53 return 10 + (digit -
'a');
56 Execution::Throw (DataExchange::BadFormatException::kThe);
61 inline char ConvertWriteSingleHexDigit_ (
int numZeroToFifteen)
63 Require (numZeroToFifteen >= 0);
64 Require (numZeroToFifteen <= 15);
65 if (numZeroToFifteen < 10) {
66 return static_cast<char> (
'0' + numZeroToFifteen);
69 return static_cast<char> (
'a' + (numZeroToFifteen - 10));
74 inline static LineSpacing mkLineSpacing_From_RTFValues_ (CoordinateType sl,
bool multi)
85 if (sl < 0 or sl > 2000) {
88 result = LineSpacing (LineSpacing::eExactLinesSpacing, sl / 12);
92 result = LineSpacing (LineSpacing::eExactTWIPSSpacing, TWIPS (-sl));
95 result = LineSpacing (LineSpacing::eAtLeastTWIPSSpacing, TWIPS (sl));
101 inline static void mkRTFValues_From_LineSpacing (LineSpacing inLS, CoordinateType* sl,
bool* multi)
103 const int kOneLinesWorth = 240;
104 switch (inLS.fRule) {
105 case LineSpacing::eOnePointFiveSpace:
106 *sl =
static_cast<CoordinateType
> (kOneLinesWorth * 1.5);
109 case LineSpacing::eDoubleSpace:
110 *sl = kOneLinesWorth * 2;
113 case LineSpacing::eAtLeastTWIPSSpacing:
117 case LineSpacing::eExactTWIPSSpacing:
118 *sl = -
static_cast<CoordinateType
> (inLS.fArg);
121 case LineSpacing::eExactLinesSpacing:
122 *sl = inLS.fArg * 12;
127 case LineSpacing::eSingleSpace:
140RTFIO::FontTableEntry::FontTableEntry ()
144 , fCharSet (static_cast<uint8_t> (-1))
155using FontTableEntry = RTFIO::FontTableEntry;
156using FontTable = RTFIO::FontTable;
157FontTable::FontTable ()
162FontTable::FontTable (
const vector<FontTableEntry>& fontTable)
163 : fEntries{fontTable}
167IncrementalFontSpecification FontTable::GetFontSpec (
int fontNumber)
169 const FontTableEntry* ftep = LookupEntryByNumber (fontNumber);
170 if (ftep ==
nullptr) {
171 return IncrementalFontSpecification{};
173 IncrementalFontSpecification fontSpec;
174#if qStroika_Platform_Windows
175 fontSpec.SetFontNameSpecifier (ftep->fFontName.c_str ());
180const FontTableEntry* FontTable::LookupEntryByNumber (
int fontNumber)
182 for (
size_t i = 0; i < fEntries.size (); ++i) {
183 const FontTableEntry& fte = fEntries[i];
184 if (fte.fFNum == fontNumber) {
191const FontTableEntry* FontTable::LookupEntryByName (
const SDKString& name)
193 for (
size_t i = 0; i < fEntries.size (); ++i) {
194 const FontTableEntry& fte = fEntries[i];
195 if (fte.fFontName == name) {
202FontTableEntry FontTable::Add (
const FontTableEntry& newEntry)
204 int newFontNumber = FindSmallestUnusedFontNumber ();
205 FontTableEntry newerEntry = newEntry;
206 newerEntry.fFNum = newFontNumber;
207 fEntries.push_back (newerEntry);
211int FontTable::FindSmallestUnusedFontNumber ()
const
216 for (
size_t i = 0; i < fEntries.size (); ++i) {
217 const FontTableEntry& fte = fEntries[i];
218 if (fte.fFNum == tryThis) {
231RTFIO::ColorTable::ColorTable ()
236RTFIO::ColorTable::ColorTable (
const vector<Color>& colorTable)
237 : fEntries (colorTable)
241Color RTFIO::ColorTable::LookupColor (
size_t colorNumber)
const
243 if (colorNumber < 0 or colorNumber >= fEntries.size ()) {
244 Execution::Throw (DataExchange::BadFormatException::kThe);
246 return fEntries[colorNumber];
249size_t RTFIO::ColorTable::LookupColor (
const Color& color)
const
251 for (
size_t i = 0; i < fEntries.size (); ++i) {
252 const Color& c = fEntries[i];
261size_t RTFIO::ColorTable::EnterColor (
const Color& color)
263 for (
size_t i = 0; i < fEntries.size (); ++i) {
264 const Color& c = fEntries[i];
269 fEntries.push_back (color);
270 return fEntries.size () - 1;
279RTFIO::ListTableEntry::ListTableEntry ()
281 , fListTemplateID (0)
282 , fListStyle (eListStyle_None)
292RTFIO::ListOverrideTableEntry::ListOverrideTableEntry ()
302RTFIO::ListTables::ListTables ()
304 , fOverrideEntries ()
308RTFIO::ListTables::ListTables (
const vector<ListTableEntry>& listTableEntries,
const vector<ListOverrideTableEntry>& listOverrideTableEntries)
309 : fEntries (listTableEntries)
310 , fOverrideEntries (listOverrideTableEntries)
319#if qStroika_Frameworks_Led_SupportGDI
320const Led_PrivateEmbeddingTag RTFIO::kRTFBodyGroupFragmentEmbeddingTag =
"RTFBFrag";
321#if qStroika_Platform_Windows
322const Led_ClipFormat RTFIO::kRTFBodyGroupFragmentClipFormat =
static_cast<Led_ClipFormat
> (::RegisterClipboardFormat (_T(
"RTFF")));
324const Led_ClipFormat RTFIO::kRTFBodyGroupFragmentClipFormat =
static_cast<Led_ClipFormat
> (
'RTFF');
328inline RTFIO::ControlWordNameMap RTFIO::mkDefaultControlWordNameMap ()
330 RTFIO::ControlWordNameMap table;
331#if qStroika_Frameworks_Led_UseMapForControlWordMap
332#define TAB_INS_METHOD(name) \
333 Assert (table.size () == RTFIO::eControlAtom_##name); \
334 table.insert (ControlWordNameMap::value_type (#name, RTFIO::eControlAtom_##name))
336#define TAB_INS_METHOD(name) \
337 Assert (table.size () == RTFIO::eControlAtom_##name); \
338 table.push_back (ControlWordNameMap::value_type (#name, RTFIO::eControlAtom_##name))
341 TAB_INS_METHOD (tab);
342 TAB_INS_METHOD (bullet);
343 TAB_INS_METHOD (endash);
344 TAB_INS_METHOD (emdash);
345 TAB_INS_METHOD (lquote);
346 TAB_INS_METHOD (rquote);
347 TAB_INS_METHOD (ldblquote);
348 TAB_INS_METHOD (rdblquote);
350 TAB_INS_METHOD (ansi);
351 TAB_INS_METHOD (author);
353 TAB_INS_METHOD (blue);
354 TAB_INS_METHOD (brdrs);
355 TAB_INS_METHOD (brdrth);
356 TAB_INS_METHOD (brdrsh);
357 TAB_INS_METHOD (brdrdb);
358 TAB_INS_METHOD (brdrdot);
359 TAB_INS_METHOD (brdrdash);
360 TAB_INS_METHOD (brdrhair);
361 TAB_INS_METHOD (brdrdashsm);
362 TAB_INS_METHOD (brdrdashd);
363 TAB_INS_METHOD (brdrdashdd);
364 TAB_INS_METHOD (brdrtriple);
365 TAB_INS_METHOD (brdrtnthsg);
366 TAB_INS_METHOD (brdrthtnsg);
367 TAB_INS_METHOD (brdrtnthtnsg);
368 TAB_INS_METHOD (brdrtnthmg);
369 TAB_INS_METHOD (brdrthtnmg);
370 TAB_INS_METHOD (brdrtnthtnmg);
371 TAB_INS_METHOD (brdrtnthlg);
372 TAB_INS_METHOD (brdrthtnlg);
373 TAB_INS_METHOD (brdrtnthtnlg);
374 TAB_INS_METHOD (brdrwavy);
375 TAB_INS_METHOD (brdrwavydb);
376 TAB_INS_METHOD (brdrdashdotstr);
377 TAB_INS_METHOD (brdremboss);
378 TAB_INS_METHOD (brdrengrave);
379 TAB_INS_METHOD (brdrw);
380 TAB_INS_METHOD (brdrcf);
381 TAB_INS_METHOD (cchs);
382 TAB_INS_METHOD (cell);
383 TAB_INS_METHOD (cellx);
385 TAB_INS_METHOD (clcbpat);
386 TAB_INS_METHOD (cpg);
387 TAB_INS_METHOD (colortbl);
388 TAB_INS_METHOD (deff);
389 TAB_INS_METHOD (deflang);
390 TAB_INS_METHOD (deftab);
391 TAB_INS_METHOD (deleted);
392 TAB_INS_METHOD (dibitmap);
394 TAB_INS_METHOD (emfblip);
396 TAB_INS_METHOD (fbidi);
397 TAB_INS_METHOD (fcharset);
398 TAB_INS_METHOD (fdecor);
400 TAB_INS_METHOD (fmodern);
401 TAB_INS_METHOD (footer);
402 TAB_INS_METHOD (fnil);
403 TAB_INS_METHOD (fonttbl);
404 TAB_INS_METHOD (fprq);
405 TAB_INS_METHOD (froman);
407 TAB_INS_METHOD (fswiss);
408 TAB_INS_METHOD (fscript);
409 TAB_INS_METHOD (ftech);
410 TAB_INS_METHOD (green);
411 TAB_INS_METHOD (header);
413 TAB_INS_METHOD (ilvl);
414 TAB_INS_METHOD (info);
415 TAB_INS_METHOD (intbl);
416 TAB_INS_METHOD (jpegblip);
418 TAB_INS_METHOD (line);
419 TAB_INS_METHOD (listtext);
420 TAB_INS_METHOD (ledprivateobjectembeddingformat);
422 TAB_INS_METHOD (mac);
423 TAB_INS_METHOD (macpict);
424 TAB_INS_METHOD (margb);
425 TAB_INS_METHOD (margl);
426 TAB_INS_METHOD (margr);
427 TAB_INS_METHOD (margt);
428 TAB_INS_METHOD (objdata);
429 TAB_INS_METHOD (
object);
430 TAB_INS_METHOD (objemb);
431 TAB_INS_METHOD (objh);
432 TAB_INS_METHOD (objscalex);
433 TAB_INS_METHOD (objscaley);
434 TAB_INS_METHOD (objw);
435 TAB_INS_METHOD (outl);
436 TAB_INS_METHOD (paperh);
437 TAB_INS_METHOD (paperw);
438 TAB_INS_METHOD (par);
439 TAB_INS_METHOD (pard);
441 TAB_INS_METHOD (pca);
442 TAB_INS_METHOD (pich);
443 TAB_INS_METHOD (pichgoal);
444 TAB_INS_METHOD (picscalex);
445 TAB_INS_METHOD (picscaley);
446 TAB_INS_METHOD (pict);
447 TAB_INS_METHOD (picw);
448 TAB_INS_METHOD (picwgoal);
449 TAB_INS_METHOD (plain);
450 TAB_INS_METHOD (pmmetafile);
452 TAB_INS_METHOD (pngblip);
453 TAB_INS_METHOD (pntext);
458 TAB_INS_METHOD (red);
459 TAB_INS_METHOD (result);
461 TAB_INS_METHOD (row);
462 TAB_INS_METHOD (rtf);
465 TAB_INS_METHOD (shad);
467 TAB_INS_METHOD (slmult);
468 TAB_INS_METHOD (sub);
469 TAB_INS_METHOD (super);
470 TAB_INS_METHOD (strike);
471 TAB_INS_METHOD (stylesheet);
472 TAB_INS_METHOD (trleft);
473 TAB_INS_METHOD (trgaph);
474 TAB_INS_METHOD (trowd);
475 TAB_INS_METHOD (trpaddb);
476 TAB_INS_METHOD (trpaddl);
477 TAB_INS_METHOD (trpaddr);
478 TAB_INS_METHOD (trpaddt);
479 TAB_INS_METHOD (trspdb);
480 TAB_INS_METHOD (trspdl);
481 TAB_INS_METHOD (trspdr);
482 TAB_INS_METHOD (trspdt);
487 TAB_INS_METHOD (ulnone);
490 TAB_INS_METHOD (wbitmap);
491 TAB_INS_METHOD (wmetafile);
493 Assert (table.size () == RTFIO::eControlAtomDynamicRangeStart);
494#if !qStroika_Frameworks_Led_UseMapForControlWordMap
495 sort (table.begin (), table.end ());
499RTFIO::ControlWordNameMap RTFIO::sControlWordNameMap = RTFIO::mkDefaultControlWordNameMap ();
501string RTFIO::GetAtomName (ControlWordAtom atom)
503 using ITER = RTFIO::ControlWordNameMap::const_iterator;
504 ITER start = sControlWordNameMap.begin ();
505 ITER end = sControlWordNameMap.end ();
506 for (ITER it = start; it != end; ++it) {
507 if (it->second == atom) {
508 return string{it->first};
515#if !qStroika_Frameworks_Led_UseMapForControlWordMap
516struct RTFIO::StringNControlWordAtom_Comparator : binary_function<RTFIO::StringNControlWordAtom, const char*, bool> {
517 bool operator() (
const RTFIO::StringNControlWordAtom& x,
const char* y)
const
523RTFIO::ControlWordAtom RTFIO::EnterControlWord (
524#
if qStroika_Frameworks_Led_UseMapForControlWordMap
525 const ControlWordAtomName& controlWord
527 const char* controlWord
531#if !qStroika_Frameworks_Led_UseMapForControlWordMap
535 using ITER = ControlWordNameMap::iterator;
536#if qStroika_Frameworks_Led_UseMapForControlWordMap
537 ITER i = sControlWordNameMap.find (controlWord);
538 if (i == sControlWordNameMap.end ()) {
539 ControlWordAtom newVal = ControlWordAtom (eControlAtomDynamicRangeStart + sControlWordNameMap.size ());
540 i = sControlWordNameMap.insert (ControlWordNameMap::value_type (controlWord, newVal)).first;
544 ITER start = sControlWordNameMap.begin ();
545 ITER end = sControlWordNameMap.end ();
546 ITER i = lower_bound (start, end, controlWord, StringNControlWordAtom_Comparator ());
547 if (i != end and controlWord == (*i).first) {
550 ControlWordAtom newVal = ControlWordAtom (eControlAtomDynamicRangeStart + sControlWordNameMap.size ());
551 sControlWordNameMap.insert (i, ControlWordNameMap::value_type (controlWord, newVal));
556#if qStroika_Frameworks_Led_SupportGDI
562const Led_PrivateEmbeddingTag RTFIO::RTFOLEEmbedding::kEmbeddingTag =
"OLE2RTFEm";
570using ReaderContext = StyledTextIOReader_RTF::ReaderContext;
600using SinkStreamDestination = ReaderContext::SinkStreamDestination;
601StyledTextIOReader_RTF::ReaderContext::SinkStreamDestination::SinkStreamDestination (StyledTextIOReader_RTF& reader)
603 , fSinkStream{reader.GetSinkStream ()}
604 , fRTFInfo{reader.GetRTFInfo ()}
609SinkStreamDestination::~SinkStreamDestination ()
614 Require (fTCharsInSmallBuffer == 0);
617void SinkStreamDestination::AppendText (
const Led_tChar* text,
size_t nTChars)
620 AppendText_ (text, nTChars);
623#if qStroika_Frameworks_Led_SupportGDI
624void SinkStreamDestination::AppendEmbedding (SimpleEmbeddedObjectStyleMarker* embedding)
633 fSinkStream.AppendEmbedding (embedding);
637void SinkStreamDestination::AppendSoftLineBreak ()
641 fSinkStream.AppendSoftLineBreak ();
644void SinkStreamDestination::EndParagraph ()
647 fParaEndedFlag =
true;
650void SinkStreamDestination::UseFont (
const IncrementalFontSpecification& fontSpec)
653 if (fCurrentContext.fFontSpec != fontSpec) {
655 fCurrentContext.fFontSpec = fontSpec;
659void SinkStreamDestination::SetJustification (Justification justification)
662 if (fCurrentContext.fJustification != justification) {
664 fSinkStream.SetJustification (fCurrentContext.fJustification = justification);
668void SinkStreamDestination::SetTabStops (
const StandardTabStopList& tabStops)
671 if (fCurrentContext.fTabStops != tabStops) {
673 fSinkStream.SetStandardTabStopList (fCurrentContext.fTabStops = tabStops);
677void SinkStreamDestination::SetFirstIndent (TWIPS tx)
680 if (fCurrentContext.fFirstIndent != tx) {
682 fSinkStream.SetFirstIndent (fCurrentContext.fFirstIndent = tx);
686void SinkStreamDestination::SetLeftMargin (TWIPS lhs)
689 if (fCurrentContext.fLeftMargin != lhs) {
691 fSinkStream.SetLeftMargin (fCurrentContext.fLeftMargin = lhs);
695void SinkStreamDestination::SetRightMargin (TWIPS rhs)
700 TWIPS effectivePaperSize = fRTFInfo.GetEffectiveDrawingWidth ();
701 TWIPS realMargin = TWIPS (effectivePaperSize - rhs);
702 if (realMargin < 0) {
703 realMargin = TWIPS (1);
705 fSinkStream.SetRightMargin (fCurrentContext.fRightMargin = realMargin);
708void SinkStreamDestination::SetSpaceBefore (TWIPS tx)
711 if (fCurrentContext.fSpaceBefore != tx) {
713 fSinkStream.SetSpaceBefore (fCurrentContext.fSpaceBefore = tx);
717void SinkStreamDestination::SetSpaceAfter (TWIPS tx)
720 if (fCurrentContext.fSpaceAfter != tx) {
722 fSinkStream.SetSpaceAfter (fCurrentContext.fSpaceAfter = tx);
726void SinkStreamDestination::SetSpaceBetweenLines (CoordinateType sl)
729 if (fCurrentContext.fSpaceBetweenLines != sl) {
731 fSinkStream.SetLineSpacing (mkLineSpacing_From_RTFValues_ (fCurrentContext.fSpaceBetweenLines = sl, fCurrentContext.fSpaceBetweenLinesMult));
735void SinkStreamDestination::SetSpaceBetweenLinesMult (
bool multipleLineSpacing)
738 if (fCurrentContext.fSpaceBetweenLinesMult != multipleLineSpacing) {
740 fSinkStream.SetLineSpacing (mkLineSpacing_From_RTFValues_ (fCurrentContext.fSpaceBetweenLines,
741 fCurrentContext.fSpaceBetweenLinesMult = multipleLineSpacing));
745void SinkStreamDestination::SetTextHidden (
bool hidden)
748 if (fCurrentContext.fTextHidden != hidden) {
750 fSinkStream.SetTextHidden (fCurrentContext.fTextHidden = hidden);
754void SinkStreamDestination::SetInTable (
bool inTable)
757 if (fInTable != inTable) {
763void SinkStreamDestination::EndRow (
bool forceEmit)
765 if (forceEmit and not fTableInRow) {
775 fSinkStream.EndTableRow ();
778 Ensure (not fTableInRow);
779 Ensure (not fTableInCell);
783void SinkStreamDestination::EndCell (
bool forceEmit)
785 if (forceEmit and not fTableInCell) {
787 if (not fTableInRow) {
795 size_t thisCellNum = fTableNextCellNum - 1;
796 if (thisCellNum < fThisRow.fCellInfosForThisRow.size ()) {
797 fSinkStream.SetCellBackColor (fThisRow.fCellInfosForThisRow[thisCellNum].f_clcbpat);
799 fSinkStream.EndTableCell ();
800 fTableInCell =
false;
804void SinkStreamDestination::SetListStyle (ListStyle listStyle)
807 if (fCurrentContext.fListStyle != listStyle) {
809 fSinkStream.SetListStyle (fCurrentContext.fListStyle = listStyle);
813void SinkStreamDestination::SetListIndentLevel (
unsigned char indentLevel)
816 if (fCurrentContext.fListIndentLevel != indentLevel) {
818 fSinkStream.SetListIndentLevel (fCurrentContext.fListIndentLevel = indentLevel);
822void SinkStreamDestination::SetTableBorderColor (
Color c)
826 fSinkStream.SetTableBorderColor (c);
829void SinkStreamDestination::SetCellX (TWIPS cellx)
839 TWIPS sub = TWIPS{0};
840 for (
auto i = fThisRow.fCellInfosForThisRow.begin (); i != fThisRow.fCellInfosForThisRow.end (); ++i) {
843 fNextCellInfo.f_cellx = cellx - sub;
846 fThisRow.fCellInfosForThisRow.push_back (fNextCellInfo);
848 fNextCellInfo = CellInfo ();
851void SinkStreamDestination::SetCellBackColor (
const Color& c)
854 fNextCellInfo.f_clcbpat = c;
857void SinkStreamDestination::Call_trowd ()
859 fNextCellInfo = CellInfo ();
860 fThisRow = RowInfo ();
863void SinkStreamDestination::Set_trleft (TWIPS t)
865 fThisRow.f_trleft = t;
868void SinkStreamDestination::SetDefaultCellMarginsForRow_top (TWIPS t)
870 fThisRow.fDefaultCellMargins.top = t;
873void SinkStreamDestination::SetDefaultCellMarginsForRow_left (TWIPS t)
875 fThisRow.fDefaultCellMargins.left = t;
878void SinkStreamDestination::SetDefaultCellMarginsForRow_bottom (TWIPS t)
880 fThisRow.fDefaultCellMargins.bottom = t;
883void SinkStreamDestination::SetDefaultCellMarginsForRow_right (TWIPS t)
885 fThisRow.fDefaultCellMargins.right = t;
888void SinkStreamDestination::SetDefaultCellSpacingForRow_top (TWIPS t)
891 fThisRow.fDefaultCellSpacing.top = TWIPS (t * 2);
894void SinkStreamDestination::SetDefaultCellSpacingForRow_left (TWIPS t)
897 fThisRow.fDefaultCellSpacing.left = TWIPS (t * 2);
900void SinkStreamDestination::SetDefaultCellSpacingForRow_bottom (TWIPS t)
903 fThisRow.fDefaultCellSpacing.bottom = TWIPS (t * 2);
906void SinkStreamDestination::SetDefaultCellSpacingForRow_right (TWIPS t)
909 fThisRow.fDefaultCellSpacing.right = TWIPS (t * 2);
912void SinkStreamDestination::AssureTableOpen ()
914 if (not fTableInRow and fTableNextRowNum == 0) {
915 fSinkStream.StartTable ();
920void SinkStreamDestination::DoStartRow ()
922 fSinkStream.StartTableRow ();
924 vector<TWIPS> cellWidths;
925 for (
auto i = fThisRow.fCellInfosForThisRow.begin (); i != fThisRow.fCellInfosForThisRow.end (); ++i) {
926 const TWIPS kMinWidth = TWIPS{0};
927 TWIPS thisCellW = (*i).f_cellx;
928 if (i == fThisRow.fCellInfosForThisRow.begin ()) {
929 thisCellW -= fThisRow.f_trleft;
935 thisCellW -= TWIPS (3 * fThisRow.fDefaultCellSpacing.left / 2);
937 if (thisCellW < kMinWidth) {
938 thisCellW = kMinWidth;
940 cellWidths.push_back (thisCellW);
942 fSinkStream.SetCellWidths (cellWidths);
943 fSinkStream.SetDefaultCellMarginsForCurrentRow (fThisRow.fDefaultCellMargins.top, fThisRow.fDefaultCellMargins.left,
944 fThisRow.fDefaultCellMargins.bottom, fThisRow.fDefaultCellMargins.right);
945 fSinkStream.SetDefaultCellSpacingForCurrentRow (fThisRow.fDefaultCellSpacing.top, fThisRow.fDefaultCellSpacing.left,
946 fThisRow.fDefaultCellSpacing.bottom, fThisRow.fDefaultCellSpacing.right);
949 fTableNextCellNum = 0;
953void SinkStreamDestination::DoStartCell ()
955 fSinkStream.StartTableCell (fThisRow.fCellInfosForThisRow[fTableNextCellNum].fColSpan);
960void SinkStreamDestination::DoEndTable ()
966 fSinkStream.EndTable ();
968 fTableNextCellNum = 0;
969 fTableNextRowNum = 0;
971 Ensure (not fTableInRow);
972 Ensure (not fTableOpen);
975void SinkStreamDestination::Flush ()
978 if (fTCharsInSmallBuffer != 0) {
980 fsp.MergeIn (fCurrentContext.fFontSpec);
981 fSinkStream.AppendText (fSmallBuffer, fTCharsInSmallBuffer, &fsp);
982 fTCharsInSmallBuffer = 0;
986void SinkStreamDestination::Done ()
988 fParaEndedFlag =
false;
990 fSinkStream.EndOfBuffer ();
994SinkStreamDestination::Context SinkStreamDestination::GetContext ()
const
996 return fCurrentContext;
999void SinkStreamDestination::SetContext (
const Context& c)
1001 fParaEndBeforeNewContext = fParaEndedFlag;
1003 fNewContextPending =
true;
1006void SinkStreamDestination::ApplyContext (
const Context& c)
1011 UseFont (c.fFontSpec);
1012 SetTabStops (c.fTabStops);
1013 SetJustification (c.fJustification);
1014 SetSpaceBefore (c.fSpaceBefore);
1015 SetSpaceAfter (c.fSpaceAfter);
1016 SetSpaceBetweenLines (c.fSpaceBetweenLines);
1017 SetSpaceBetweenLinesMult (c.fSpaceBetweenLinesMult);
1018 SetListStyle (c.fListStyle);
1019 SetListIndentLevel (c.fListIndentLevel);
1020 SetFirstIndent (c.fFirstIndent);
1021 SetLeftMargin (c.fLeftMargin);
1022 SetRightMargin (c.fRightMargin);
1023 SetTextHidden (c.fTextHidden);
1026size_t SinkStreamDestination::current_offset ()
const
1029 return fSinkStream.current_offset () + fTCharsInSmallBuffer;
1032void SinkStreamDestination::InsertMarker (Marker* m,
size_t at,
size_t length,
MarkerOwner* markerOwner)
1034 Require (at <= current_offset ());
1038 if (at + length >= fSinkStream.current_offset ()) {
1041 fSinkStream.InsertMarker (m, at, length, markerOwner);
1044void SinkStreamDestination::AppendText_ (
const Led_tChar* text,
size_t nTChars)
1051 if (not fTableInRow and fTableNextRowNum == 0) {
1052 fSinkStream.StartTable ();
1056 if (not fTableInRow) {
1059 if (not fTableInCell) {
1068 if (fTCharsInSmallBuffer + nTChars < std::size (fSmallBuffer)) {
1069 (void)::memcpy (&fSmallBuffer[fTCharsInSmallBuffer], text, nTChars *
sizeof (Led_tChar));
1070 fTCharsInSmallBuffer += nTChars;
1074 Assert (fTCharsInSmallBuffer == 0);
1076 if (nTChars < std::size (fSmallBuffer)) {
1077 (void)::memcpy (&fSmallBuffer[0], text, nTChars *
sizeof (Led_tChar));
1078 fTCharsInSmallBuffer = nTChars;
1083 fsp.MergeIn (fCurrentContext.fFontSpec);
1084 fSinkStream.AppendText (text, nTChars, &fsp);
1089void SinkStreamDestination::AboutToChange ()
const
1094 FlushParaEndings ();
1095 FlushSetContextCalls ();
1098void SinkStreamDestination::FlushSetContextCalls ()
const
1103 if (fNewContextPending) {
1104 fNewContextPending =
false;
1105 const_cast<SinkStreamDestination*
> (
this)->ApplyContext (fNewContext);
1109void SinkStreamDestination::FlushParaEndings ()
const
1114 if (fParaEndedFlag) {
1115 fParaEndedFlag =
false;
1117 const_cast<SinkStreamDestination*
> (
this)->AppendText_ (&c, 1);
1126SinkStreamDestination::CellInfo::CellInfo ()
1128 , f_clcbpat{
Color::kWhite}
1138SinkStreamDestination::RowInfo::RowInfo ()
1140 , f_trleft{TWIPS{0}}
1141 , fDefaultCellMargins{TWIPS{0}, TWIPS{0}, TWIPS{0}, TWIPS{0}}
1142 , fDefaultCellSpacing{TWIPS{0}, TWIPS{0}, TWIPS{0}, TWIPS{0}}
1143 , fCellInfosForThisRow{}
1152StyledTextIOReader_RTF::ReaderContext::ReaderContext (StyledTextIOReader_RTF& reader)
1154 , fDocumentCharacterSet (Characters::WellKnownCodePages::kANSI)
1156 fCurrentInputCharSetEncoding_ (Characters::WellKnownCodePages::kANSI)
1157 , fMultiByteInputCharBuf ()
1159 memset (fMultiByteInputCharBuf, 0,
sizeof (fMultiByteInputCharBuf));
1160 fDefaultDestination = unique_ptr<Destination_> (
new SinkStreamDestination (reader));
1161 SetDestination (fDefaultDestination.get ());
1164StyledTextIOReader_RTF::ReaderContext::~ReaderContext ()
1166 Require (fCurrentGroup ==
nullptr);
1173void StyledTextIOReader_RTF::ReaderContext::UseInputCharSetEncoding (
CodePage codePage)
1175 fCurrentInputCharSetEncoding_ = codePage;
1178void StyledTextIOReader_RTF::ReaderContext::PutRawCharToDestination (
char c)
1182 if (fSkipNextNChars_UC > 0) {
1183 fSkipNextNChars_UC--;
1187 CodePage codePage = GetCurrentInputCharSetEncoding ();
1207 if ((GetCurrentGroupContext ()->fCCHSCodePage != 0) and fDocumentCharacterSet == codePage) {
1208 codePage = GetCurrentGroupContext ()->fCCHSCodePage;
1211 if (fMultiByteInputCharBuf[0] ==
'\0') {
1212 fMultiByteInputCharBuf[0] = c;
1213 fMultiByteInputCharBuf[1] =
'\0';
1220 fMultiByteInputCharBuf[1] = c;
1224 size_t nOutChars = 1;
1226 auto inBuf = span{
reinterpret_cast<const byte*
> (fMultiByteInputCharBuf), fMultiByteInputCharBuf[1] ==
'\0' ? 1u : 2u};
1228 Assert (nOutChars == 0 or nOutChars == 1);
1229 if (nOutChars == 1) {
1230 GetDestination ().AppendText (&outChar, 1);
1231 fMultiByteInputCharBuf[0] =
'\0';
1234 if (fMultiByteInputCharBuf[1] ==
'\0') {
1240 Led_tChar u = GetReader ().GetDefaultUnsupportedCharacterChar ();
1241 GetDestination ().AppendText (&u, 1);
1242 fMultiByteInputCharBuf[0] =
'\0';
1252StyledTextIOReader_RTF::ReaderContext::GroupContext::GroupContext (ReaderContext& readerContext)
1253 : fReaderContext (readerContext)
1254 , fParentGroup (readerContext.fCurrentGroup)
1255 , fCurrentGroupStartIdx (readerContext.GetReader ().GetSrcStream ().current_offset ())
1256 , fCurrentCodePage (WellKnownCodePages::kANSI)
1258 , fDestinationContext ()
1260 if (fParentGroup !=
nullptr) {
1261 fDestinationContext = fParentGroup->fDestinationContext;
1262 fCurrentCodePage = fParentGroup->fCurrentCodePage;
1263 fCCHSCodePage = fParentGroup->fCCHSCodePage;
1265 readerContext.fCurrentGroup =
this;
1268StyledTextIOReader_RTF::ReaderContext::GroupContext::~GroupContext ()
1270 Assert (fReaderContext.fCurrentGroup ==
this);
1272 fReaderContext.fCurrentGroup = fParentGroup;
1273 if (fReaderContext.fCurrentGroup !=
nullptr) {
1274 fReaderContext.UseInputCharSetEncoding (fReaderContext.fCurrentGroup->fCurrentCodePage);
1275 fReaderContext.GetDestination ().SetContext (fReaderContext.fCurrentGroup->fDestinationContext);
1279RTFIO::ControlWordAtomName::ControlWordAtomName (
const char* c)
1282 Characters::CString::Copy (fName, eMaxControlAtomNameLen, c);
1290const StyledTextIOReader_RTF::SpecialCharMappings StyledTextIOReader_RTF::kMappings[8] = {
1291 {RTFIO::eControlAtom_tab, 0x0009}, {RTFIO::eControlAtom_bullet, 0x2022}, {RTFIO::eControlAtom_endash, 0x2014},
1292 {RTFIO::eControlAtom_emdash, 0x2013}, {RTFIO::eControlAtom_lquote, 0x2018}, {RTFIO::eControlAtom_rquote, 0x2019},
1293 {RTFIO::eControlAtom_ldblquote, 0x201c}, {RTFIO::eControlAtom_rdblquote, 0x201d},
1296StyledTextIOReader_RTF::StyledTextIOReader_RTF (SrcStream* srcStream, SinkStream* sinkStream, RTFInfo* rtfInfo)
1297 : StyledTextIOReader (srcStream, sinkStream)
1299 , fDefaultUnsupportedCharacterChar (LED_TCHAR_OF (
'?'))
1300 , fRTFInfo (rtfInfo == nullptr ? new RTFInfo () : rtfInfo)
1301 , fOwnRTFInfo (rtfInfo == nullptr)
1302#if qStroika_Platform_Windows
1303 , fCachedFontSize (0)
1304 , fCachedFontSizeTMHeight (0)
1313 fPlainFont.SetPointSize (12);
1314#if qStroika_Platform_Windows
1315 fCachedFontSize = 12;
1316 fCachedFontSizeTMHeight = fPlainFont.PeekAtTMHeight ();
1320StyledTextIOReader_RTF::~StyledTextIOReader_RTF ()
1327void StyledTextIOReader_RTF::Read ()
1329 ReaderContext readerContext (*
this);
1331 ReadGroup (readerContext);
1333 catch (ReadEOFException& ) {
1339 readerContext.fDefaultDestination->Done ();
1342bool StyledTextIOReader_RTF::QuickLookAppearsToBeRightFormat ()
1344 SrcStreamSeekSaver savePos (GetSrcStream ());
1346 const char kStandardRTFOpenString[] =
"{\\rtf";
1347 char buf[
sizeof (kStandardRTFOpenString) - 1];
1348 size_t bytesRead = GetSrcStream ().read (buf,
sizeof (buf));
1349 return ((bytesRead ==
sizeof (kStandardRTFOpenString) - 1) and ::memcmp (kStandardRTFOpenString, buf,
sizeof (kStandardRTFOpenString) - 1) == 0);
1352void StyledTextIOReader_RTF::ReadGroup (ReaderContext& readerContext)
1354 ReaderContext::GroupContext thisGroupContext (readerContext);
1356 if (GetNextChar () != RTFIO::kRTFOpenGroupChar) {
1357 HandleBadlyFormattedInput (
true);
1361 char c = GetNextChar ();
1363 case RTFIO::kRTFOpenGroupChar: {
1366 ReadGroup (readerContext);
1369 case RTFIO::kRTFCloseGroupChar: {
1373 case RTFIO::kRTFStartTagChar: {
1375 char nextChar = PeekNextChar ();
1437 RTFIO::ControlWord cw = ReadControlWord ();
1438 if (HandleControlWord (readerContext, cw)) {
1445 const wchar_t kFormula = 0x0006;
1446 Led_tChar cc = kFormula;
1447 CheckIfAboutToStartBody (readerContext);
1448 readerContext.GetDestination ().AppendText (&cc, 1);
1453 Led_tChar cc = kNonBreakingSpace;
1454 CheckIfAboutToStartBody (readerContext);
1455 readerContext.GetDestination ().AppendText (&cc, 1);
1461 const wchar_t kOptionalHyphen = 0x00AD;
1463 Led_tChar cc = kOptionalHyphen;
1464 CheckIfAboutToStartBody (readerContext);
1465 readerContext.GetDestination ().AppendText (&cc, 1);
1470 const wchar_t kNonBreakingHyphen = 0x2011;
1471 Led_tChar cc = kNonBreakingHyphen;
1472 CheckIfAboutToStartBody (readerContext);
1473 readerContext.GetDestination ().AppendText (&cc, 1);
1481 ReadCommentGroup (readerContext);
1488 int number = ConvertReadSingleHexDigit_ (GetNextChar ());
1490 number += ConvertReadSingleHexDigit_ (GetNextChar ());
1491 c =
static_cast<char> (number);
1492 goto ReadNormalChar;
1500 goto ReadNormalChar;
1512 CheckIfAboutToStartBody (readerContext);
1514 readerContext.PutRawCharToDestination (c);
1520bool StyledTextIOReader_RTF::HandleControlWord (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
1522 switch (controlWord.fWord) {
1523 case RTFIO::eControlAtom_ansi:
1524 return (HandleControlWord_ansi (readerContext, controlWord));
1525 case RTFIO::eControlAtom_author:
1526 return (HandleControlWord_author (readerContext, controlWord));
1527 case RTFIO::eControlAtom_b:
1528 return (HandleControlWord_b (readerContext, controlWord));
1529 case RTFIO::eControlAtom_brdrs:
1530 case RTFIO::eControlAtom_brdrth:
1531 case RTFIO::eControlAtom_brdrsh:
1532 case RTFIO::eControlAtom_brdrdb:
1533 case RTFIO::eControlAtom_brdrdot:
1534 case RTFIO::eControlAtom_brdrdash:
1535 case RTFIO::eControlAtom_brdrhair:
1536 case RTFIO::eControlAtom_brdrdashsm:
1537 case RTFIO::eControlAtom_brdrdashd:
1538 case RTFIO::eControlAtom_brdrdashdd:
1539 case RTFIO::eControlAtom_brdrtriple:
1540 case RTFIO::eControlAtom_brdrtnthsg:
1541 case RTFIO::eControlAtom_brdrthtnsg:
1542 case RTFIO::eControlAtom_brdrtnthtnsg:
1543 case RTFIO::eControlAtom_brdrtnthmg:
1544 case RTFIO::eControlAtom_brdrthtnmg:
1545 case RTFIO::eControlAtom_brdrtnthtnmg:
1546 case RTFIO::eControlAtom_brdrtnthlg:
1547 case RTFIO::eControlAtom_brdrthtnlg:
1548 case RTFIO::eControlAtom_brdrtnthtnlg:
1549 case RTFIO::eControlAtom_brdrwavy:
1550 case RTFIO::eControlAtom_brdrwavydb:
1551 case RTFIO::eControlAtom_brdrdashdotstr:
1552 case RTFIO::eControlAtom_brdremboss:
1553 case RTFIO::eControlAtom_brdrengrave:
1554 case RTFIO::eControlAtom_brdrw:
1555 case RTFIO::eControlAtom_brdrcf:
1556 return (HandleControlWord_brdrXXX (readerContext, controlWord));
1557 case RTFIO::eControlAtom_cchs:
1558 return (HandleControlWord_cchs (readerContext, controlWord));
1559 case RTFIO::eControlAtom_cell:
1560 return (HandleControlWord_cell (readerContext, controlWord));
1561 case RTFIO::eControlAtom_cellx:
1562 return (HandleControlWord_cellx (readerContext, controlWord));
1563 case RTFIO::eControlAtom_cf:
1564 return (HandleControlWord_cf (readerContext, controlWord));
1565 case RTFIO::eControlAtom_clcbpat:
1566 return (HandleControlWord_clcbpat (readerContext, controlWord));
1567 case RTFIO::eControlAtom_cpg:
1568 return (HandleControlWord_cpg (readerContext, controlWord));
1569 case RTFIO::eControlAtom_colortbl:
1570 return (HandleControlWord_colortbl (readerContext, controlWord));
1571 case RTFIO::eControlAtom_deff:
1572 return (HandleControlWord_deff (readerContext, controlWord));
1573 case RTFIO::eControlAtom_deftab:
1574 return (HandleControlWord_deftab (readerContext, controlWord));
1575 case RTFIO::eControlAtom_deleted:
1576 return (HandleControlWord_deleted (readerContext, controlWord));
1577 case RTFIO::eControlAtom_dn:
1578 return (HandleControlWord_dn (readerContext, controlWord));
1579 case RTFIO::eControlAtom_f:
1580 return (HandleControlWord_f (readerContext, controlWord));
1581 case RTFIO::eControlAtom_fi:
1582 return (HandleControlWord_fi (readerContext, controlWord));
1583 case RTFIO::eControlAtom_footer:
1584 return (HandleControlWord_footer (readerContext, controlWord));
1585 case RTFIO::eControlAtom_fonttbl:
1586 return (HandleControlWord_fonttbl (readerContext, controlWord));
1587 case RTFIO::eControlAtom_fs:
1588 return (HandleControlWord_fs (readerContext, controlWord));
1589 case RTFIO::eControlAtom_header:
1590 return (HandleControlWord_header (readerContext, controlWord));
1591 case RTFIO::eControlAtom_i:
1592 return (HandleControlWord_i (readerContext, controlWord));
1593 case RTFIO::eControlAtom_ilvl:
1594 return (HandleControlWord_ilvl (readerContext, controlWord));
1595 case RTFIO::eControlAtom_info:
1596 return (HandleControlWord_info (readerContext, controlWord));
1597 case RTFIO::eControlAtom_intbl:
1598 return (HandleControlWord_intbl (readerContext, controlWord));
1599 case RTFIO::eControlAtom_li:
1600 return (HandleControlWord_li (readerContext, controlWord));
1601 case RTFIO::eControlAtom_line:
1602 return (HandleControlWord_line (readerContext, controlWord));
1603 case RTFIO::eControlAtom_listtext:
1604 return (HandleControlWord_listtext (readerContext, controlWord));
1605 case RTFIO::eControlAtom_ls:
1606 return (HandleControlWord_ls (readerContext, controlWord));
1607 case RTFIO::eControlAtom_mac:
1608 return (HandleControlWord_mac (readerContext, controlWord));
1609 case RTFIO::eControlAtom_margb:
1610 case RTFIO::eControlAtom_margl:
1611 case RTFIO::eControlAtom_margr:
1612 case RTFIO::eControlAtom_margt:
1613 return (HandleControlWord_margX (readerContext, controlWord));
1614 case RTFIO::eControlAtom_object:
1615 return (HandleControlWord_object (readerContext, controlWord));
1616 case RTFIO::eControlAtom_outl:
1617 return (HandleControlWord_outl (readerContext, controlWord));
1618 case RTFIO::eControlAtom_paperh:
1619 return (HandleControlWord_paperX (readerContext, controlWord));
1620 case RTFIO::eControlAtom_paperw:
1621 return (HandleControlWord_paperX (readerContext, controlWord));
1622 case RTFIO::eControlAtom_par:
1623 return (HandleControlWord_par (readerContext, controlWord));
1624 case RTFIO::eControlAtom_pard:
1625 return (HandleControlWord_pard (readerContext, controlWord));
1626 case RTFIO::eControlAtom_pc:
1627 return (HandleControlWord_pc (readerContext, controlWord));
1628 case RTFIO::eControlAtom_pca:
1629 return (HandleControlWord_pca (readerContext, controlWord));
1630 case RTFIO::eControlAtom_pict:
1631 return (HandleControlWord_pict (readerContext, controlWord));
1632 case RTFIO::eControlAtom_plain:
1633 return (HandleControlWord_plain (readerContext, controlWord));
1634 case RTFIO::eControlAtom_pntext:
1635 return (HandleControlWord_pntext (readerContext, controlWord));
1636 case RTFIO::eControlAtom_qc:
1637 return (HandleControlWord_qc (readerContext, controlWord));
1638 case RTFIO::eControlAtom_qj:
1639 return (HandleControlWord_qj (readerContext, controlWord));
1640 case RTFIO::eControlAtom_ql:
1641 return (HandleControlWord_ql (readerContext, controlWord));
1642 case RTFIO::eControlAtom_qr:
1643 return (HandleControlWord_qr (readerContext, controlWord));
1644 case RTFIO::eControlAtom_ri:
1645 return (HandleControlWord_ri (readerContext, controlWord));
1646 case RTFIO::eControlAtom_row:
1647 return (HandleControlWord_row (readerContext, controlWord));
1648 case RTFIO::eControlAtom_rtf:
1649 return (HandleControlWord_rtf (readerContext, controlWord));
1650 case RTFIO::eControlAtom_sa:
1651 return (HandleControlWord_sa (readerContext, controlWord));
1652 case RTFIO::eControlAtom_sb:
1653 return (HandleControlWord_sb (readerContext, controlWord));
1654 case RTFIO::eControlAtom_shad:
1655 return (HandleControlWord_shad (readerContext, controlWord));
1656 case RTFIO::eControlAtom_sl:
1657 return (HandleControlWord_sl (readerContext, controlWord));
1658 case RTFIO::eControlAtom_slmult:
1659 return (HandleControlWord_slmult (readerContext, controlWord));
1660 case RTFIO::eControlAtom_sub:
1661 return (HandleControlWord_sub (readerContext, controlWord));
1662 case RTFIO::eControlAtom_super:
1663 return (HandleControlWord_super (readerContext, controlWord));
1664 case RTFIO::eControlAtom_strike:
1665 return (HandleControlWord_strike (readerContext, controlWord));
1666 case RTFIO::eControlAtom_stylesheet:
1667 return (HandleControlWord_stylesheet (readerContext, controlWord));
1668 case RTFIO::eControlAtom_trgaph:
1669 return (HandleControlWord_trgaph (readerContext, controlWord));
1670 case RTFIO::eControlAtom_trleft:
1671 return (HandleControlWord_trleft (readerContext, controlWord));
1672 case RTFIO::eControlAtom_trowd:
1673 return (HandleControlWord_trowd (readerContext, controlWord));
1674 case RTFIO::eControlAtom_trpaddb:
1675 case RTFIO::eControlAtom_trpaddl:
1676 case RTFIO::eControlAtom_trpaddr:
1677 case RTFIO::eControlAtom_trpaddt:
1678 return (HandleControlWord_trpaddX (readerContext, controlWord));
1679 case RTFIO::eControlAtom_trspdb:
1680 case RTFIO::eControlAtom_trspdl:
1681 case RTFIO::eControlAtom_trspdr:
1682 case RTFIO::eControlAtom_trspdt:
1683 return (HandleControlWord_trspdX (readerContext, controlWord));
1684 case RTFIO::eControlAtom_tx:
1685 return (HandleControlWord_tx (readerContext, controlWord));
1686 case RTFIO::eControlAtom_u:
1687 return (HandleControlWord_u (readerContext, controlWord));
1688 case RTFIO::eControlAtom_uc:
1689 return (HandleControlWord_uc (readerContext, controlWord));
1690 case RTFIO::eControlAtom_ul:
1691 return (HandleControlWord_ul (readerContext, controlWord));
1692 case RTFIO::eControlAtom_ulnone:
1693 return (HandleControlWord_ulnone (readerContext, controlWord));
1694 case RTFIO::eControlAtom_up:
1695 return (HandleControlWord_up (readerContext, controlWord));
1696 case RTFIO::eControlAtom_v:
1697 return (HandleControlWord_v (readerContext, controlWord));
1700 return (HandleControlWord_UnknownControlWord (readerContext, controlWord));
1704bool StyledTextIOReader_RTF::HandleControlWord_ansi (ReaderContext& readerContext,
const RTFIO::ControlWord& )
1706 readerContext.fDocumentCharacterSet = WellKnownCodePages::kANSI;
1707 readerContext.UseInputCharSetEncoding (readerContext.fDocumentCharacterSet);
1711bool StyledTextIOReader_RTF::HandleControlWord_author (ReaderContext& ,
const RTFIO::ControlWord& )
1713 SkipToEndOfCurrentGroup ();
1717bool StyledTextIOReader_RTF::HandleControlWord_b (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
1719 ApplyFontSpec (readerContext, controlWord);
1723bool StyledTextIOReader_RTF::HandleControlWord_brdrXXX (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
1725 switch (controlWord.fWord) {
1726 case RTFIO::eControlAtom_brdrcf: {
1727 if (not controlWord.fHasArg) {
1728 HandleBadlyFormattedInput (
true);
1730 readerContext.GetDestination ().SetTableBorderColor (LookupColor (readerContext,
static_cast<size_t> (controlWord.fValue)));
1742bool StyledTextIOReader_RTF::HandleControlWord_cchs (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
1744 CheckIfAboutToStartBody (readerContext);
1745 if (readerContext.GetCurrentGroupContext () ==
nullptr) {
1746 HandleBadlyFormattedInput (
true);
1748 if (not controlWord.fHasArg) {
1749 HandleBadlyFormattedInput (
true);
1752 switch (controlWord.fValue) {
1754 readerContext.GetCurrentGroupContext ()->fCCHSCodePage = WellKnownCodePages::kANSI;
1757 readerContext.GetCurrentGroupContext ()->fCCHSCodePage = WellKnownCodePages::kPC;
1760 readerContext.GetCurrentGroupContext ()->fCCHSCodePage = WellKnownCodePages::kPCA;
1763 readerContext.GetCurrentGroupContext ()->fCCHSCodePage = WellKnownCodePages::kMAC;
1774bool StyledTextIOReader_RTF::HandleControlWord_cell (ReaderContext& readerContext,
const RTFIO::ControlWord& )
1776 CheckIfAboutToStartBody (readerContext);
1777 readerContext.GetDestination ().EndCell (
true);
1781bool StyledTextIOReader_RTF::HandleControlWord_cellx (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
1783 CheckIfAboutToStartBody (readerContext);
1784 if (not controlWord.fHasArg) {
1785 HandleBadlyFormattedInput (
true);
1787 readerContext.GetDestination ().SetCellX (TWIPS (controlWord.fValue));
1791bool StyledTextIOReader_RTF::HandleControlWord_cf (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
1793 ApplyFontSpec (readerContext, controlWord);
1797bool StyledTextIOReader_RTF::HandleControlWord_clcbpat (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
1799 CheckIfAboutToStartBody (readerContext);
1800 readerContext.GetDestination ().SetCellBackColor (LookupColor (readerContext,
static_cast<size_t> (controlWord.fValue)));
1804bool StyledTextIOReader_RTF::HandleControlWord_cpg (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
1806 CheckIfAboutToStartBody (readerContext);
1807 if (readerContext.GetCurrentGroupContext () ==
nullptr) {
1808 HandleBadlyFormattedInput (
true);
1810 if (not controlWord.fHasArg) {
1811 HandleBadlyFormattedInput (
true);
1813 readerContext.GetCurrentGroupContext ()->fCurrentCodePage = controlWord.fValue;
1814 readerContext.UseInputCharSetEncoding (readerContext.GetCurrentGroupContext ()->fCurrentCodePage);
1818bool StyledTextIOReader_RTF::HandleControlWord_colortbl (ReaderContext& readerContext,
const RTFIO::ControlWord& )
1820 if (readerContext.fColorTable !=
nullptr) {
1821 HandleBadlyFormattedInput ();
1830 if (readerContext.GetCurrentGroupContext () ==
nullptr) {
1831 HandleBadlyFormattedInput (
true);
1833 GetSrcStream ().seek_to (readerContext.GetCurrentGroupContext ()->fCurrentGroupStartIdx);
1834 if (GetNextChar () != RTFIO::kRTFOpenGroupChar) {
1835 HandleBadlyFormattedInput (
true);
1839 RTFIO::ControlWord cword = ReadControlWord ();
1840 if (cword.fWord != RTFIO::eControlAtom_colortbl or cword.fHasArg) {
1841 HandleBadlyFormattedInput (
true);
1845 vector<Color> colorTable;
1847 Color curColor = Color::kBlack;
1851 switch (PeekNextChar ()) {
1852 case RTFIO::kRTFCloseGroupChar: {
1854 goto ColorsComplete;
1860 case RTFIO::kRTFStartTagChar: {
1861 RTFIO::ControlWord cword = ReadControlWord ();
1862 if (cword.fWord == RTFIO::eControlAtom_red) {
1863 if (not cword.fHasArg) {
1864 HandleBadlyFormattedInput ();
1867 curColor =
Color (
static_cast<Color::ColorValue
> (
unsigned (cword.fValue) << 8), 0, 0);
1871 HandleBadlyFormattedInput ();
1881 HandleBadlyFormattedInput ();
1887 switch (PeekNextChar ()) {
1892 case RTFIO::kRTFStartTagChar: {
1893 RTFIO::ControlWord cword = ReadControlWord ();
1894 if (cword.fWord == RTFIO::eControlAtom_green) {
1895 if (not cword.fHasArg) {
1896 HandleBadlyFormattedInput ();
1899 curColor =
Color (curColor.GetRed (),
static_cast<Color::ColorValue
> (unsigned (cword.fValue) << 8), 0);
1903 HandleBadlyFormattedInput ();
1913 HandleBadlyFormattedInput ();
1919 switch (PeekNextChar ()) {
1924 case RTFIO::kRTFStartTagChar: {
1925 RTFIO::ControlWord cword = ReadControlWord ();
1926 if (cword.fWord == RTFIO::eControlAtom_blue) {
1927 if (not cword.fHasArg) {
1928 HandleBadlyFormattedInput ();
1931 curColor =
Color (curColor.GetRed (), curColor.GetGreen (),
static_cast<Color::ColorValue
> (unsigned (cword.fValue) << 8));
1935 HandleBadlyFormattedInput ();
1945 HandleBadlyFormattedInput ();
1951 switch (PeekNextChar ()) {
1961 HandleBadlyFormattedInput ();
1967 colorTable.push_back (curColor);
1971 Assert (readerContext.fColorTable ==
nullptr);
1972 readerContext.fColorTable =
new RTFIO::ColorTable (colorTable);
1977bool StyledTextIOReader_RTF::HandleControlWord_deff (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
1979 if (not controlWord.fHasArg) {
1980 HandleBadlyFormattedInput ();
1983 readerContext.fDefaultFontNumber = controlWord.fValue;
1988bool StyledTextIOReader_RTF::HandleControlWord_deftab (ReaderContext& ,
const RTFIO::ControlWord& controlWord)
1990 if (not controlWord.fHasArg) {
1991 HandleBadlyFormattedInput ();
1994 if (controlWord.fValue < 0) {
1995 HandleBadlyFormattedInput ();
1998 TWIPS tsl = TWIPS (controlWord.fValue);
2000 HandleBadlyFormattedInput ();
2003 if (fRTFInfo !=
nullptr) {
2004 fRTFInfo->fDefaultTabStop = tsl;
2009bool StyledTextIOReader_RTF::HandleControlWord_deleted (ReaderContext& ,
const RTFIO::ControlWord& )
2015 SkipToEndOfCurrentGroup ();
2019bool StyledTextIOReader_RTF::HandleControlWord_dn (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2024 if (controlWord.fHasArg and controlWord.fValue > 0) {
2025 RTFIO::ControlWord newCW;
2026 newCW.fHasArg =
false;
2027 newCW.fWord = RTFIO::eControlAtom_sub;
2028 return HandleControlWord_sub (readerContext, newCW);
2033bool StyledTextIOReader_RTF::HandleControlWord_f (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2035 ApplyFontSpec (readerContext, controlWord);
2039bool StyledTextIOReader_RTF::HandleControlWord_fi (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2041 if (not controlWord.fHasArg) {
2042 HandleBadlyFormattedInput ();
2045 readerContext.GetDestination ().SetFirstIndent (readerContext.GetCurrentGroupContext ()->fDestinationContext.fFirstIndent =
2046 TWIPS (controlWord.fValue));
2051bool StyledTextIOReader_RTF::HandleControlWord_footer (ReaderContext& ,
const RTFIO::ControlWord& )
2057 SkipToEndOfCurrentGroup ();
2061bool StyledTextIOReader_RTF::HandleControlWord_fonttbl (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2063 if (readerContext.fFontTable !=
nullptr) {
2064 HandleBadlyFormattedInput ();
2073 if (readerContext.GetCurrentGroupContext () ==
nullptr) {
2074 HandleBadlyFormattedInput (
true);
2076 GetSrcStream ().seek_to (readerContext.GetCurrentGroupContext ()->fCurrentGroupStartIdx);
2077 if (GetNextChar () != RTFIO::kRTFOpenGroupChar) {
2078 HandleBadlyFormattedInput (
true);
2081 vector<FontTableEntry> fontTable;
2084 ScanForwardFor (
"{}");
2085 switch (PeekNextChar ()) {
2086 case RTFIO::kRTFOpenGroupChar: {
2087 fontTable.push_back (ReadInFontTablesEntry ());
2089 case RTFIO::kRTFCloseGroupChar: {
2091 if (readerContext.fFontTable ==
nullptr) {
2093 readerContext.fFontTable =
new FontTable (fontTable);
2105bool StyledTextIOReader_RTF::HandleControlWord_fs (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2107 ApplyFontSpec (readerContext, controlWord);
2111bool StyledTextIOReader_RTF::HandleControlWord_header (ReaderContext& ,
const RTFIO::ControlWord& )
2117 SkipToEndOfCurrentGroup ();
2121bool StyledTextIOReader_RTF::HandleControlWord_i (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2123 ApplyFontSpec (readerContext, controlWord);
2127bool StyledTextIOReader_RTF::HandleControlWord_ilvl (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2129 if (not controlWord.fHasArg) {
2130 HandleBadlyFormattedInput ();
2133 unsigned char listLevel =
static_cast<unsigned char> (controlWord.fValue);
2134 if (listLevel > 8) {
2137 readerContext.GetDestination ().SetListIndentLevel (readerContext.GetCurrentGroupContext ()->fDestinationContext.fListIndentLevel = listLevel);
2142bool StyledTextIOReader_RTF::HandleControlWord_info (ReaderContext& ,
const RTFIO::ControlWord& )
2144 SkipToEndOfCurrentGroup ();
2148bool StyledTextIOReader_RTF::HandleControlWord_intbl (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2150 CheckIfAboutToStartBody (readerContext);
2151 if (readerContext.GetCurrentGroupContext () ==
nullptr) {
2152 HandleBadlyFormattedInput (
true);
2154 readerContext.GetDestination ().SetInTable (
true);
2158bool StyledTextIOReader_RTF::HandleControlWord_li (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2160 if (not controlWord.fHasArg) {
2161 HandleBadlyFormattedInput ();
2164 readerContext.GetDestination ().SetLeftMargin (readerContext.GetCurrentGroupContext ()->fDestinationContext.fLeftMargin =
2165 TWIPS (controlWord.fValue));
2170bool StyledTextIOReader_RTF::HandleControlWord_line (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2172 readerContext.GetDestination ().AppendSoftLineBreak ();
2176bool StyledTextIOReader_RTF::HandleControlWord_listtext (ReaderContext& ,
const RTFIO::ControlWord& )
2178 SkipToEndOfCurrentGroup ();
2182bool StyledTextIOReader_RTF::HandleControlWord_ls (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2184 if (not controlWord.fHasArg) {
2185 HandleBadlyFormattedInput ();
2191 ListStyle listStyle = eListStyle_Bullet;
2192 readerContext.GetDestination ().SetListStyle (readerContext.GetCurrentGroupContext ()->fDestinationContext.fListStyle = listStyle);
2197bool StyledTextIOReader_RTF::HandleControlWord_mac (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2199 readerContext.fDocumentCharacterSet = WellKnownCodePages::kMAC;
2200 readerContext.UseInputCharSetEncoding (readerContext.fDocumentCharacterSet);
2204bool StyledTextIOReader_RTF::HandleControlWord_margX (ReaderContext& ,
const RTFIO::ControlWord& controlWord)
2206 if (not controlWord.fHasArg) {
2207 HandleBadlyFormattedInput ();
2211 switch (controlWord.fWord) {
2212 case RTFIO::eControlAtom_margt: {
2213 fRTFInfo->fDefaultMarginTop = TWIPS (controlWord.fValue);
2215 case RTFIO::eControlAtom_margb: {
2216 fRTFInfo->fDefaultMarginBottom = TWIPS (controlWord.fValue);
2218 case RTFIO::eControlAtom_margl: {
2219 fRTFInfo->fDefaultMarginLeft = TWIPS (controlWord.fValue);
2221 case RTFIO::eControlAtom_margr: {
2222 fRTFInfo->fDefaultMarginRight = TWIPS (controlWord.fValue);
2231bool StyledTextIOReader_RTF::HandleControlWord_outl (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2233 ApplyFontSpec (readerContext, controlWord);
2237bool StyledTextIOReader_RTF::HandleControlWord_paperX (ReaderContext& ,
const RTFIO::ControlWord& controlWord)
2239 if (not controlWord.fHasArg) {
2240 HandleBadlyFormattedInput ();
2244 switch (controlWord.fWord) {
2245 case RTFIO::eControlAtom_paperh: {
2246 fRTFInfo->fDefaultPaperSize.v = TWIPS (controlWord.fValue);
2248 case RTFIO::eControlAtom_paperw: {
2249 fRTFInfo->fDefaultPaperSize.h = TWIPS (controlWord.fValue);
2258bool StyledTextIOReader_RTF::HandleControlWord_object (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2260 CheckIfAboutToStartBody (readerContext);
2261#if qStroika_Frameworks_Led_SupportGDI
2262 using UnknownRTFEmbedding = RTFIO::UnknownRTFEmbedding;
2264 using ControlWord = RTFIO::ControlWord;
2278 bool isOLEEmbedding =
false;
2279 bool isPrivateLedEmbedding =
false;
2280 TWIPS_Point shownSize = TWIPS_Point (TWIPS{0}, TWIPS{0});
2281 vector<char> objData;
2282 float scaleX = 1.0f;
2283 float scaleY = 1.0f;
2284 size_t resultFoundAt = size_t (-1);
2288 if (PeekNextChar () != RTFIO::kRTFStartTagChar) {
2289 ScanForwardFor (
"{}");
2291 switch (PeekNextChar ()) {
2292 case RTFIO::kRTFStartTagChar: {
2293 ControlWord cw = ReadControlWord ();
2295 case RTFIO::eControlAtom_ledprivateobjectembeddingformat:
2296 isPrivateLedEmbedding =
true;
2298 case RTFIO::eControlAtom_objemb:
2299 isOLEEmbedding =
true;
2301 case RTFIO::eControlAtom_objh:
2302 if (not cw.fHasArg) {
2303 HandleBadlyFormattedInput ();
2306 shownSize.v = TWIPS (cw.fValue);
2308 case RTFIO::eControlAtom_objw:
2309 if (not cw.fHasArg) {
2310 HandleBadlyFormattedInput ();
2313 shownSize.h = TWIPS (cw.fValue);
2315 case RTFIO::eControlAtom_objscalex:
2316 if (not cw.fHasArg) {
2317 HandleBadlyFormattedInput ();
2320 scaleX = cw.fValue / 100.0f;
2322 case RTFIO::eControlAtom_objscaley:
2323 if (not cw.fHasArg) {
2324 HandleBadlyFormattedInput ();
2327 scaleY = cw.fValue / 100.0f;
2329 case RTFIO::eControlAtom_result:
2330 resultFoundAt = readerContext.GetReader ().GetSrcStream ().current_offset ();
2334 case RTFIO::kRTFOpenGroupChar: {
2335 ReadInObjectSubGroupEntry (readerContext, &objData, &resultFoundAt);
2337 case RTFIO::kRTFCloseGroupChar: {
2341 shownSize.h *= scaleX;
2342 shownSize.v *= scaleY;
2343#if qStroika_Frameworks_Led_SupportGDI
2344 if (shownSize.v > 20000 or shownSize.h > 20000 or shownSize.h < 100 or shownSize.v < 100) {
2345 shownSize = UnknownRTFEmbedding::CalcStaticDefaultShownSize ();
2351 if (isOLEEmbedding and isPrivateLedEmbedding) {
2352 HandleBadlyFormattedInput ();
2354 if (isOLEEmbedding) {
2356 ConstructOLEEmebddingFromRTFInfo (readerContext, shownSize, objData.size (), &objData.front ());
2359 isOLEEmbedding =
false;
2362 if (isPrivateLedEmbedding) {
2364 ConstructLedEmebddingFromRTFInfo (readerContext, objData.size (), &objData.front ());
2367 isPrivateLedEmbedding =
false;
2374 if (isOLEEmbedding or isPrivateLedEmbedding) {
2379 GetSrcStream ().seek_to (readerContext.GetCurrentGroupContext ()->fCurrentGroupStartIdx);
2380 string s = ReadInGroupAndSave ();
2382#if qStroika_Frameworks_Led_SupportGDI
2383 SimpleEmbeddedObjectStyleMarker* embedding =
nullptr;
2389 if (resultFoundAt !=
size_t (-1)) {
2390 size_t RETURN_TO = readerContext.GetReader ().GetSrcStream ().current_offset ();
2391 GetSrcStream ().seek_to (resultFoundAt);
2392 if (SearchForwardFor (
"\\pict", s.length ())) {
2393 ControlWord cw = ReadControlWord ();
2394 if (cw.fWord == RTFIO::eControlAtom_pict) {
2395 TWIPS_Point bmSize = TWIPS_Point (TWIPS{0}, TWIPS{0});
2396 vector<char> pictureData;
2397 ImageFormat imageFormat = eDefaultImageFormat;
2398 ReadTopLevelPictData (&shownSize, &imageFormat, &bmSize, &pictureData);
2406 unique_ptr<Led_DIB> dib = unique_ptr<Led_DIB> (
2407 ConstructDIBFromData (shownSize, imageFormat, bmSize, objData.size (), &pictureData.front ()));
2408 if (dib.get () !=
nullptr) {
2409 RTFIO::UnknownRTFEmbedding* e =
new RTFIO::UnknownRTFEmbedding (RTFIO::kRTFBodyGroupFragmentClipFormat,
2410 RTFIO::kRTFBodyGroupFragmentEmbeddingTag,
2411 s.c_str (), s.length (), dib.get ());
2412 e->SetShownSize (shownSize);
2417 GetSrcStream ().seek_to (RETURN_TO);
2420 if (embedding ==
nullptr) {
2421 RTFIO::UnknownRTFEmbedding* e =
new RTFIO::UnknownRTFEmbedding (
2422 RTFIO::kRTFBodyGroupFragmentClipFormat, RTFIO::kRTFBodyGroupFragmentEmbeddingTag, s.c_str (), s.length ());
2423 e->SetShownSize (shownSize);
2427 readerContext.GetDestination ().AppendEmbedding (embedding);
2445bool StyledTextIOReader_RTF::HandleControlWord_par (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2452 CheckIfAboutToStartBody (readerContext);
2453 readerContext.GetDestination ().EndParagraph ();
2457bool StyledTextIOReader_RTF::HandleControlWord_pard (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2461 readerContext.GetDestination ().SetTabStops (readerContext.GetCurrentGroupContext ()->fDestinationContext.fTabStops =
2462 StandardTabStopList (GetRTFInfo ().GetDefaultTabStop ()));
2463 readerContext.GetDestination ().SetJustification (readerContext.GetCurrentGroupContext ()->fDestinationContext.fJustification = eLeftJustify);
2464 readerContext.GetDestination ().SetFirstIndent (readerContext.GetCurrentGroupContext ()->fDestinationContext.fFirstIndent = TWIPS{0});
2465 readerContext.GetDestination ().SetLeftMargin (readerContext.GetCurrentGroupContext ()->fDestinationContext.fLeftMargin = TWIPS{0});
2466 readerContext.GetDestination ().SetRightMargin (readerContext.GetCurrentGroupContext ()->fDestinationContext.fRightMargin = TWIPS{0});
2467 readerContext.GetDestination ().SetSpaceBefore (readerContext.GetCurrentGroupContext ()->fDestinationContext.fSpaceBefore = TWIPS{0});
2468 readerContext.GetDestination ().SetSpaceAfter (readerContext.GetCurrentGroupContext ()->fDestinationContext.fSpaceAfter = TWIPS{0});
2469 readerContext.GetDestination ().SetSpaceBetweenLines (readerContext.GetCurrentGroupContext ()->fDestinationContext.fSpaceBetweenLines = 1000);
2470 readerContext.GetDestination ().SetSpaceBetweenLinesMult (readerContext.GetCurrentGroupContext ()->fDestinationContext.fSpaceBetweenLinesMult =
true);
2471 readerContext.GetDestination ().SetListStyle (readerContext.GetCurrentGroupContext ()->fDestinationContext.fListStyle = eListStyle_None);
2472 readerContext.GetDestination ().SetListIndentLevel (readerContext.GetCurrentGroupContext ()->fDestinationContext.fListIndentLevel = 0);
2476 readerContext.GetDestination ().SetInTable (
false);
2480bool StyledTextIOReader_RTF::HandleControlWord_pc (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2482 readerContext.fDocumentCharacterSet = WellKnownCodePages::kPC;
2483 readerContext.UseInputCharSetEncoding (readerContext.fDocumentCharacterSet);
2487bool StyledTextIOReader_RTF::HandleControlWord_pca (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2489 readerContext.fDocumentCharacterSet = WellKnownCodePages::kPCA;
2490 readerContext.UseInputCharSetEncoding (readerContext.fDocumentCharacterSet);
2494bool StyledTextIOReader_RTF::HandleControlWord_pict (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2496 CheckIfAboutToStartBody (readerContext);
2498 TWIPS_Point shownSize = TWIPS_Point (TWIPS{0}, TWIPS{0});
2499 TWIPS_Point bmSize = TWIPS_Point (TWIPS{0}, TWIPS{0});
2500 vector<char> objData;
2501 ImageFormat imageFormat = eDefaultImageFormat;
2502 ReadTopLevelPictData (&shownSize, &imageFormat, &bmSize, &objData);
2511 unique_ptr<Led_DIB> dib = unique_ptr<Led_DIB> (ConstructDIBFromData (shownSize, imageFormat, bmSize, objData.size (), &objData.front ()));
2512#if qStroika_Frameworks_Led_SupportGDI
2513 bool createSucceeded = dib.get () !=
nullptr;
2514 SimpleEmbeddedObjectStyleMarker* embedding =
nullptr;
2515 if (createSucceeded) {
2516 embedding =
new StandardDIBStyleMarker (dib.get ());
2520 GetSrcStream ().seek_to (readerContext.GetCurrentGroupContext ()->fCurrentGroupStartIdx);
2521 string s = ReadInGroupAndSave ();
2522 embedding =
new RTFIO::UnknownRTFEmbedding (RTFIO::kRTFBodyGroupFragmentClipFormat, RTFIO::kRTFBodyGroupFragmentEmbeddingTag,
2523 s.c_str (), s.length ());
2526 if (embedding !=
nullptr) {
2528 readerContext.GetDestination ().AppendEmbedding (embedding);
2539bool StyledTextIOReader_RTF::HandleControlWord_plain (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2541 ApplyFontSpec (readerContext, controlWord);
2545bool StyledTextIOReader_RTF::HandleControlWord_pntext (ReaderContext& ,
const RTFIO::ControlWord& )
2547 SkipToEndOfCurrentGroup ();
2551bool StyledTextIOReader_RTF::HandleControlWord_qc (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2553 readerContext.GetDestination ().SetJustification (readerContext.GetCurrentGroupContext ()->fDestinationContext.fJustification = eCenterJustify);
2557bool StyledTextIOReader_RTF::HandleControlWord_qj (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2559 readerContext.GetDestination ().SetJustification (readerContext.GetCurrentGroupContext ()->fDestinationContext.fJustification = eFullyJustify);
2563bool StyledTextIOReader_RTF::HandleControlWord_ql (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2565 readerContext.GetDestination ().SetJustification (readerContext.GetCurrentGroupContext ()->fDestinationContext.fJustification = eLeftJustify);
2569bool StyledTextIOReader_RTF::HandleControlWord_qr (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2571 readerContext.GetDestination ().SetJustification (readerContext.GetCurrentGroupContext ()->fDestinationContext.fJustification = eRightJustify);
2575bool StyledTextIOReader_RTF::HandleControlWord_ri (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2577 if (not controlWord.fHasArg) {
2578 HandleBadlyFormattedInput ();
2581 readerContext.GetDestination ().SetRightMargin (readerContext.GetCurrentGroupContext ()->fDestinationContext.fRightMargin =
2582 TWIPS (controlWord.fValue));
2587bool StyledTextIOReader_RTF::HandleControlWord_row (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2589 CheckIfAboutToStartBody (readerContext);
2590 readerContext.GetDestination ().EndRow (
true);
2594bool StyledTextIOReader_RTF::HandleControlWord_rtf (ReaderContext& ,
const RTFIO::ControlWord& )
2600bool StyledTextIOReader_RTF::HandleControlWord_sa (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2602 if (not controlWord.fHasArg) {
2603 HandleBadlyFormattedInput ();
2606 readerContext.GetDestination ().SetSpaceAfter (readerContext.GetCurrentGroupContext ()->fDestinationContext.fSpaceAfter =
2607 TWIPS (controlWord.fValue));
2612bool StyledTextIOReader_RTF::HandleControlWord_sb (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2614 if (not controlWord.fHasArg) {
2615 HandleBadlyFormattedInput ();
2618 readerContext.GetDestination ().SetSpaceBefore (readerContext.GetCurrentGroupContext ()->fDestinationContext.fSpaceBefore =
2619 TWIPS (controlWord.fValue));
2624bool StyledTextIOReader_RTF::HandleControlWord_shad (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2626 ApplyFontSpec (readerContext, controlWord);
2630bool StyledTextIOReader_RTF::HandleControlWord_sl (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2632 if (not controlWord.fHasArg) {
2633 HandleBadlyFormattedInput ();
2636 readerContext.GetDestination ().SetSpaceBetweenLines (readerContext.GetCurrentGroupContext ()->fDestinationContext.fSpaceBetweenLines =
2637 controlWord.fValue);
2642bool StyledTextIOReader_RTF::HandleControlWord_slmult (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2644 if (not controlWord.fHasArg) {
2645 HandleBadlyFormattedInput ();
2648 readerContext.GetDestination ().SetSpaceBetweenLinesMult (
2649 readerContext.GetCurrentGroupContext ()->fDestinationContext.fSpaceBetweenLinesMult =
static_cast<bool> (controlWord.fValue));
2654bool StyledTextIOReader_RTF::HandleControlWord_sub (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2656 ApplyFontSpec (readerContext, controlWord);
2660bool StyledTextIOReader_RTF::HandleControlWord_super (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2662 ApplyFontSpec (readerContext, controlWord);
2666bool StyledTextIOReader_RTF::HandleControlWord_strike (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2668 ApplyFontSpec (readerContext, controlWord);
2672bool StyledTextIOReader_RTF::HandleControlWord_stylesheet (ReaderContext& ,
const RTFIO::ControlWord& )
2674 SkipToEndOfCurrentGroup ();
2678bool StyledTextIOReader_RTF::HandleControlWord_trleft (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2680 CheckIfAboutToStartBody (readerContext);
2681 if (not controlWord.fHasArg) {
2682 HandleBadlyFormattedInput ();
2684 readerContext.GetDestination ().Set_trleft (TWIPS (controlWord.fValue));
2688bool StyledTextIOReader_RTF::HandleControlWord_trgaph (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2690 CheckIfAboutToStartBody (readerContext);
2691 if (not controlWord.fHasArg) {
2692 HandleBadlyFormattedInput ();
2694 TWIPS margins = TWIPS (controlWord.fValue);
2695 readerContext.GetDestination ().SetDefaultCellMarginsForRow_top (margins);
2696 readerContext.GetDestination ().SetDefaultCellMarginsForRow_left (margins);
2697 readerContext.GetDestination ().SetDefaultCellMarginsForRow_bottom (margins);
2698 readerContext.GetDestination ().SetDefaultCellMarginsForRow_right (margins);
2702bool StyledTextIOReader_RTF::HandleControlWord_trowd (ReaderContext& readerContext,
const RTFIO::ControlWord& )
2704 CheckIfAboutToStartBody (readerContext);
2705 readerContext.GetDestination ().Call_trowd ();
2709bool StyledTextIOReader_RTF::HandleControlWord_trpaddX (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2711 CheckIfAboutToStartBody (readerContext);
2712 if (not controlWord.fHasArg) {
2713 HandleBadlyFormattedInput ();
2715 TWIPS margin = TWIPS (controlWord.fValue);
2716 switch (controlWord.fWord) {
2717 case RTFIO::eControlAtom_trpaddb:
2718 readerContext.GetDestination ().SetDefaultCellMarginsForRow_bottom (margin);
2720 case RTFIO::eControlAtom_trpaddl:
2721 readerContext.GetDestination ().SetDefaultCellMarginsForRow_left (margin);
2723 case RTFIO::eControlAtom_trpaddr:
2724 readerContext.GetDestination ().SetDefaultCellMarginsForRow_right (margin);
2726 case RTFIO::eControlAtom_trpaddt:
2727 readerContext.GetDestination ().SetDefaultCellMarginsForRow_top (margin);
2735bool StyledTextIOReader_RTF::HandleControlWord_trspdX (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2737 CheckIfAboutToStartBody (readerContext);
2738 if (not controlWord.fHasArg) {
2739 HandleBadlyFormattedInput ();
2741 TWIPS margin = TWIPS (controlWord.fValue);
2742 switch (controlWord.fWord) {
2743 case RTFIO::eControlAtom_trspdb:
2744 readerContext.GetDestination ().SetDefaultCellSpacingForRow_bottom (margin);
2746 case RTFIO::eControlAtom_trspdl:
2747 readerContext.GetDestination ().SetDefaultCellSpacingForRow_left (margin);
2749 case RTFIO::eControlAtom_trspdr:
2750 readerContext.GetDestination ().SetDefaultCellSpacingForRow_right (margin);
2752 case RTFIO::eControlAtom_trspdt:
2753 readerContext.GetDestination ().SetDefaultCellSpacingForRow_top (margin);
2761bool StyledTextIOReader_RTF::HandleControlWord_tx (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2763 if (not controlWord.fHasArg) {
2764 HandleBadlyFormattedInput ();
2767 StandardTabStopList* curTabs = &readerContext.GetCurrentGroupContext ()->fDestinationContext.fTabStops;
2768 CoordinateType lastStop = 0;
2769 for (
auto i = curTabs->fTabStops.begin (); i != curTabs->fTabStops.end (); ++i) {
2772 TWIPS newStop = TWIPS (controlWord.fValue);
2773 if (newStop <= lastStop) {
2774 HandleBadlyFormattedInput ();
2777 Assert (newStop > lastStop);
2778 curTabs->fTabStops.push_back (TWIPS (newStop - lastStop));
2779 readerContext.GetDestination ().SetTabStops (*curTabs);
2784bool StyledTextIOReader_RTF::HandleControlWord_u ([[maybe_unused]] ReaderContext& readerContext, [[maybe_unused]]
const RTFIO::ControlWord& controlWord)
2789 if (controlWord.fHasArg) {
2790 readerContext.fSkipNextNChars_UC = readerContext.fUnicodeUCValue;
2791 wchar_t u =
static_cast<wchar_t> (controlWord.fValue);
2792 readerContext.GetDestination ().AppendText (&u, 1);
2795 HandleBadlyFormattedInput ();
2800bool StyledTextIOReader_RTF::HandleControlWord_uc ([[maybe_unused]] ReaderContext& readerContext, [[maybe_unused]]
const RTFIO::ControlWord& controlWord)
2802 if (not controlWord.fHasArg) {
2803 readerContext.fUnicodeUCValue = 1;
2806 readerContext.fUnicodeUCValue = max (0L, controlWord.fValue);
2811bool StyledTextIOReader_RTF::HandleControlWord_ul (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2813 ApplyFontSpec (readerContext, controlWord);
2817bool StyledTextIOReader_RTF::HandleControlWord_ulnone (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2819 ApplyFontSpec (readerContext, controlWord);
2823bool StyledTextIOReader_RTF::HandleControlWord_up (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2828 if (controlWord.fHasArg and controlWord.fValue > 0) {
2829 RTFIO::ControlWord newCW;
2830 newCW.fHasArg =
false;
2831 newCW.fWord = RTFIO::eControlAtom_super;
2832 return HandleControlWord_super (readerContext, newCW);
2837bool StyledTextIOReader_RTF::HandleControlWord_v (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2839 CheckIfAboutToStartBody (readerContext);
2840 if (readerContext.GetCurrentGroupContext () ==
nullptr) {
2841 HandleBadlyFormattedInput (
true);
2843 bool startHidden = controlWord.fHasArg ? controlWord.fValue :
true;
2844 readerContext.GetDestination ().SetTextHidden (readerContext.GetCurrentGroupContext ()->fDestinationContext.fTextHidden = startHidden);
2848bool StyledTextIOReader_RTF::HandleControlWord_UnknownControlWord (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2850 (void)HandlePossibleSpecialCharacterControlWord (readerContext, controlWord);
2854bool StyledTextIOReader_RTF::HandlePossibleSpecialCharacterControlWord (ReaderContext& readerContext,
const RTFIO::ControlWord& controlWord)
2857 for (
size_t i = 0; i < std::size (kMappings); ++i) {
2858 if (controlWord.fWord == kMappings[i].fControlWordName) {
2859 CheckIfAboutToStartBody (readerContext);
2860 readerContext.GetDestination ().AppendText (&kMappings[i].fUNICODECharacter, 1);
2867void StyledTextIOReader_RTF::ReadCommentGroup (ReaderContext& readerContext)
2878 if (PeekNextChar () == RTFIO::kRTFStartTagChar) {
2879 RTFIO::ControlWord cword = ReadControlWord ();
2880 if (cword.fWord == RTFIO::eControlAtom_pn) {
2881 ReadIn_pn_Group (readerContext);
2886 SkipToEndOfCurrentGroup ();
2889void StyledTextIOReader_RTF::ReadIn_pn_Group (ReaderContext& readerContext)
2897 ListStyle listStyle = eListStyle_Bullet;
2898 if (readerContext.GetParentGroupContext () !=
nullptr) {
2899 readerContext.GetDestination ().SetListStyle (readerContext.GetParentGroupContext ()->fDestinationContext.fListStyle = listStyle);
2901 SkipToEndOfCurrentGroup ();
2904inline bool quickIsAlpha (
char c)
2906 return (c >=
'a' and c <=
'z') or (c >=
'A' and c <=
'Z');
2908inline bool quickIsDigit (
char c)
2910 return (c >=
'0' and c <=
'9');
2913RTFIO::ControlWord StyledTextIOReader_RTF::ReadControlWord ()
2919 RTFIO::ControlWord controlWord;
2921 if (GetNextChar () != RTFIO::kRTFStartTagChar) {
2923 HandleBadlyFormattedInput (
true);
2932 char c = GetNextChar ();
2982 RTFIO::ControlWordAtomName controlWordBuf;
2983 size_t controlWordLen = 0;
2984 for (; quickIsAlpha (c); c = GetNextChar ()) {
2992 if (controlWordLen < RTFIO::eMaxControlAtomNameLen) {
2993 controlWordBuf[controlWordLen] = c;
2996#if qStroika_Foundation_Debug_AssertionsChecked
3002 controlWordBuf[controlWordLen] =
'\0';
3003 controlWord.fWord = RTFIO::EnterControlWord (controlWordBuf);
3012 else if (c ==
'-' or quickIsDigit (c)) {
3013 bool negative = bool (c ==
'-');
3017 unsigned long number = 0;
3018 for (; quickIsDigit (c); c = GetNextChar ()) {
3020 number += (
unsigned long)(c -
'0');
3022 controlWord.fHasArg =
true;
3025 controlWord.fValue = negative ? -long (number) : number;
3042void StyledTextIOReader_RTF::AboutToStartBody (ReaderContext& readerContext)
3044 Require (not readerContext.fStartedBodyYet);
3045 readerContext.fStartedBodyYet =
true;
3047 if (readerContext.fDefaultFontNumber != size_t (-1)) {
3050 IncrementalFontSpecification fontSpec = readerContext.GetCurrentGroupContext ()->fDestinationContext.fFontSpec;
3054 if (readerContext.fFontTable !=
nullptr) {
3055 IncrementalFontSpecification a = readerContext.fFontTable->GetFontSpec (readerContext.fDefaultFontNumber);
3056 if (a.GetFontNameSpecifier_Valid ()) {
3057 fontSpec.SetFontNameSpecifier (a.GetFontNameSpecifier ());
3060 newPlain.SetFontNameSpecifier (a.GetFontNameSpecifier ());
3061 SetPlainFont (newPlain);
3064 readerContext.GetDestination ().UseFont (readerContext.GetCurrentGroupContext ()->fDestinationContext.fFontSpec = fontSpec);
3068FontTableEntry StyledTextIOReader_RTF::ReadInFontTablesEntry ()
3074 FontTableEntry entry;
3076 if (GetNextChar () != RTFIO::kRTFOpenGroupChar) {
3081 while (PeekNextChar () == RTFIO::kRTFStartTagChar) {
3082 RTFIO::ControlWord cword = ReadControlWord ();
3083 switch (cword.fWord) {
3084 case RTFIO::eControlAtom_f: {
3085 if (not cword.fHasArg) {
3086 HandleBadlyFormattedInput ();
3089 entry.fFNum = cword.fValue;
3093 case RTFIO::eControlAtom_fnil:
3094 entry.fFamily = FontTableEntry::eNil;
3096 case RTFIO::eControlAtom_froman:
3097 entry.fFamily = FontTableEntry::eRoman;
3099 case RTFIO::eControlAtom_fswiss:
3100 entry.fFamily = FontTableEntry::eSwiss;
3102 case RTFIO::eControlAtom_fmodern:
3103 entry.fFamily = FontTableEntry::eModern;
3105 case RTFIO::eControlAtom_fscript:
3106 entry.fFamily = FontTableEntry::eScript;
3108 case RTFIO::eControlAtom_fdecor:
3109 entry.fFamily = FontTableEntry::eDecor;
3111 case RTFIO::eControlAtom_ftech:
3112 entry.fFamily = FontTableEntry::eTech;
3114 case RTFIO::eControlAtom_fbidi:
3115 entry.fFamily = FontTableEntry::eBidi;
3118 case RTFIO::eControlAtom_fcharset: {
3119 if (not cword.fHasArg) {
3120 HandleBadlyFormattedInput ();
3123 entry.fCharSet =
static_cast<uint8_t
> (cword.fValue);
3126 case RTFIO::eControlAtom_fprq: {
3127 if (not cword.fHasArg) {
3128 HandleBadlyFormattedInput ();
3131 entry.fPitch = cword.fValue;
3140 if (PeekNextChar () == RTFIO::kRTFOpenGroupChar) {
3142 SkipToEndOfCurrentGroup ();
3146 size_t startOfName = GetSrcStream ().current_offset ();
3147 ScanForwardFor (
"{;");
3148 entry.fFontName = String::FromNarrowSDKString (GrabString (startOfName)).AsSDKString ();
3151 if (PeekNextChar () == RTFIO::kRTFOpenGroupChar) {
3153 SkipToEndOfCurrentGroup ();
3156 ScanForwardFor (
"}");
3157 if (GetNextChar () != RTFIO::kRTFCloseGroupChar) {
3158 HandleBadlyFormattedInput (
true);
3165void StyledTextIOReader_RTF::ReadInObjectSubGroupEntry (ReaderContext& readerContext, vector<char>* data,
size_t* resultFoundAt)
3168 if (GetNextChar () != RTFIO::kRTFOpenGroupChar) {
3169 HandleBadlyFormattedInput (
true);
3172 if (PeekNextChar () == RTFIO::kRTFStartTagChar) {
3176 size_t xxxxxxx = readerContext.GetReader ().GetSrcStream ().current_offset ();
3177 RTFIO::ControlWord xxx = ReadControlWord ();
3178 if (xxx.fWord == RTFIO::eControlAtom_result) {
3179 *resultFoundAt = readerContext.GetReader ().GetSrcStream ().current_offset ();
3180 SkipToEndOfCurrentGroup ();
3184 GetSrcStream ().seek_to (xxxxxxx);
3191 if (PeekNextChar () ==
'*') {
3194 if (PeekNextChar () == RTFIO::kRTFStartTagChar) {
3195 RTFIO::ControlWord cword = ReadControlWord ();
3196 if (cword.fWord == RTFIO::eControlAtom_objdata) {
3203 SkipToEndOfCurrentGroup ();
3206void StyledTextIOReader_RTF::ReadObjData (vector<char>* data)
3211 for (
char c = PeekNextChar (); c != RTFIO::kRTFCloseGroupChar; c = PeekNextChar ()) {
3212 if (c ==
'\n' or c ==
'\r') {
3216 data->push_back (GetNextRTFHexByte ());
3218 Assert (PeekNextChar () == RTFIO::kRTFCloseGroupChar);
3222void StyledTextIOReader_RTF::ConstructOLEEmebddingFromRTFInfo ([[maybe_unused]] ReaderContext& readerContext, [[maybe_unused]] TWIPS_Point size,
3223 [[maybe_unused]]
size_t nBytes, [[maybe_unused]]
const void* data)
3225#if qStroika_Platform_Windows
3226 using RTFOLEEmbedding = RTFIO::RTFOLEEmbedding;
3228 const vector<EmbeddedObjectCreatorRegistry::Assoc>& types = EmbeddedObjectCreatorRegistry::Get ().GetAssocList ();
3229 for (
size_t i = 0; i < types.size (); ++i) {
3230 EmbeddedObjectCreatorRegistry::Assoc assoc = types[i];
3231 if (memcmp (assoc.fEmbeddingTag, RTFIO::RTFOLEEmbedding::kEmbeddingTag, sizeof (RTFIO::RTFOLEEmbedding::kEmbeddingTag)) == 0) {
3233 SimpleEmbeddedObjectStyleMarker* embedding = (assoc.fReadFromMemory) (RTFIO::RTFOLEEmbedding::kEmbeddingTag, data, nBytes);
3234 RTFOLEEmbedding* rtfe =
dynamic_cast<RTFOLEEmbedding*
> (embedding);
3235 if (rtfe !=
nullptr) {
3236 rtfe->PostCreateSpecifyExtraInfo (size);
3239 readerContext.GetDestination ().AppendEmbedding (embedding);
3249 Execution::Throw (DataExchange::BadFormatException::kThe);
3252void StyledTextIOReader_RTF::ConstructLedEmebddingFromRTFInfo (ReaderContext& readerContext,
size_t nBytes,
const void* data)
3254#if qStroika_Frameworks_Led_SupportGDI
3257 if (nBytes <
sizeof (Led_PrivateEmbeddingTag)) {
3258 Execution::Throw (DataExchange::BadFormatException::kThe);
3260 const char* tag = (
const char*)data;
3261 const char* theData = tag +
sizeof (Led_PrivateEmbeddingTag);
3262 size_t theDataNBytes = nBytes -
sizeof (Led_PrivateEmbeddingTag);
3263 const vector<EmbeddedObjectCreatorRegistry::Assoc>& types = EmbeddedObjectCreatorRegistry::Get ().GetAssocList ();
3264 for (
size_t i = 0; i < types.size (); ++i) {
3265 EmbeddedObjectCreatorRegistry::Assoc assoc = types[i];
3266 if (memcmp (assoc.fEmbeddingTag, tag, sizeof (assoc.fEmbeddingTag)) == 0) {
3268 SimpleEmbeddedObjectStyleMarker* embedding = (assoc.fReadFromMemory) (tag, theData, theDataNBytes);
3270 readerContext.GetDestination ().AppendEmbedding (embedding);
3280 Execution::Throw (DataExchange::BadFormatException::kThe);
3283void StyledTextIOReader_RTF::ReadPictData (vector<char>* data)
3289 for (
char c = PeekNextChar (); c != RTFIO::kRTFCloseGroupChar and c != RTFIO::kRTFStartTagChar; c = PeekNextChar ()) {
3290 if (c ==
'\n' or c ==
'\r') {
3294 PUSH_BACK (*data, GetNextRTFHexByte ());
3296 Assert (PeekNextChar () == RTFIO::kRTFCloseGroupChar or PeekNextChar () == RTFIO::kRTFStartTagChar);
3303void StyledTextIOReader_RTF::ReadTopLevelPictData (TWIPS_Point* shownSize, ImageFormat* imageFormat, TWIPS_Point* bmSize, vector<char>* objData)
3305#if qStroika_Frameworks_Led_SupportGDI
3306 using UnknownRTFEmbedding = RTFIO::UnknownRTFEmbedding;
3308 using ControlWord = RTFIO::ControlWord;
3310 *imageFormat = eDefaultImageFormat;
3311 *shownSize = TWIPS_Point (TWIPS{0}, TWIPS{0});
3312 *bmSize = TWIPS_Point (TWIPS{0}, TWIPS{0});
3313 *objData = vector<char> ();
3314 float scaleX = 1.0f;
3315 float scaleY = 1.0f;
3318 switch (PeekNextChar ()) {
3319 case RTFIO::kRTFStartTagChar: {
3320 ControlWord cw = ReadControlWord ();
3322 case RTFIO::eControlAtom_emfblip:
3323 *imageFormat = eEMF;
3325 case RTFIO::eControlAtom_pngblip:
3326 *imageFormat = ePNG;
3328 case RTFIO::eControlAtom_jpegblip:
3329 *imageFormat = eJPEG;
3331 case RTFIO::eControlAtom_macpict:
3332 *imageFormat = eMacPICT;
3334 case RTFIO::eControlAtom_pmmetafile:
3335 *imageFormat = ePMMetaFile;
3337 case RTFIO::eControlAtom_wmetafile:
3338 *imageFormat = eWMF;
3340 case RTFIO::eControlAtom_dibitmap:
3341 *imageFormat = eDIB;
3343 case RTFIO::eControlAtom_wbitmap:
3344 *imageFormat = eBITMAP;
3346 case RTFIO::eControlAtom_picw:
3347 if (not cw.fHasArg) {
3348 HandleBadlyFormattedInput ();
3351 bmSize->h = TWIPS (cw.fValue);
3353 case RTFIO::eControlAtom_pich:
3354 if (not cw.fHasArg) {
3355 HandleBadlyFormattedInput ();
3358 bmSize->v = TWIPS (cw.fValue);
3360 case RTFIO::eControlAtom_picwgoal:
3361 if (not cw.fHasArg) {
3362 HandleBadlyFormattedInput ();
3365 shownSize->h = TWIPS (cw.fValue);
3367 case RTFIO::eControlAtom_pichgoal:
3368 if (not cw.fHasArg) {
3369 HandleBadlyFormattedInput ();
3372 shownSize->v = TWIPS (cw.fValue);
3374 case RTFIO::eControlAtom_picscalex:
3375 if (not cw.fHasArg) {
3376 HandleBadlyFormattedInput ();
3379 scaleX = cw.fValue / 100.0f;
3381 case RTFIO::eControlAtom_picscaley:
3382 if (not cw.fHasArg) {
3383 HandleBadlyFormattedInput ();
3386 scaleY = cw.fValue / 100.0f;
3391 case RTFIO::kRTFOpenGroupChar: {
3394 SkipToEndOfCurrentGroup ();
3397 case RTFIO::kRTFCloseGroupChar: {
3401 if (shownSize->h == 0) {
3402 shownSize->h = bmSize->h;
3404 if (shownSize->v == 0) {
3405 shownSize->v = bmSize->v;
3408 shownSize->h *= scaleX;
3409 shownSize->v *= scaleY;
3410#if qStroika_Frameworks_Led_SupportGDI
3411 if (shownSize->v > 20000 or shownSize->h > 20000 or shownSize->h < 10 or shownSize->v < 10) {
3412 *shownSize = UnknownRTFEmbedding::CalcStaticDefaultShownSize ();
3420 ReadPictData (objData);
3431Led_DIB* StyledTextIOReader_RTF::ConstructDIBFromData ([[maybe_unused]] TWIPS_Point shownSize, ImageFormat imageFormat,
3432 [[maybe_unused]] TWIPS_Point bmSize,
size_t nBytes,
const void* data)
3434 if (data ==
nullptr) {
3435 HandleBadlyFormattedInput ();
3438 switch (imageFormat) {
3440 const Led_DIB* dib =
reinterpret_cast<const Led_DIB*
> (data);
3441 if (Led_GetDIBImageByteCount (dib) != nBytes) {
3442 HandleBadlyFormattedInput ();
3445 return Led_CloneDIB (dib);
3447#if qStroika_Platform_Windows
3449 Led_DIB* result =
nullptr;
3450 HENHMETAFILE hMF = ::SetEnhMetaFileBits (
static_cast<UINT
> (nBytes),
reinterpret_cast<const unsigned char*
> (data));
3452 result = ConstructDIBFromEMFHelper (shownSize, bmSize, hMF);
3455 Verify (::DeleteEnhMetaFile (hMF));
3458 Verify (::DeleteEnhMetaFile (hMF));
3462 Led_DIB* result =
nullptr;
3463 HENHMETAFILE hMF = ::SetWinMetaFileBits (
static_cast<UINT
> (nBytes),
reinterpret_cast<const unsigned char*
> (data),
nullptr,
nullptr);
3465 result = ConstructDIBFromEMFHelper (shownSize, bmSize, hMF);
3468 Verify (::DeleteEnhMetaFile (hMF));
3471 Verify (::DeleteEnhMetaFile (hMF));
3479#if qStroika_Platform_Windows
3486Led_DIB* StyledTextIOReader_RTF::ConstructDIBFromEMFHelper (TWIPS_Point shownSize, [[maybe_unused]] TWIPS_Point bmSize,
const HENHMETAFILE hMF)
3490 ENHMETAHEADER header{};
3491 Verify (::GetEnhMetaFileHeader (hMF,
sizeof (header), &header) ==
sizeof (header));
3494 Tablet screenDC = (::GetWindowDC (
nullptr));
3496 DistanceType hSize = screenDC.CvtFromTWIPSH (shownSize.h);
3497 DistanceType vSize = screenDC.CvtFromTWIPSV (shownSize.v);
3498 Led_Rect imageRect = Led_Rect (0, 0, vSize, hSize);
3501 Bitmap memoryBitmap;
3506 HBITMAP oldBitmapInDC = memDC.SelectObject (memoryBitmap);
3510 Led_Rect eraser = imageRect;
3511 Color eraseColor = Led_GetTextBackgroundColor ();
3512 Brush backgroundBrush (eraseColor.GetOSRep ());
3513 GDI_Obj_Selector pen (&memDC, ::GetStockObject (NULL_PEN));
3514 GDI_Obj_Selector brush (&memDC, backgroundBrush);
3517 memDC.Rectangle (AsRECT (eraser));
3521 HPALETTE usePalette =
nullptr;
3523 UINT nPalEntries = ::GetEnhMetaFilePaletteEntries (hMF, 0,
nullptr);
3524 Assert (nPalEntries != GDI_ERROR);
3525 if (nPalEntries != 0) {
3526 LOGPALETTE* paletteData =
reinterpret_cast<LOGPALETTE*
> (
new char[
sizeof (LOGPALETTE) + nPalEntries *
sizeof (PALETTEENTRY)]);
3527 paletteData->palVersion = 0;
3528 paletteData->palNumEntries =
static_cast<WORD
> (nPalEntries);
3529 Verify (::GetEnhMetaFilePaletteEntries (hMF, nPalEntries, paletteData->palPalEntry) == nPalEntries);
3530 usePalette = ::CreatePalette (paletteData);
3531 delete[] (
char*)paletteData;
3534 HPALETTE oldPalette =
nullptr;
3535 if (usePalette !=
nullptr) {
3536 oldPalette = ::SelectPalette (memDC, usePalette,
true);
3537 ::RealizePalette (memDC);
3541 bool failed =
false;
3543 RECT rect = AsRECT (imageRect);
3544 if (PlayEnhMetaFile (memDC.m_hDC, hMF, &rect) == 0) {
3549 if (oldPalette !=
nullptr) {
3550 ::SelectPalette (memDC, oldPalette,
true);
3552 if (usePalette !=
nullptr) {
3553 ::DeleteObject (usePalette);
3555 if (oldBitmapInDC !=
nullptr) {
3556 (void)memDC.SelectObject (oldBitmapInDC);
3559 HandleBadlyFormattedInput ();
3564 return Led_DIBFromHBITMAP (memDC.m_hDC, memoryBitmap);
3568void StyledTextIOReader_RTF::ApplyFontSpec (ReaderContext& readerContext,
const RTFIO::ControlWord& cw)
3570 CheckIfAboutToStartBody (readerContext);
3571 if (readerContext.GetCurrentGroupContext () ==
nullptr) {
3572 HandleBadlyFormattedInput (
true);
3574 IncrementalFontSpecification fontSpec = readerContext.GetCurrentGroupContext ()->fDestinationContext.fFontSpec;
3577 case RTFIO::eControlAtom_plain: {
3578 fontSpec = GetPlainFont ();
3580 readerContext.GetDestination ().SetTextHidden (readerContext.GetCurrentGroupContext ()->fDestinationContext.fTextHidden =
false);
3583 case RTFIO::eControlAtom_cf: {
3584 if (not cw.fHasArg) {
3585 HandleBadlyFormattedInput ();
3588 fontSpec.SetTextColor (LookupColor (readerContext,
static_cast<size_t> (cw.fValue)));
3591 case RTFIO::eControlAtom_f: {
3592 if (readerContext.fFontTable ==
nullptr) {
3597 if (not cw.fHasArg) {
3598 HandleBadlyFormattedInput (
true);
3600 IncrementalFontSpecification a = readerContext.fFontTable->GetFontSpec (cw.fValue);
3601 if (a.GetFontNameSpecifier_Valid ()) {
3602 fontSpec.SetFontNameSpecifier (a.GetFontNameSpecifier ());
3606 const FontTableEntry* fte = readerContext.fFontTable->LookupEntryByNumber (cw.fValue);
3607 if (fte ==
nullptr) {
3614#if qStroika_Platform_Windows
3615 if (fte->fCharSet != -1) {
3617 CodePage cp = Platform::Windows::Win32CharSetToCodePage (fte->fCharSet);
3619 readerContext.GetCurrentGroupContext ()->fCurrentCodePage = cp;
3621 readerContext.UseInputCharSetEncoding (readerContext.GetCurrentGroupContext ()->fCurrentCodePage);
3626 case RTFIO::eControlAtom_fs: {
3627 if (not cw.fHasArg) {
3628 HandleBadlyFormattedInput (
true);
3630 int newSize = cw.fValue / 2;
3634 if (newSize > 128) {
3637#if qStroika_Platform_Windows
3638 if (newSize == fCachedFontSize) {
3639 fontSpec.PokeAtTMHeight (fCachedFontSizeTMHeight);
3643 fontSpec.SetPointSize (
static_cast<FontSpecification::FontSize
> (newSize));
3644#if qStroika_Platform_Windows
3645 fCachedFontSize =
static_cast<FontSpecification::FontSize
> (newSize);
3646 fCachedFontSizeTMHeight = fontSpec.PeekAtTMHeight ();
3650 case RTFIO::eControlAtom_b: {
3651 bool turnStyleOn =
true;
3653 turnStyleOn = cw.fValue;
3655 fontSpec.SetStyle_Bold (turnStyleOn);
3658 case RTFIO::eControlAtom_i: {
3659 bool turnStyleOn =
true;
3661 turnStyleOn = cw.fValue;
3663 fontSpec.SetStyle_Italic (turnStyleOn);
3666 case RTFIO::eControlAtom_sub: {
3667 fontSpec.SetStyle_SubOrSuperScript (FontSpecification::eSubscript);
3669 case RTFIO::eControlAtom_super: {
3670 fontSpec.SetStyle_SubOrSuperScript (FontSpecification::eSuperscript);
3672 case RTFIO::eControlAtom_strike: {
3673#if qStroika_Platform_Windows
3674 bool turnStyleOn =
true;
3676 turnStyleOn = cw.fValue;
3678 fontSpec.SetStyle_Strikeout (turnStyleOn);
3681 case RTFIO::eControlAtom_ul: {
3682 bool turnStyleOn =
true;
3684 turnStyleOn = cw.fValue;
3686 fontSpec.SetStyle_Underline (turnStyleOn);
3689 case RTFIO::eControlAtom_ulnone: {
3690 fontSpec.SetStyle_Underline (
false);
3693 readerContext.GetDestination ().UseFont (readerContext.GetCurrentGroupContext ()->fDestinationContext.fFontSpec = fontSpec);
3696unsigned char StyledTextIOReader_RTF::GetNextRTFHexByte ()
const
3698 char c = GetNextChar ();
3701 while (c ==
'\n' or c ==
'\r') {
3704 unsigned char value =
'\0';
3705 if (c >=
'0' and c <=
'9') {
3708 else if (c >=
'a' and c <=
'f') {
3709 value = c -
'a' + 10;
3711 else if (c >=
'A' and c <=
'F') {
3712 value = c -
'A' + 10;
3716 HandleBadlyFormattedInput (
true);
3721 while (c ==
'\n' or c ==
'\r') {
3724 unsigned char value2 =
'\0';
3725 if (c >=
'0' and c <=
'9') {
3728 else if (c >=
'a' and c <=
'f') {
3729 value2 = c -
'a' + 10;
3731 else if (c >=
'A' and c <=
'F') {
3732 value2 = c -
'A' + 10;
3736 HandleBadlyFormattedInput (
true);
3743string StyledTextIOReader_RTF::ReadInGroupAndSave ()
3745 size_t startOfGroup = GetSrcStream ().current_offset ();
3746 if (GetNextChar () != RTFIO::kRTFOpenGroupChar) {
3747 HandleBadlyFormattedInput (
true);
3749 SkipToEndOfCurrentGroup ();
3750 return GrabString (startOfGroup);
3753void StyledTextIOReader_RTF::SkipToEndOfCurrentGroup ()
3756 for (; depth > 0;) {
3757 ScanForwardFor (
"{}");
3758 switch (PeekNextChar ()) {
3759 case RTFIO::kRTFOpenGroupChar: {
3763 case RTFIO::kRTFCloseGroupChar: {
3774void StyledTextIOReader_RTF::ScanForwardFor (
const char* setOfChars)
3778#if qUseCompiledSetHack_
3779 bitset<256> compiledSet;
3780 for (
auto p = setOfChars; *p !=
'\0'; ++p) {
3781 compiledSet[(
unsigned char)*p] =
true;
3786 for (
char c = GetNextChar ();; c = GetNextChar ()) {
3787 if (c == RTFIO::kRTFQuoteNextCharChar) {
3790#if qUseCompiledSetHack_
3791 if (compiledSet[(
unsigned char)c]) {
3796 for (
const char* p = setOfChars; *p !=
'\0'; ++p) {
3805 catch (ReadEOFException&) {
3818bool StyledTextIOReader_RTF::SearchForwardFor (
const char* searchFor,
size_t maxCharsToExamine)
3821 SrcStream& srcStream = GetSrcStream ();
3822 size_t origOffset = srcStream.current_offset ();
3823 size_t matchStrLen = ::strlen (searchFor);
3824 Require (matchStrLen >= 1);
3828 for (; (c = GetNextChar ()) !=
'\0';) {
3829 if (c == *searchFor) {
3831 size_t foundAt = srcStream.current_offset () - 1;
3832 for (c = GetNextChar (); matchStrLen > (srcStream.current_offset () - foundAt); c = GetNextChar ()) {
3833 size_t idx = srcStream.current_offset () - foundAt - 1;
3834 if (searchFor[idx] == c) {
3839 srcStream.seek_to (foundAt + 1);
3840 goto RetryNextMatch;
3844 Assert (matchStrLen == srcStream.current_offset () - foundAt);
3845 srcStream.seek_to (foundAt);
3848 if (srcStream.current_offset () > origOffset + maxCharsToExamine) {
3849 srcStream.seek_to (origOffset);
3854 catch (ReadEOFException) {
3855 srcStream.seek_to (origOffset);
3859 srcStream.seek_to (origOffset);
3865RTFInfo& StyledTextIOReader_RTF::GetRTFInfo ()
const
3876size_t StyledTextIOWriter_RTF::WriterContext::GetCurSrcOffset ()
const
3878 return GetSrcStream ().current_offset ();
3881#if qStroika_Frameworks_Led_SupportGDI
3882SimpleEmbeddedObjectStyleMarker* StyledTextIOWriter_RTF::WriterContext::GetCurSimpleEmbeddedObjectStyleMarker ()
const
3884 size_t offset = GetCurSrcOffset ();
3885 vector<SimpleEmbeddedObjectStyleMarker*> embeddingsList = GetSrcStream ().CollectAllEmbeddingMarkersInRange (offset - 1, offset);
3886 Assert (embeddingsList.size () <= 1);
3889 if (embeddingsList.empty ()) {
3893 return embeddingsList[0];
3898StyledTextIOWriter_RTF::Table* StyledTextIOWriter_RTF::WriterContext::GetCurRTFTable ()
const
3900 return GetSrcStream ().GetTableAt (GetCurSrcOffset () - 1);
3908StyledTextIOWriter_RTF::StyledTextIOWriter_RTF (SrcStream* srcStream, SinkStream* sinkStream, RTFInfo* rtfInfo)
3909 : StyledTextIOWriter (srcStream, sinkStream)
3910 , fCurrentOutputCharSetEncoding{WellKnownCodePages::kANSI}
3912 , fDocumentCharacterSet{WellKnownCodePages::kANSI}
3913 , fSoftLineBreakChar (srcStream->GetSoftLineBreakCharacter ())
3914 , fHidableTextRuns (srcStream->GetHidableTextRuns ())
3916 static const pair<string, wchar_t> kCharsWrittenByName[] = {
3917 pair<string, wchar_t> (
"tab", L
'\x0009'), pair<string, wchar_t> (
"emdash", L
'\x2013'),
3918 pair<string, wchar_t> (
"endash", L
'\x2014'), pair<string, wchar_t> (
"lquote", L
'\x2018'),
3919 pair<string, wchar_t> (
"rquote", L
'\x2019'), pair<string, wchar_t> (
"ldblquote", L
'\x201c'),
3920 pair<string, wchar_t> (
"rdblquote", L
'\x201d'),
3922 SetCharactersSavedByName (vector<pair<string, wchar_t>> (&kCharsWrittenByName[0], &kCharsWrittenByName[std::size (kCharsWrittenByName)]));
3925StyledTextIOWriter_RTF::~StyledTextIOWriter_RTF ()
3932void StyledTextIOWriter_RTF::UseOutputCharSetEncoding (
CodePage codePage)
3934 fCurrentOutputCharSetEncoding = codePage;
3937void StyledTextIOWriter_RTF::SetCharactersSavedByName (
const vector<pair<string, wchar_t>>& charactersSavedByName)
3939 fCharactersSavedByName = charactersSavedByName;
3940 for (vector<pair<string, wchar_t>>::const_iterator i = fCharactersSavedByName.begin (); i != fCharactersSavedByName.end (); ++i) {
3941 fCharactersSavedByName_Name2Char.insert (map<string, wchar_t>::value_type (i->first, i->second));
3942 fCharactersSavedByName_Char2Name.insert (map<wchar_t, string>::value_type (i->second, i->first));
3946void StyledTextIOWriter_RTF::Write ()
3948 WriterContext writerContext (*
this);
3950 write (RTFIO::kRTFOpenGroupChar);
3951 WriteHeader (writerContext);
3952 WriteBody (writerContext);
3953 write (RTFIO::kRTFCloseGroupChar);
3956void StyledTextIOWriter_RTF::WriteHeader (WriterContext& writerContext)
3960 WriteFontTable (writerContext);
3961 WriteColorTable (writerContext);
3963 if (fRTFInfo !=
nullptr) {
3964 WriteTagNValue (
"deftab", fRTFInfo->fDefaultTabStop);
3969void StyledTextIOWriter_RTF::WriteBody (WriterContext& writerContext)
3976 AssureStyleRunSummaryBuilt (writerContext);
3978 WriteStartParagraph (writerContext);
3979 writerContext.fLastEmittedISR = StyledInfoSummaryRecord (IncrementalFontSpecification (), 0);
3980 writerContext.fNextStyleChangeAt = 0;
3981 writerContext.fIthStyleRun = 0;
3982 if (not fHidableTextRuns.empty ()) {
3983 writerContext.fNextHidableTextChangeAt = fHidableTextRuns[0].fOffsetFromPrev;
3986 while (writerContext.GetSrcStream ().readNTChars (&c, 1) != 0) {
3987 WriteBodyCharacter (writerContext, c);
3989 if (writerContext.fHidableTextRegionOpen) {
3991 writerContext.fNextHidableTextChangeAt = size_t (-1);
3995void StyledTextIOWriter_RTF::WriteBodyCharacter (WriterContext& writerContext, Led_tChar c)
4003 if (writerContext.GetCurSrcOffset () - 1 == writerContext.fNextHidableTextChangeAt) {
4004 if (writerContext.fHidableTextRegionOpen) {
4006 ++writerContext.fIthHidableTextRun;
4007 if (writerContext.fIthHidableTextRun < fHidableTextRuns.size ()) {
4008 writerContext.fNextHidableTextChangeAt += fHidableTextRuns[writerContext.fIthHidableTextRun].fOffsetFromPrev;
4011 writerContext.fNextHidableTextChangeAt = size_t (-1);
4017 writerContext.fNextHidableTextChangeAt += fHidableTextRuns[writerContext.fIthHidableTextRun].fElementLength;
4019 writerContext.fHidableTextRegionOpen = not writerContext.fHidableTextRegionOpen;
4023 if (writerContext.GetCurSrcOffset () - 1 == writerContext.fNextStyleChangeAt) {
4024 const StyledInfoSummaryRecord& nextStyleRun = fStyleRunSummary[writerContext.fIthStyleRun];
4025 if (writerContext.GetCurSrcOffset () <= 1) {
4026 EmitBodyFontInfoChange (writerContext, nextStyleRun);
4029 EmitBodyFontInfoChange (writerContext, nextStyleRun, writerContext.fLastEmittedISR);
4031 writerContext.fLastEmittedISR = nextStyleRun;
4032 writerContext.fNextStyleChangeAt += writerContext.fLastEmittedISR.fLength;
4033 ++writerContext.fIthStyleRun;
4036 if (writerContext.fCharsToSkip > 0) {
4037 --writerContext.fCharsToSkip;
4044 WriteStartParagraph (writerContext);
4059#if qStroika_Frameworks_Led_SupportGDI
4060 case kEmbeddingSentinelChar: {
4061 unique_ptr<StyledTextIOWriter_RTF::Table> table (writerContext.GetCurRTFTable ());
4062 if (table.get () !=
nullptr) {
4063 Assert (writerContext.fCharsToSkip == 0);
4064 WriteTable (writerContext, table.get ());
4065 size_t x = table->GetOffsetEnd ();
4067 writerContext.fCharsToSkip = x - 1;
4071 SimpleEmbeddedObjectStyleMarker* embedding = writerContext.GetCurSimpleEmbeddedObjectStyleMarker ();
4072 if (embedding ==
nullptr) {
4073 WriteHexCharHelper (kEmbeddingSentinelChar);
4076 if (PossiblyWriteUnknownRTFEmbedding (writerContext, embedding)) {
4079 else if (PossiblyWriteOLERTFEmbedding (writerContext, embedding)) {
4082 else if (PossiblyWritePICTEmbedding (writerContext, embedding)) {
4085 WritePrivatLedEmbedding (writerContext, embedding);
4091 if (c == fSoftLineBreakChar) {
4095 map<wchar_t, string>::const_iterator i = fCharactersSavedByName_Char2Name.find (c);
4097 if (i == fCharactersSavedByName_Char2Name.end ()) {
4098 WritePlainUnicodeCharCharacterHelper (uc);
4101 WriteTag ((*i).second.c_str ());
4106 if ((writerContext.GetCurSrcOffset ()) % 80 == 0) {
4112void StyledTextIOWriter_RTF::WritePlainUnicodeCharCharacterHelper (
wchar_t c)
4115 size_t mbCharCount =
4116 CodeCvt<wchar_t>{fCurrentOutputCharSetEncoding}.Characters2Bytes (span{&c, 1}, Memory::SpanBytesCast<span<byte>> (span{mbCharBuf})).size ();
4117 Assert (mbCharCount == 1 or mbCharCount == 2);
4119 bool needToWriteUNICODE = c >= 0x80;
4120 if (needToWriteUNICODE) {
4122 WriteTagNValue (
"uc",
static_cast<int> (mbCharCount));
4123 WriteTagNValue (
"u", c);
4126 unsigned char uc = mbCharBuf[0];
4131 WriteHexCharHelper (uc);
4133 if (mbCharCount == 2) {
4139 WriteHexCharHelper (uc);
4144void StyledTextIOWriter_RTF::WriteHexCharHelper (
unsigned char c)
4150 buf[2] = ConvertWriteSingleHexDigit_ (c / 16);
4151 buf[3] = ConvertWriteSingleHexDigit_ (c % 16);
4156void StyledTextIOWriter_RTF::WriteStartParagraph (WriterContext& writerContext)
4159 if (writerContext.fInTable) {
4162 switch (writerContext.GetSrcStream ().GetJustification ()) {
4163 case eCenterJustify:
4175 StandardTabStopList tabStops = writerContext.GetSrcStream ().GetStandardTabStopList ();
4178 TWIPS tabSoFar = TWIPS{0};
4179 for (
size_t i = 0; i < tabStops.fTabStops.size (); ++i) {
4180 tabSoFar += tabStops.fTabStops[i];
4181 WriteTagNValue (
"tx", tabSoFar);
4185 TWIPS fi = writerContext.GetSrcStream ().GetFirstIndent ();
4187 WriteTagNValue (
"fi", fi);
4192 TWIPS lhs = TWIPS{0};
4193 TWIPS rhs = TWIPS{0};
4194 writerContext.GetSrcStream ().GetMargins (&lhs, &rhs);
4196 WriteTagNValue (
"li", lhs);
4199 TWIPS effectiveDrawingWidth = fRTFInfo ==
nullptr ? RTFInfo ().GetEffectiveDrawingWidth () : fRTFInfo->GetEffectiveDrawingWidth ();
4200 TWIPS rhsRTFMarginInTWIPS = TWIPS (effectiveDrawingWidth - rhs);
4201 if (rhsRTFMarginInTWIPS != 0) {
4202 WriteTagNValue (
"ri", rhsRTFMarginInTWIPS);
4207 TWIPS sb = writerContext.GetSrcStream ().GetSpaceBefore ();
4209 WriteTagNValue (
"sb", sb);
4213 TWIPS sa = writerContext.GetSrcStream ().GetSpaceAfter ();
4215 WriteTagNValue (
"sa", sa);
4219 LineSpacing sl = writerContext.GetSrcStream ().GetLineSpacing ();
4220 if (sl.fRule != LineSpacing::eSingleSpace) {
4221 CoordinateType rtfsl = 1000;
4223 mkRTFValues_From_LineSpacing (sl, &rtfsl, &multi);
4224 if (rtfsl != 1000) {
4225 WriteTagNValue (
"sl", rtfsl);
4226 WriteTagNValue (
"slmult", multi);
4231 ListStyle listStyle = eListStyle_None;
4232 unsigned char indentLevel = 0;
4233 writerContext.GetSrcStream ().GetListStyleInfo (&listStyle, &indentLevel);
4234 if (listStyle != eListStyle_None) {
4238 WriteTag (
"listtext");
4245 int listTableID = 1;
4246 WriteTagNValue (
"ls", listTableID);
4247 if (indentLevel != 0) {
4248 WriteTagNValue (
"ilvl", indentLevel);
4254void StyledTextIOWriter_RTF::WriteTable (WriterContext& writerContext, Table* table)
4256 using CellInfo = StyledTextIOWriter_RTF::Table::CellInfo;
4260 size_t rows = table->GetRows ();
4261 for (
size_t r = 0; r < rows; ++r) {
4264 TWIPS_Rect cellMargins = table->GetDefaultCellMarginsForRow (r);
4265 TWIPS_Rect cellSpacing = table->GetDefaultCellSpacingForRow (r);
4267 WriteTagNValue (
"trgaph", (cellMargins.top + cellMargins.left + cellMargins.bottom + cellMargins.right) / 4);
4270 if (cellSpacing.top != 0) {
4271 WriteTagNValue (
"trspdt", cellSpacing.top / 2);
4272 WriteTagNValue (
"trspdft", 3);
4274 if (cellSpacing.left != 0) {
4275 WriteTagNValue (
"trspdl", cellSpacing.left / 2);
4276 WriteTagNValue (
"trspdfl", 3);
4278 if (cellSpacing.bottom != 0) {
4279 WriteTagNValue (
"trspdb", cellSpacing.bottom / 2);
4280 WriteTagNValue (
"trspdfb", 3);
4282 if (cellSpacing.right != 0) {
4283 WriteTagNValue (
"trspdr", cellSpacing.right / 2);
4284 WriteTagNValue (
"trspdfr", 3);
4289 if (cellMargins.top != 0) {
4290 WriteTagNValue (
"trpaddt", cellMargins.top);
4291 WriteTagNValue (
"trpaddft", 3);
4293 if (cellMargins.left != 0) {
4294 WriteTagNValue (
"trpaddl", cellMargins.left);
4295 WriteTagNValue (
"trpaddfl", 3);
4297 if (cellMargins.bottom != 0) {
4298 WriteTagNValue (
"trpaddb", cellMargins.bottom);
4299 WriteTagNValue (
"trpaddfb", 3);
4301 if (cellMargins.right != 0) {
4302 WriteTagNValue (
"trpaddr", cellMargins.right);
4303 WriteTagNValue (
"trpaddfr", 3);
4307 vector<CellInfo> cellInfos;
4308 table->GetRowInfo (r, &cellInfos);
4309 size_t columns = cellInfos.size ();
4312 TWIPS cellxSoFar = TWIPS{0};
4313 for (vector<CellInfo>::const_iterator i = cellInfos.begin (); i != cellInfos.end (); ++i) {
4314 WriteTagNValue (
"clcbpat",
static_cast<int> (fColorTable->LookupColor (i->f_clcbpat)));
4319 TWIPS cellWidthIncludingSpacing = (*i).f_cellx + TWIPS (3 * cellSpacing.left / 2);
4321 cellxSoFar += cellWidthIncludingSpacing;
4322 WriteTagNValue (
"cellx", cellxSoFar);
4326#if qStroika_Foundation_Debug_AssertionsChecked
4327 size_t nCellsWritten = 0;
4329 for (
size_t c = 0; c < columns; ++c) {
4330 unique_ptr<StyledTextIOWriter::SrcStream> srcStream = unique_ptr<StyledTextIOWriter::SrcStream>{table->MakeCellSubSrcStream (r, c)};
4331 if (srcStream.get () !=
nullptr) {
4332 WriterContext wc{writerContext, *srcStream.get ()};
4333 vector<StyledInfoSummaryRecord> x = fStyleRunSummary;
4334 fStyleRunSummary.clear ();
4335 AssureStyleRunSummaryBuilt (wc);
4337 fStyleRunSummary = x;
4339#if qStroika_Foundation_Debug_AssertionsChecked
4344#if qStroika_Foundation_Debug_AssertionsChecked
4345 Assert (nCellsWritten == cellInfos.size ());
4353 WriteStartParagraph (writerContext);
4357#if qStroika_Frameworks_Led_SupportGDI
4358bool StyledTextIOWriter_RTF::PossiblyWriteUnknownRTFEmbedding (WriterContext& , SimpleEmbeddedObjectStyleMarker* embedding)
4361 if (RTFIO::UnknownRTFEmbedding* ee =
dynamic_cast<RTFIO::UnknownRTFEmbedding*
> (embedding)) {
4368 if (memcmp (ee->GetTag (), RTFIO::kRTFBodyGroupFragmentEmbeddingTag, sizeof (RTFIO::kRTFBodyGroupFragmentEmbeddingTag)) == 0) {
4369 write (ee->GetData (), ee->GetDataLength ());
4376bool StyledTextIOWriter_RTF::PossiblyWriteOLERTFEmbedding (WriterContext& , SimpleEmbeddedObjectStyleMarker* embedding)
4379 if (RTFIO::RTFOLEEmbedding* anRTFOLEEmbedding =
dynamic_cast<RTFIO::RTFOLEEmbedding*
> (embedding)) {
4382 byte* theDataBytes =
nullptr;
4383 anRTFOLEEmbedding->DoWriteToOLE1Stream (&nBytes, &theDataBytes);
4387 WriteTag (
"object");
4388 WriteTag (
"objemb");
4389 Led_Size size = anRTFOLEEmbedding->GetSize ();
4390 WriteTagNValue (
"objh", Led_CvtScreenPixelsToTWIPSV (size.v));
4391 WriteTagNValue (
"objw", Led_CvtScreenPixelsToTWIPSH (size.h));
4397 string className = String::FromSDKString (anRTFOLEEmbedding->GetObjClassName ()).AsNarrowSDKString ();
4398 if (not className.empty ()) {
4399 write (
"{\\*\\objclass ");
4402 write (className.c_str ());
4408 write (
"\\*\\objdata ");
4409 WriteHexCharDataBlock (nBytes, theDataBytes);
4410 delete[] theDataBytes;
4428#define qWriteAsDIB_ 1
4429bool StyledTextIOWriter_RTF::PossiblyWritePICTEmbedding (WriterContext& , SimpleEmbeddedObjectStyleMarker* embedding)
4432 if (StandardDIBStyleMarker* aPictEmbedding =
dynamic_cast<StandardDIBStyleMarker*
> (embedding)) {
4436 const Led_DIB* dib = aPictEmbedding->GetDIBData ();
4437 Led_Size size = Led_GetDIBImageSize (dib);
4439 int vEnhSize = size.v * (1400 / 10) * 2.54;
4440 int hEnhSize = size.h * (1400 / 10) * 2.54;
4441 WriteTagNValue (
"pich", size.v * 20);
4442 WriteTagNValue (
"picw", size.h * 20);
4444 WriteTagNValue (
"pichgoal", Led_CvtScreenPixelsToTWIPSV (size.v));
4445 WriteTagNValue (
"picwgoal", Led_CvtScreenPixelsToTWIPSH (size.h));
4448 WriteTag (
"dibitmap");
4449 const void* theDataBytes = dib;
4450 size_t nBytes = Led_GetDIBImageByteCount (dib);
4453 WriteTagNValue (
"pich", Led_CvtScreenPixelsToTWIPSV (size.v));
4454 WriteTagNValue (
"picw", Led_CvtScreenPixelsToTWIPSH (size.h));
4455 WriteTagNValue (
"wbmbitspixel", dib->bmiHeader.biBitCount == 0 ? 24 : dib->bmiHeader.biBitCount);
4456 WriteTagNValue (
"wbmplanes", dib->bmiHeader.biPlanes == 0 ? 1 : dib->bmiHeader.biPlanes);
4457 WriteTagNValue (
"wbmwidthbytes",
static_cast<int> (Led_GetDIBImageRowByteCount (dib)));
4459 WriteTagNValue (
"wmetafile", 8);
4461 void* theDataBytes =
nullptr;
4463 unique_ptr<BYTE> theDataBytes_;
4465 Tablet screenDC = (::GetWindowDC (
nullptr));
4466 UINT mapMode = MM_TEXT;
4468 HENHMETAFILE hMF =
nullptr;
4470 RECT rect = AsRECT (Led_Rect (0, 0, vEnhSize, hEnhSize));
4471 HDC hMFDC = ::CreateEnhMetaFile (
nullptr,
nullptr, &rect,
nullptr);
4472 ::SetMapMode (hMFDC, mapMode);
4473 const char* lpBits =
reinterpret_cast<const char*
> (dib) + Led_GetDIBPalletByteCount (dib) +
sizeof (BITMAPINFOHEADER);
4474 Assert (mapMode == MM_TWIPS or mapMode == MM_TEXT);
4475 if (mapMode == MM_TWIPS) {
4476 ::StretchDIBits (hMFDC, 0, 0, Led_CvtScreenPixelsToTWIPSH (size.h), Led_CvtScreenPixelsToTWIPSV (size.v), 0, 0, size.h,
4477 size.v, lpBits, dib, DIB_RGB_COLORS, SRCCOPY);
4479 else if (mapMode == MM_TEXT) {
4480 ::StretchDIBits (hMFDC, 0, 0, size.h, size.v, 0, 0, size.h, size.v, lpBits, dib, DIB_RGB_COLORS, SRCCOPY);
4482 hMF = ::CloseEnhMetaFile (hMFDC);
4484 nBytes = ::GetWinMetaFileBits (hMF, 0,
nullptr, mapMode, screenDC);
4489 BYTE* bytes =
new BYTE[nBytes];
4490 Verify (::GetWinMetaFileBits (hMF, nBytes, bytes, mapMode, screenDC) == nBytes);
4492 theDataBytes = bytes;
4493 theDataBytes_ = unique_ptr<BYTE> (bytes);
4495 ::DeleteEnhMetaFile (hMF);
4501 WriteHexCharDataBlock (nBytes, theDataBytes);
4512#if qStroika_Frameworks_Led_SupportGDI
4513void StyledTextIOWriter_RTF::WritePrivatLedEmbedding (WriterContext& , SimpleEmbeddedObjectStyleMarker* embedding)
4515 struct VectorSinkStream : SimpleEmbeddedObjectStyleMarker::SinkStream {
4517 virtual void write (
const void* buffer,
size_t bytes)
override
4519 using ci =
const char*;
4520 fData.insert (fData.end (), ci (buffer), ci (buffer) + bytes);
4524 VectorSinkStream embeddingData;
4525 embedding->Write (embeddingData);
4529 WriteTag (
"object");
4530 WriteTag (
"ledprivateobjectembeddingformat");
4536 write (
"\\*\\objdata ");
4537 WriteHexCharDataBlock (
sizeof (Led_PrivateEmbeddingTag), embedding->GetTag ());
4538 WriteHexCharDataBlock (embeddingData.fData.size (), &embeddingData.fData.front ());
4548void StyledTextIOWriter_RTF::WriteTag (
const char* tagStr)
4551 Require (tagStr[0] !=
'\\');
4552 Require (::strchr (tagStr,
' ') == 0);
4558void StyledTextIOWriter_RTF::WriteTagNValue (
const char* tagStr,
int value)
4561 Require (tagStr[0] !=
'\\');
4562 Require (::strchr (tagStr,
' ') == 0);
4566 (void)snprintf (buf, std::size (buf),
"%d", value);
4571void StyledTextIOWriter_RTF::WriteHexCharDataBlock (
size_t nBytes,
const void* resultData)
4573 const unsigned char* start = (
const unsigned char*)resultData;
4574 const unsigned char* end = start + nBytes;
4575 for (
const unsigned char* cur = start; cur != end; ++cur) {
4576 WriteRTFHexByte (*cur);
4577 if ((cur - start) % 50 == 0) {
4584void StyledTextIOWriter_RTF::WriteRTFHexByte (
unsigned char theByte)
4586 unsigned char hiNibble = (theByte) >> 4;
4587 unsigned char lowNibble = (theByte) & 0xf;
4588 Require (hiNibble <= 0xf);
4589 Require (lowNibble <= 0xf);
4590 write (ConvertWriteSingleHexDigit_ (hiNibble));
4591 write (ConvertWriteSingleHexDigit_ (lowNibble));
4594void StyledTextIOWriter_RTF::WriteDocCharset ()
4596 switch (fDocumentCharacterSet) {
4597 case WellKnownCodePages::kANSI:
4600 case WellKnownCodePages::kMAC:
4603 case WellKnownCodePages::kPC:
4606 case WellKnownCodePages::kPCA:
4615void StyledTextIOWriter_RTF::WriteFontTable (WriterContext& writerContext)
4618 WriteTag (
"fonttbl");
4620 AssureFontTableBuilt (writerContext);
4623 size_t entryCount = fFontTable->fEntries.size ();
4624 for (
size_t i = 0; i < entryCount; ++i) {
4625 WriteFontTablesEntry (fFontTable->fEntries[i]);
4631void StyledTextIOWriter_RTF::WriteFontTablesEntry (
const FontTableEntry& entry)
4635 WriteTagNValue (
"f", entry.fFNum);
4637 switch (entry.fFamily) {
4638 case FontTableEntry::eNil:
4641 case FontTableEntry::eRoman:
4642 WriteTag (
"froman");
4644 case FontTableEntry::eSwiss:
4645 WriteTag (
"fswiss");
4647 case FontTableEntry::eModern:
4648 WriteTag (
"fmodern");
4650 case FontTableEntry::eScript:
4651 WriteTag (
"fscript");
4653 case FontTableEntry::eDecor:
4654 WriteTag (
"fdecor");
4656 case FontTableEntry::eTech:
4659 case FontTableEntry::eBidi:
4664 if (entry.fCharSet !=
static_cast<uint8_t
> (-1)) {
4665 WriteTagNValue (
"fcharset", entry.fCharSet);
4668 if (entry.fPitch != 0) {
4669 WriteTagNValue (
"fprq", entry.fPitch);
4672 write (String::FromSDKString (entry.fFontName).AsNarrowSDKString ());
4679void StyledTextIOWriter_RTF::WriteColorTable (WriterContext& writerContext)
4681 AssureColorTableBuilt (writerContext);
4685 WriteTag (
"colortbl");
4687 size_t entryCount = fColorTable->fEntries.size ();
4688 for (
size_t i = 0; i < entryCount; ++i) {
4689 Color c = fColorTable->LookupColor (i);
4691 (void)snprintf (buf, std::size (buf),
"\\red%d\\green%d\\blue%d;", c.GetRed () >> 8, c.GetGreen () >> 8, c.GetBlue () >> 8);
4698void StyledTextIOWriter_RTF::WriteListTable ()
4701 RTFIO::ListTableEntry lte;
4702 lte.fListID = rand ();
4703 lte.fListTemplateID = rand ();
4704 lte.fListStyle = eListStyle_Bullet;
4706 RTFIO::ListOverrideTableEntry lote;
4707 lote.fListID = lte.fListID;
4709 write (
"\r\n{\\*\\listtable");
4710 WriteListTablesEntry (lte);
4713 write (
"{\\*\\listoverridetable");
4714 WriteListOverrideTablesEntry (lote);
4718void StyledTextIOWriter_RTF::WriteListTablesEntry (
const RTFIO::ListTableEntry& entry)
4722 WriteTagNValue (
"listtemplateid", entry.fListTemplateID);
4724 WriteTag (
"listlevel");
4725 WriteTagNValue (
"levelnfc", entry.fListStyle);
4726 WriteTagNValue (
"leveljc", 0);
4727 WriteTagNValue (
"levelfollow", 0);
4728 WriteTagNValue (
"levelstartat", 1);
4729 WriteTagNValue (
"levelindent", 0);
4731 int levelTemplateID = rand ();
4732 WriteTag (
"leveltext");
4733 WriteTagNValue (
"levelnfc", entry.fListStyle);
4734 WriteTagNValue (
"leveltemplateid", levelTemplateID);
4742 WriteTagNValue (
"u", 0x2022);
4745 WriteTagNValue (
"f", entry.fFontID);
4746 WriteTagNValue (
"fi", -360);
4747 WriteTagNValue (
"li", 720);
4748 WriteTag (
"jclisttab");
4749 WriteTagNValue (
"tx", 720);
4751 WriteTagNValue (
"listid", entry.fListID);
4755void StyledTextIOWriter_RTF::WriteListOverrideTablesEntry (
const RTFIO::ListOverrideTableEntry& oEntry)
4758 WriteTag (
"listoverride");
4759 WriteTagNValue (
"listid", oEntry.fListID);
4760 WriteTagNValue (
"listoverridecount", 0);
4761 WriteTagNValue (
"ls", 1);
4765void StyledTextIOWriter_RTF::WriteGenerator ()
4768 WriteTag (
"generator");
4769 write (
"Sophist Solutions, Inc. Stroika Led RTF IO Engine - " qStroika_Version_ShortVersionString);
4774void StyledTextIOWriter_RTF::EmitBodyFontInfoChange (WriterContext& writerContext,
const FontSpecification& newOne)
4780 if (writerContext.fHidableTextRegionOpen) {
4786 const FontTableEntry* fe = fFontTable->LookupEntryByName (newOne.GetFontName ());
4789 WriteTagNValue (
"f", fe->fFNum);
4793 WriteTagNValue (
"fs", newOne.GetPointSize () * 2);
4796 if (newOne.GetStyle_Bold ()) {
4799 if (newOne.GetStyle_Italic ()) {
4802 if (newOne.GetStyle_Underline ()) {
4805 switch (newOne.GetStyle_SubOrSuperScript ()) {
4806 case FontSpecification::eSubscript:
4809 case FontSpecification::eSuperscript:
4813#if qStroika_Platform_Windows
4814 if (newOne.GetStyle_Strikeout ()) {
4815 WriteTag (
"strike");
4819 WriteTagNValue (
"cf",
static_cast<int> (fColorTable->LookupColor (newOne.GetTextColor ())));
4825 EmitBodyFontInfoChange (writerContext, newOne);
4828void StyledTextIOWriter_RTF::AssureColorTableBuilt (WriterContext& writerContext)
4830 if (fColorTable ==
nullptr) {
4831 fColorTable =
new RTFIO::ColorTable ();
4832 set<Color> colorsUsed;
4833 writerContext.GetSrcStream ().SummarizeFontAndColorTable (
nullptr, &colorsUsed);
4834 for (set<Color>::const_iterator i = colorsUsed.begin (); i != colorsUsed.end (); ++i) {
4835 (void)fColorTable->EnterColor (*i);
4840#if qStroika_Platform_Windows
4842 BOOL FAR PASCAL Save_Charset_EnumFontFamiliesProc (ENUMLOGFONTEX* pelf, NEWTEXTMETRICEX* ,
int , LPVOID pCharset)
4844 BYTE* charSet =
reinterpret_cast<BYTE*
> (pCharset);
4845 *charSet = pelf->elfLogFont.lfCharSet;
4851void StyledTextIOWriter_RTF::AssureFontTableBuilt (WriterContext& writerContext)
4853 if (fFontTable ==
nullptr) {
4854 fFontTable =
new FontTable ();
4856 set<SDKString> fontNames;
4857 writerContext.GetSrcStream ().SummarizeFontAndColorTable (&fontNames,
nullptr);
4858#if qStroika_Platform_Windows
4859 WindowDC screenDC (
nullptr);
4861 for (set<SDKString>::const_iterator i = fontNames.begin (); i != fontNames.end (); ++i) {
4863 if (fFontTable->LookupEntryByName (name) ==
nullptr) {
4865 fte.fFontName = name;
4879#if qStroika_Platform_Windows
4881 (void)::memset (&lf, 0,
sizeof (lf));
4882 Characters::CString::Copy (lf.lfFaceName, std::size (lf.lfFaceName), name.c_str ());
4883 lf.lfCharSet = DEFAULT_CHARSET;
4884 BYTE useCharset = DEFAULT_CHARSET;
4885 ::EnumFontFamiliesEx (screenDC.m_hDC, &lf, (FONTENUMPROC)Save_Charset_EnumFontFamiliesProc,
reinterpret_cast<LPARAM
> (&useCharset), 0);
4886 if (useCharset != DEFAULT_CHARSET) {
4887 fte.fCharSet = useCharset;
4891 fFontTable->Add (fte);
4897void StyledTextIOWriter_RTF::AssureStyleRunSummaryBuilt (WriterContext& writerContext)
4899 if (fStyleRunSummary.empty ()) {
4900 size_t totalTextLength = writerContext.GetSrcStream ().GetTotalTextLength ();
4901 if (totalTextLength != 0) {
4902 fStyleRunSummary = writerContext.GetSrcStream ().GetStyleInfo (0, totalTextLength);
4907void StyledTextIOWriter_RTF::AssureListTableBuilt (WriterContext& )
4909 if (fListTable ==
nullptr) {
4910 fListTable =
new RTFIO::ListTables ();
#define RequireNotNull(p)
CodeCvt unifies byte <-> unicode conversions, vaguely inspired by (and wraps) std::codecvt,...
nonvirtual size_t Bytes2Characters(span< const byte > from) const
convert span byte (external serialized format) parameters to characters (like std::codecvt<>::in () -...
basic_string< SDKChar > SDKString