Stroika Library 3.0d23x
 
Loading...
Searching...
No Matches
StyledTextIO.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Frameworks_Led_StyledTextIO_h_
5#define _Stroika_Frameworks_Led_StyledTextIO_h_ 1
6
7#include "Stroika/Frameworks/StroikaPreComp.h"
8
10
11/*
12@MODULE: StyledTextIO
13@DESCRIPTION:
14 <p>A portable attempt at abstracting away the details of styled text file IO and all
15 the different formats for styled text.</p>
16 <p>This code defines APIs which should allow for reading any different styled text format.
17 And dumping it to any different output (eg. text buffer).</p>
18 <p>The only real LED-SPECIFIC parts of this are that I only provide concrete output (aka sinks)
19 implementations to Led StandardStyledTextImagers. And that some of the Src/Sink APIs are oriented towards what would be
20 helpful for a Led-based editor (in other words, features not supported by Led aren't communicated to/from the src/sinks).</p>
21 <p>The <em>big picture</em> for this module is that there are two main basic subdivisions. There are
22 @'StyledTextIOReader' subclasses, and @'StyledTextIOWriter' subclasses. The readers are for READING some file format,
23 and converting it to a stream of method calls (on a sink to be described later). And writers are for writing those
24 formatted data files, based on results of method calls on an abstract source class.</p>
25 <p>Though @'StyledTextIOReader' and @'StyledTextIOWriter' share no common base class, they <em>do</em> follow
26 a very similar design pattern. They both define abstract 'sources' and 'sinks' for their operation.</p>
27 <p>For a @'StyledTextIOReader', it reads its data from a @'StyledTextIOReader::SrcStream' (typically maybe a file),
28 and writes it to a @'StyledTextIOReader::SinkStream' (typically a Led-text-buffer/view).</p>
29 <p>A @'StyledTextIOWriter', writes data extracted from a @'StyledTextIOWriter::SrcStream'
30 (typically view/textstore, much like a @'StyledTextIOReader::SinkStream'),
31 and writes it to a @'StyledTextIOWriter::SinkStream' (typically an output file).</p>
32 <p>These abstract sources and sinks are defined to just the minimal pure virtual APIs needed to extract/write bare bytes,
33 or formatted text in a format Led can understand. Several concrete instantiations of each are provided by Led (some here, and
34 some in other modules, as appropriate).</p>
35 <p>Subclasses of @'StyledTextIOReader' and @'StyledTextIOWriter' are where the knowledge of particular file formats resides.
36 For example, the knowledge of how to read RTF is in @'StyledTextIOReader_RTF' and the knowledge of how to write HTML is in
37 @'StyledTextIOWriter_HTML'.</p>
38 */
39
40#include <set>
41
42#include "Stroika/Foundation/Memory/Common.h"
43
44#include "Stroika/Frameworks/Led/StandardStyledTextImager.h" // For StyledInfoSummaryRecord declaration
45#include "Stroika/Frameworks/Led/StyledTextEmbeddedObjects.h"
46#include "Stroika/Frameworks/Led/StyledTextImager.h"
47#include "Stroika/Frameworks/Led/Support.h"
48
49namespace Stroika::Frameworks::Led::StyledTextIO {
50
51 /*
52 @CLASS: StyledTextIOReader
53 @DESCRIPTION: <p>Abstract base class for styled text reading. Subclasses know about various styled text file formats, and
54 take care of the details of mapping streams of bytes into Led internal data structures with that styled text.</p>
55 */
56 class StyledTextIOReader {
57 public:
58 /*
59 @DESCRIPTION: <p>A StyledTextIOReader needs a pointer to a function which is a source of raw bytes
60 to be interpretted as text which will be inserted into a text buffer. SrcStream is an abstract class
61 defining this API.</p>
62
63 \@todo THIS IS OBSOLETE - and should be switched to using Streams::InputStream<byte> --LGP 2024-02-22
64
65 */
66 class SrcStream {
67 public:
68 virtual ~SrcStream () = default;
69
70 public:
71 /*
72 @METHOD: StyledTextIOReader::SrcStream::current_offset
73 @DESCRIPTION: <p>Return the current seekPos</p>
74 */
75 virtual size_t current_offset () const = 0;
76
77 public:
78 /*
79 @METHOD: StyledTextIOReader::SrcStream::seek_to
80 @DESCRIPTION: <p>Sets the current read-pointer to the given position (often used to scan backwards, but can be any direction).
81 Note if 'to' is past end, this just pins one past end of buffer.</p>
82 */
83 virtual void seek_to (size_t to) = 0;
84
85 public:
86 /*
87 @METHOD: StyledTextIOReader::SrcStream::read
88 @DESCRIPTION: <p>Read the given number of bytes from the is source, and fill them into the buffer. Returns
89 the number of bytes read. Always return as many bytes as possible and block if they
90 are not yet available. Don't return partial reads (except on EOF). 'bytes' can be zero, and then
91 'read' will return immediately with a return value of zero.</p>
92 */
93 virtual size_t read (void* buffer, size_t bytes) = 0;
94
95 public:
96 /*
97 @METHOD: StyledTextIOReader::SrcStream::read1
98 @DESCRIPTION: <p>Read 1 character and return the number of characters read (0 or 1).
99 This is a trivial wrapper on @'StyledTextIOReader::SrcStream::read' which can be overriden
100 and is frequently used as a performance optimization.</p>
101 */
102 virtual size_t read1 (char* c)
103 {
104 return read (c, 1);
105 }
106 };
107
108 public:
109 class SinkStream;
110 /*
111 @CLASS: StyledTextIOReader::BadInputHandler
112 @DESCRIPTION:
113 <p>Abstract base class for styled text writing. Subclasses know about various styled text file formats, and
114 take care of the details of mapping Led internal data structures with styled text into streams of bytes in that format.</p>
115 */
116 class BadInputHandler {
117 public:
118 virtual ~BadInputHandler () = default;
119 virtual void HandleBadlyFormattedInput (const StyledTextIOReader& reader, bool unrecoverable);
120 };
121
122 protected:
123 StyledTextIOReader (SrcStream* srcStream, SinkStream* sinkStream,
124 const shared_ptr<BadInputHandler>& badInputHander = shared_ptr<BadInputHandler> ()); // callers responsability to destroy srcStream/sinkStream
125
126 // The Read() method must be overriden by one subclass to provide the format interpretation
127 public:
128 virtual void Read () = 0;
129 virtual bool QuickLookAppearsToBeRightFormat () = 0;
130
131 public:
132 /*
133 @CLASS: StyledTextIOReader::BufferedIndirectSrcStream
134 @BASES: @'StyledTextIOReader::SrcStream'
135 @DESCRIPTION: <p></p>
136 */
137 class BufferedIndirectSrcStream : public SrcStream {
138 public:
139 BufferedIndirectSrcStream (SrcStream& realSrcStream);
140
141 public:
142 virtual size_t current_offset () const override;
143 virtual void seek_to (size_t to) override;
144 virtual size_t read (void* buffer, size_t bytes) override;
145 virtual size_t read1 (char* c) override;
146
147 private:
148 nonvirtual void FillCache ();
149
150 private:
151 SrcStream& fRealSrcStream;
152 char fWindowTop_Data[4 * 1024]; // buffer for how much we buffer at a time...
153 size_t fWindowTop_Offset;
154 const char* fWindowBottom_Data;
155 size_t fWindowBottom_Offset;
156 const char* fCursor_Data;
157 size_t fCursor_Offset;
158 };
159
160 public:
161 nonvirtual SrcStream& GetSrcStream () const;
162 nonvirtual SinkStream& GetSinkStream () const;
163
164 private:
165 mutable BufferedIndirectSrcStream fSrcStream;
166 SinkStream* fSinkStream;
167
168 public:
169 nonvirtual shared_ptr<BadInputHandler> GetBadInputHandler () const;
170 nonvirtual void SetBadInputHandler (const shared_ptr<BadInputHandler>& badInputHandler);
171
172 private:
173 shared_ptr<BadInputHandler> fBadInputHandler;
174
175 public:
176 nonvirtual void HandleBadlyFormattedInput (bool unrecoverable = false) const;
177
178 protected:
179 class SrcStreamSeekSaver;
180
181 protected:
182 struct ReadEOFException {}; // not an error state necesserily. Just allows our Read helper routines
183 // to be simpler. Don't need to worry as much about this special case,
184 // and they can just return chars (and throw on eof).
185
186 nonvirtual void PutBackLastChar () const;
187 nonvirtual char GetNextChar () const;
188 nonvirtual char PeekNextChar () const;
189 nonvirtual void ConsumeNextChar () const;
190 nonvirtual string GrabString (size_t from, size_t to = size_t (-1)); // doesn't move seek_to () position (rather restores it)
191 // if no end specified (-1), then grab from to current seekpos
192 };
193
194 // utility to auto-scroll back to place in stream where we were created on DTOR
195 class StyledTextIOReader::SrcStreamSeekSaver {
196 public:
197 SrcStreamSeekSaver (SrcStream& srcStream);
198 ~SrcStreamSeekSaver ();
199
200 private:
201 SrcStream& fSrcStream;
202 size_t fSavedPos;
203 };
204
205 /*
206 @CLASS: StyledTextIOReader::SinkStream
207 @DESCRIPTION: <p>A StyledTextIOReader needs a pointer to a function which is a sink for all the styled text
208 and other information read. SinkStream is an abstract class defining this API.</p>
209 */
210 class StyledTextIOReader::SinkStream {
211 public:
212 virtual ~SinkStream ()
213 {
214 }
215
216 public:
217 /*
218 @METHOD: StyledTextIOReader::SinkStream::current_offset
219 @DESCRIPTION: <p>Return the current seekPos</p>
220 */
221 virtual size_t current_offset () const = 0; // current seekPos
222
223 public:
224 /*
225 @METHOD: StyledTextIOReader::SinkStream::AppendText
226 @DESCRIPTION: <p>Append the given text to the output text buffer. If fontSpec is nullptr, use default.
227 Probably later we will return and update the fontspec with @'StyledTextIOReader::SinkStream::ApplyStyle'. Note, this style
228 of API is defined cuz some format readers give us a bunch of text at once, and then later (elsewhere) store the style
229 information. And still others provide them together, hand-in-hand.</p>
230 */
231 virtual void AppendText (const Led_tChar* text, size_t nTChars, const FontSpecification* fontSpec) = 0;
232
233 public:
234 /*
235 @METHOD: StyledTextIOReader::SinkStream::ApplyStyle
236 @DESCRIPTION: <p>Apply the given style information to the given range of text. See @'StyledTextIOReader::SinkStream::AppendText'.</p>
237 */
238 virtual void ApplyStyle (size_t from, size_t to, const vector<StyledInfoSummaryRecord>& styleRuns) = 0;
239
240 public:
241 /*
242 @METHOD: StyledTextIOReader::SinkStream::GetDefaultFontSpec
243 @DESCRIPTION:
244 */
245 virtual FontSpecification GetDefaultFontSpec () const = 0;
246
247#if qStroika_Frameworks_Led_SupportGDI
248 public:
249 /*
250 @METHOD: StyledTextIOReader::SinkStream::InsertEmbeddingForExistingSentinel
251 @DESCRIPTION:
252 */
253 virtual void InsertEmbeddingForExistingSentinel (SimpleEmbeddedObjectStyleMarker* embedding, size_t at) = 0;
254
255 public:
256 /*
257 @METHOD: StyledTextIOReader::SinkStream::AppendEmbedding
258 @DESCRIPTION:
259 */
260 virtual void AppendEmbedding (SimpleEmbeddedObjectStyleMarker* embedding) = 0;
261#endif
262
263 public:
264 /*
265 @METHOD: StyledTextIOReader::SinkStream::AppendSoftLineBreak
266 @DESCRIPTION:
267 */
268 virtual void AppendSoftLineBreak () = 0;
269
270 public:
271 virtual void StartTable ();
272 virtual void EndTable ();
273 virtual void StartTableRow ();
274 virtual void EndTableRow ();
275 virtual void StartTableCell (size_t colSpan);
276 virtual void EndTableCell ();
277
278 public:
279 /*
280 @METHOD: StyledTextIOReader::SinkStream::InsertMarker
281 @DESCRIPTION:
282 */
283 virtual void InsertMarker (Marker* m, size_t at, size_t length, MarkerOwner* markerOwner) = 0;
284
285 public:
286 virtual void SetJustification (Justification justification);
287 virtual void SetStandardTabStopList (const StandardTabStopList& tabStops);
288 virtual void SetFirstIndent (TWIPS tx);
289 virtual void SetLeftMargin (TWIPS lhs);
290 virtual void SetRightMargin (TWIPS rhs);
291 virtual void SetSpaceBefore (TWIPS sb);
292 virtual void SetSpaceAfter (TWIPS sa);
293 virtual void SetLineSpacing (LineSpacing sl);
294 virtual void SetTextHidden (bool hidden);
295 virtual void SetListStyle (ListStyle listStyle);
296 virtual void SetListIndentLevel (unsigned char indentLevel);
297
298 public:
299 virtual void SetTableBorderColor (Color c);
300 virtual void SetTableBorderWidth (TWIPS bWidth);
301 virtual void SetCellWidths (const vector<TWIPS>& cellWidths);
302 virtual void SetCellBackColor (const Color c);
303 virtual void SetDefaultCellMarginsForCurrentRow (TWIPS top, TWIPS left, TWIPS bottom, TWIPS right);
304 virtual void SetDefaultCellSpacingForCurrentRow (TWIPS top, TWIPS left, TWIPS bottom, TWIPS right);
305
306 public:
307 /*
308 @METHOD: StyledTextIOReader::SinkStream::EndOfBuffer
309 @DESCRIPTION: <p>Called by StyledText IO readers when end of source buffer is encountered. This means that
310 the next Flush () call contains the last of the text.</p>
311 */
312 virtual void EndOfBuffer () {};
313
314 public:
315 /*
316 @METHOD: StyledTextIOReader::SinkStream::Flush
317 @DESCRIPTION:
318 */
319 virtual void Flush () = 0;
320
321 public:
322 nonvirtual size_t GetCountOfTCharsInserted () const;
323 };
324
325 /*
326 @CLASS: StyledTextIOWriter
327 @DESCRIPTION:
328 <p>Abstract base class for styled text writing. Subclasses know about various styled text file formats, and
329 take care of the details of mapping Led internal data structures with styled text into streams of bytes in that format.</p>
330 */
331 class StyledTextIOWriter {
332 public:
333 class SrcStream;
334 class SinkStream;
335
336 protected:
337 StyledTextIOWriter (SrcStream* srcStream, SinkStream* sinkStream); // callers responsability to destroy srcStream/sinkStream
338
339 // The Read() method must be overriden by one subclass to provide the format interpretation
340 public:
341 virtual void Write () = 0;
342
343 public:
344 nonvirtual SrcStream& GetSrcStream () const;
345 nonvirtual SinkStream& GetSinkStream () const;
346
347 private:
348 SrcStream* fSrcStream;
349 SinkStream* fSinkStream;
350
351 // Utilities
352 protected:
353 nonvirtual void write (const void* data, size_t nBytes);
354 nonvirtual void write (char c);
355 nonvirtual void write (const char* str);
356 nonvirtual void write (const string& str);
357 };
358
359 /*
360 @CLASS: StyledTextIOWriter::SrcStream
361 @DESCRIPTION: <p>Abstract base class for @'StyledTextIOWriter's to get their text content from.</p>
362 */
363 class StyledTextIOWriter::SrcStream {
364 public:
365 virtual ~SrcStream () = default;
366
367 public:
368 /*
369 @METHOD: StyledTextIOWriter::SrcStream::readNTChars
370 @DESCRIPTION: <p>readNTChars can retun less than maxTChars before end of buffer, only to make us end on even
371 mbyte char boundary.</p>
372 */
373 virtual size_t readNTChars (Led_tChar* intoBuf, size_t maxTChars) = 0;
374
375 public:
376 /*
377 @METHOD: StyledTextIOWriter::SrcStream::current_offset
378 @DESCRIPTION: <p>current seekPos</p>
379 */
380 virtual size_t current_offset () const = 0;
381
382 public:
383 /*
384 @METHOD: StyledTextIOWriter::SrcStream::seek_to
385 @DESCRIPTION: <p>'to' past end just pins one past end of buffer</p>
386 */
387 virtual void seek_to (size_t to) = 0;
388
389 public:
390 /*
391 @METHOD: StyledTextIOWriter::SrcStream::GetTotalTextLength
392 @DESCRIPTION: <p>Total # of tChars</p>
393 */
394 virtual size_t GetTotalTextLength () const = 0;
395
396 public:
397 /*
398 @METHOD: StyledTextIOWriter::SrcStream::GetStyleInfo
399 @DESCRIPTION:
400 */
401 virtual vector<StyledInfoSummaryRecord> GetStyleInfo (size_t from, size_t len) const = 0;
402
403#if qStroika_Frameworks_Led_SupportGDI
404 public:
405 /*
406 @METHOD: StyledTextIOWriter::SrcStream::CollectAllEmbeddingMarkersInRange
407 @DESCRIPTION:
408 */
409 virtual vector<SimpleEmbeddedObjectStyleMarker*> CollectAllEmbeddingMarkersInRange (size_t from, size_t to) const = 0;
410#endif
411
412 public:
413 class Table;
414
415 /*
416 @METHOD: StyledTextIOWriter::SrcStream::GetTableAt
417 @DESCRIPTION: Return a @'StyledTextIOWriter::SrcStream::Table' object. Note - this is not to be
418 confused with a @'WordProcessor::Table' object. Though they are closely related, this object
419 contains just the API required for writing tables to files.
420 */
421 virtual Table* GetTableAt (size_t at) const = 0;
422
423 public:
424 /*
425 @METHOD: StyledTextIOWriter::SrcStream::SummarizeFontAndColorTable
426 @DESCRIPTION: <p>Produce a list of all fontnames and colors used in the document. This is needed for some formats
427 like RTF which require a list of all font names and colors before writing any of the rest of the document.</p>
428 */
429 virtual void SummarizeFontAndColorTable (set<SDKString>* fontNames, set<Color>* colorsUsed) const = 0;
430
431 public:
432 /*
433 @METHOD: StyledTextIOWriter::SrcStream::GetEmbeddingMarkerPosOffset
434 @DESCRIPTION: <p>Since we maybe externalizing a subset of the buffer, and the marker positions in the embedding object
435 are absolute, we need to know this to relativize them in the externalized stream</p>
436 */
437 virtual size_t GetEmbeddingMarkerPosOffset () const = 0;
438
439 public:
440 virtual Justification GetJustification () const;
441 virtual StandardTabStopList GetStandardTabStopList () const;
442 virtual TWIPS GetFirstIndent () const;
443 virtual void GetMargins (TWIPS* lhs, TWIPS* rhs) const;
444 virtual TWIPS GetSpaceBefore () const;
445 virtual TWIPS GetSpaceAfter () const;
446 virtual LineSpacing GetLineSpacing () const;
447 virtual void GetListStyleInfo (ListStyle* listStyle, unsigned char* indentLevel) const;
448 virtual Led_tChar GetSoftLineBreakCharacter () const;
449 virtual DiscontiguousRun<bool> GetHidableTextRuns () const;
450 };
451
452 /*
453 @CLASS: StyledTextIOWriter::SrcStream::Table
454 @DESCRIPTION: <p>Simple abstract API so styled text IO code can ask key questions about a table object in order to persist it..</p>
455 */
456 class StyledTextIOWriter::SrcStream::Table {
457 public:
458 virtual ~Table () = default;
459
460 public:
461 struct CellInfo {
462 CellInfo ();
463 TWIPS f_cellx;
464 Color f_clcbpat; // cell background color
465 };
466
467 public:
468 /*
469 @METHOD: StyledTextIOWriter::SrcStream::Table::GetRows
470 @DESCRIPTION: <p>Get the number of rows in the given table.</p>
471 */
472 virtual size_t GetRows () const = 0;
473 /*
474 @METHOD: StyledTextIOWriter::SrcStream::Table::GetColumns
475 @DESCRIPTION: <p>Get the number of columns in the given row. Note that this can be
476 different from row to row within a given table.</p>
477 */
478 virtual size_t GetColumns (size_t row) const = 0;
479 /*
480 @METHOD: StyledTextIOWriter::SrcStream::Table::GetRowInfo
481 @DESCRIPTION: <p>Get the @'StyledTextIOWriter::SrcStream::Table::CellInfo's for the given
482 row. The number of these records is the same as the return value from
483 @'StyledTextIOWriter::SrcStream::Table::GetColumns'.
484 </p>
485 */
486 virtual void GetRowInfo (size_t row, vector<CellInfo>* cellInfos) = 0;
487 /*
488 @METHOD: StyledTextIOWriter::SrcStream::Table::MakeCellSubSrcStream
489 @DESCRIPTION: <p>Returns a @'StyledTextIOWriter::SrcStream' containing the data for the given table cell.
490 Note that this can return nullptr for 'merged' cells.</p>
491 */
492 virtual StyledTextIOWriter::SrcStream* MakeCellSubSrcStream (size_t row, size_t column) = 0;
493 /*
494 @METHOD: StyledTextIOWriter::SrcStream::Table::GetOffsetEnd
495 @DESCRIPTION: <p>Returns the source-doc offset of the given table end relative to its start. Readers should
496 skip ahead that many positions after writing the tables contents.</p>
497 */
498 virtual size_t GetOffsetEnd () const = 0;
499 /*
500 @METHOD: StyledTextIOWriter::SrcStream::Table::GetDefaultCellMarginsForRow
501 @DESCRIPTION: <p>Return the default cell margins for the given row. Note that the @'TWIPS_Rect'
502 is not a true rectangle, but just a handy way to return 4 values - a top/left/bottom/right.</p>
503 */
504 virtual TWIPS_Rect GetDefaultCellMarginsForRow (size_t row) const = 0;
505 /*
506 @METHOD: StyledTextIOWriter::SrcStream::Table::GetDefaultCellSpacingForRow
507 @DESCRIPTION: <p>Return the default cell spacing for the given row. Note that the @'TWIPS_Rect'
508 is not a true rectangle, but just a handy way to return 4 values - a top/left/bottom/right.</p>
509 */
510 virtual TWIPS_Rect GetDefaultCellSpacingForRow (size_t row) const = 0;
511 };
512
513 /*
514 <p>Abstract base class for @'StyledTextIOWriter's to dump their text content to.</p>
515
516 \@todo THIS IS OBSOLETE - and should be switched to using Streams::OutputStream<byte> --LGP 2024-02-22
517 */
518 class StyledTextIOWriter::SinkStream {
519 public:
520 virtual ~SinkStream ()
521 {
522 }
523
524 public:
525 /*
526 @METHOD: StyledTextIOWriter::SinkStream::current_offset
527 @DESCRIPTION: <p>Return the current seekPos.</p>
528 */
529 virtual size_t current_offset () const = 0;
530
531 public:
532 /*
533 @METHOD: StyledTextIOWriter::SinkStream::seek_to
534 @DESCRIPTION: <p>'to' past end just pins one past end of buffer</p>
535 */
536 virtual void seek_to (size_t to) = 0;
537
538 public:
539 /*
540 @METHOD: StyledTextIOWriter::SinkStream::write
541 @DESCRIPTION:
542 */
543 virtual void write (const void* buffer, size_t bytes) = 0;
544 };
545
546 /*
547 ********* Some StyledTextIOReader::SrcStream subclasses *********
548 */
549 /*
550 @CLASS: StyledTextIOSrcStream_Memory
551 @BASES: @'StyledTextIOReader::SrcStream'
552 @DESCRIPTION: <p>If you have a block of memory which contains the untyped contents which will be converted by some
553 reader (@'StyledTextIOReader'), you use this as the @'StyledTextIOReader::SrcStream'. Just initialize one of these
554 with the appropriate data, and pass this to the appropriate @'StyledTextIOReader'.</p>
555 <p>NB: This class doesn't free up, or copy the given pointer. It is up the the caller todo that, and only after
556 this SrcStream object has been destroyed. Typically, this follows trivially from a sequential, stack-based allocation
557 strategy, where the data comes from some object declared earlier on the stack.</p>
558 */
559 class StyledTextIOSrcStream_Memory : public StyledTextIOReader::SrcStream {
560 public:
561 StyledTextIOSrcStream_Memory (const void* data, size_t nBytes);
562
563 public:
564 virtual size_t current_offset () const override;
565 virtual void seek_to (size_t to) override;
566 virtual size_t read (void* buffer, size_t bytes) override;
567 virtual size_t read1 (char* c) override;
568
569 private:
570 const void* fData;
571 const void* fDataEnd;
572 size_t fBytesInBuffer;
573 const void* fCurPtr;
574 };
575
576 inline StyledTextIOReader::BufferedIndirectSrcStream::BufferedIndirectSrcStream (SrcStream& realSrcStream)
577 : fRealSrcStream (realSrcStream)
578 ,
579 //fWindowTop_Data (),
580 fWindowTop_Offset (size_t (-1))
581 , fWindowBottom_Data (nullptr)
582 , fWindowBottom_Offset (size_t (-1))
583 , fCursor_Data (nullptr)
584 , fCursor_Offset (0)
585 {
586 }
587 inline void StyledTextIOReader::BufferedIndirectSrcStream::FillCache ()
588 {
589 fWindowTop_Offset = fCursor_Offset;
590 fRealSrcStream.seek_to (fWindowTop_Offset); // probably could frequently optimize this call way if we were careful to cache last seek-offset from buffer
591 size_t bytesRead = fRealSrcStream.read (fWindowTop_Data, std::size (fWindowTop_Data));
592 fWindowBottom_Data = fWindowTop_Data + bytesRead;
593 fWindowBottom_Offset = fWindowTop_Offset + bytesRead;
594 Assert (fCursor_Offset >= fWindowTop_Offset and fCursor_Offset <= fWindowBottom_Offset); // should only call FillCache in that case?
595 Assert (fCursor_Offset == fWindowTop_Offset); // should only call FillCache in that case?
596 if (fCursor_Offset >= fWindowTop_Offset and fCursor_Offset <= fWindowBottom_Offset) {
597 fCursor_Data = fWindowTop_Data + (fCursor_Offset - fWindowTop_Offset);
598 }
599 Ensure (fWindowTop_Data <= fCursor_Data and fCursor_Data <= fWindowBottom_Data);
600 Ensure (fWindowTop_Offset <= fCursor_Offset and fCursor_Offset <= fWindowBottom_Offset);
601 }
602 inline size_t StyledTextIOReader::BufferedIndirectSrcStream::current_offset () const
603 {
604 return fCursor_Offset;
605 }
606 inline void StyledTextIOReader::BufferedIndirectSrcStream::seek_to (size_t to)
607 {
608 // If seekpos inside our window (at end of buffer counts as inside window even though next read may force a FillCache),
609 // just update offset(s), and otherwise - mark fCursor_Data as nullptr so we know cache invalid
610 if (fWindowTop_Offset <= to and to <= fWindowBottom_Offset) {
611 fCursor_Data = fWindowTop_Data + (to - fWindowTop_Offset);
612 }
613 else {
614 fCursor_Data = nullptr;
615 }
616 fCursor_Offset = to;
617 }
618 inline size_t StyledTextIOReader::BufferedIndirectSrcStream::read (void* buffer, size_t bytes)
619 {
620 RequireNotNull (buffer);
621
622 byte* destCursor = reinterpret_cast<byte*> (buffer);
623 size_t bytesReadSoFar = 0;
624
625 /*
626 * See if the initial part of this request can be satisfied by our current buffered data
627 * and updated 'bytesReadSoFar' to reflect how much read from that buffer.
628 */
629 if (fCursor_Data != nullptr and fWindowTop_Offset >= fCursor_Offset and fCursor_Offset < fWindowBottom_Offset) {
630 size_t bytesAvail = fWindowBottom_Offset - fCursor_Offset; // must be > 0 UNLESS we are at EOF
631 size_t thisReadCount = min (bytesAvail, bytes);
632 AssertNotNull (fCursor_Data);
633 (void)::memcpy (destCursor, fCursor_Data, thisReadCount);
634 destCursor += thisReadCount;
635 fCursor_Data += thisReadCount;
636 fCursor_Offset += thisReadCount;
637 bytesReadSoFar += thisReadCount;
638 }
639
640 /*
641 * If we've not completed the request, see if it can be accomodated by by filling the buffer,
642 * and trying to pull data out of that buffer. If not - then simply read the data directly.
643 */
644 if (bytesReadSoFar < bytes) {
645 size_t bytesLeftToRead = bytes - bytesReadSoFar;
646 if (bytesLeftToRead < std::size (fWindowTop_Data)) {
647 FillCache ();
648 size_t bytesAvail = fWindowBottom_Offset - fCursor_Offset; // must be > 0 UNLESS we are at EOF
649 size_t thisReadCount = min (bytesAvail, bytesLeftToRead);
650 AssertNotNull (fCursor_Data);
651 DISABLE_COMPILER_MSC_WARNING_START (6387) // fCursor_Data is not null because of assertion above
652 (void)::memcpy (destCursor, fCursor_Data, thisReadCount);
653 DISABLE_COMPILER_MSC_WARNING_END (6387)
654 destCursor += thisReadCount;
655 fCursor_Data += thisReadCount;
656 fCursor_Offset += thisReadCount;
657 bytesReadSoFar += thisReadCount;
658 }
659 else {
660 fRealSrcStream.seek_to (fCursor_Offset);
661 size_t bytesRead = fRealSrcStream.read (destCursor, bytesLeftToRead);
662 bytesReadSoFar += bytesRead;
663 fCursor_Offset += bytesRead;
664 // Cache is invalid - so mark it so...
665 fCursor_Data = nullptr;
666 }
667 }
668 return bytesReadSoFar;
669 }
670 inline size_t StyledTextIOReader::BufferedIndirectSrcStream::read1 (char* c)
671 {
672 RequireNotNull (c);
673 /*
674 * See if we can read ANY non-zero number of bytes out of our window. If yes - then just
675 * return those (even if thats less than the user requested - following standard UNIX read
676 * conventions). If we cannot read any bytes given our current window, refill the window, and
677 * try again.
678 */
679 if ((fCursor_Data == nullptr) or (fCursor_Offset < fWindowTop_Offset or fCursor_Offset >= fWindowBottom_Offset)) {
680 FillCache ();
681 }
682 Assert (fWindowTop_Offset <= fCursor_Offset and fCursor_Offset <= fWindowBottom_Offset);
683 if (fWindowBottom_Offset == fCursor_Offset) {
684 return 0;
685 }
686 else {
687 AssertNotNull (fCursor_Data);
688 *c = *fCursor_Data;
689 ++fCursor_Data;
690 ++fCursor_Offset;
691 return 1;
692 }
693 }
694
695 /*
696 ********* Some StyledTextIOReader::SrcStream subclasses *********
697 */
698 /*
699 @CLASS: StyledTextIOWriterSinkStream_Memory
700 @BASES: @'StyledTextIOWriter::SinkStream'
701 @DESCRIPTION:
702 */
703 class StyledTextIOWriterSinkStream_Memory : public StyledTextIOWriter::SinkStream {
704 public:
705 StyledTextIOWriterSinkStream_Memory ();
706 ~StyledTextIOWriterSinkStream_Memory ();
707
708 private: // prevent accidental copying
709 StyledTextIOWriterSinkStream_Memory (const StyledTextIOWriterSinkStream_Memory&) = delete;
710 void operator= (const StyledTextIOWriterSinkStream_Memory&) = delete;
711
712 public:
713 virtual size_t current_offset () const override;
714 virtual void seek_to (size_t to) override;
715 virtual void write (const void* buffer, size_t bytes) override;
716
717 nonvirtual const void* PeekAtData () const;
718 nonvirtual size_t GetLength () const;
719
720 private:
721 char* fData;
722 size_t fBytesUsed;
723 size_t fBytesAllocated;
724 char* fCurPtr;
725 };
726
727#if qStroika_Frameworks_Led_SupportGDI
728 /*
729 @CLASS: EmbeddingSinkStream
730 @BASES: @'SimpleEmbeddedObjectStyleMarker::SinkStream'
731 @DESCRIPTION:
732 */
733 class EmbeddingSinkStream : public SimpleEmbeddedObjectStyleMarker::SinkStream {
734 public:
735 EmbeddingSinkStream (StyledTextIOWriter::SinkStream& realSinkStream);
736
737 virtual void write (const void* buffer, size_t bytes) override;
738
739 private:
740 StyledTextIOWriter::SinkStream& fRealSinkStream;
741 };
742#endif
743
744 /*
745 ********************************************************************************
746 ***************************** Implementation Details ***************************
747 ********************************************************************************
748 */
749 // class StyledTextIOReader::SrcStreamSeekSaver
750 inline StyledTextIOReader::SrcStreamSeekSaver::SrcStreamSeekSaver (SrcStream& srcStream)
751 : fSrcStream (srcStream)
752 , fSavedPos (srcStream.current_offset ())
753 {
754 }
755 inline StyledTextIOReader::SrcStreamSeekSaver::~SrcStreamSeekSaver ()
756 {
757 try {
758 fSrcStream.seek_to (fSavedPos);
759 }
760 catch (...) {
761 // ignore errors here cuz throwing out of DTORs appears to cause havoc with
762 // MWERKS runtime?? Is it a MWERKS bug? Or mine - or has this been fixed?
763 // LGP 960906
764 }
765 }
766
767 // class StyledTextIOReader
768 inline StyledTextIOReader::StyledTextIOReader (SrcStream* srcStream, SinkStream* sinkStream, const shared_ptr<BadInputHandler>& badInputHander)
769 : fSrcStream (*srcStream)
770 , fSinkStream (sinkStream)
771 , fBadInputHandler (badInputHander)
772 {
773 RequireNotNull (srcStream);
774 if (fBadInputHandler.get () == nullptr) {
775 fBadInputHandler = Memory::MakeSharedPtr<BadInputHandler> ();
776 }
777 }
778 inline StyledTextIOReader::SrcStream& StyledTextIOReader::GetSrcStream () const
779 {
780 return fSrcStream;
781 }
782 inline StyledTextIOReader::SinkStream& StyledTextIOReader::GetSinkStream () const
783 {
784 EnsureNotNull (fSinkStream);
785 return *fSinkStream;
786 }
787 /*
788 @METHOD: StyledTextIOReader::GetBadInputHandler
789 @DESCRIPTION: <p>Each reader class has associated with it an error handler - of type @'StyledTextIOReader::BadInputHandler'. This is used
790 to handle syntactic or logical errors in the input. By default - this class is simple
791 @'StyledTextIOReader::BadInputHandler'.</p>
792 <p>See also @'StyledTextIOReader::SetBadInputHandler' and @'StyledTextIOReader::HandleBadlyFormattedInput'.</p>
793 */
794 inline shared_ptr<StyledTextIOReader::BadInputHandler> StyledTextIOReader::GetBadInputHandler () const
795 {
796 Ensure (fBadInputHandler.get () != nullptr);
797 return fBadInputHandler;
798 }
799 /*
800 @METHOD: StyledTextIOReader::SetBadInputHandler
801 @DESCRIPTION: <p>See @'StyledTextIOReader::GetBadInputHandler'</p>
802 */
803 inline void StyledTextIOReader::SetBadInputHandler (const shared_ptr<BadInputHandler>& badInputHandler)
804 {
805 fBadInputHandler = badInputHandler;
806 if (fBadInputHandler == nullptr) {
807 fBadInputHandler = Memory::MakeSharedPtr<BadInputHandler> ();
808 }
809 }
810 /*
811 @METHOD: StyledTextIOReader::HandleBadlyFormattedInput
812 @DESCRIPTION: <p>This routine is called whenever this is badly formatted input text to the reader.
813 This is a simple wrapper on the owned @'StyledTextIOReader::BadInputHandler', which can be gotten/set with
814 @'StyledTextIOReader::GetBadInputHandler' / @'StyledTextIOReader::SetBadInputHandler'</p>
815 */
816 inline void StyledTextIOReader::HandleBadlyFormattedInput (bool unrecoverable) const
817 {
818 GetBadInputHandler ()->HandleBadlyFormattedInput (*this, unrecoverable);
819 }
820 /*
821 @METHOD: StyledTextIOReader::PutBackLastChar
822 @DESCRIPTION: <p>Unread the last read character. Note - this can be done as many times as you want (allowing infinite unread)
823 but it is a bug/error if you ever unread characters that handn't been read in the first place</p>
824 */
825 inline void StyledTextIOReader::PutBackLastChar () const
826 {
827 Require (fSrcStream.current_offset () > 0);
828 fSrcStream.seek_to (fSrcStream.current_offset () - 1);
829 }
830 inline char StyledTextIOReader::GetNextChar () const
831 {
832 //char c = '\0';
833 char c; // Better to leave uninitialized for performance reasons - LGP 2003-03-17
834 if (fSrcStream.read1 (&c) == 1) {
835 return c;
836 }
837 else {
838 throw ReadEOFException ();
839 Assert (false);
840 return 0; // NOT REACHED
841 }
842 }
843 inline char StyledTextIOReader::PeekNextChar () const
844 {
845 //char c = '\0';
846 char c; // Better to leave uninitialized for performance reasons - LGP 2003-03-17
847 if (fSrcStream.read1 (&c) == 1) {
848 PutBackLastChar ();
849 return c;
850 }
851 else {
852 throw ReadEOFException ();
854 return 0; // NOT REACHED
855 }
856 }
857 inline void StyledTextIOReader::ConsumeNextChar () const
858 {
859 (void)GetNextChar ();
860 }
861
862 // class StyledTextIOWriter
863 inline StyledTextIOWriter::StyledTextIOWriter (SrcStream* srcStream, SinkStream* sinkStream)
864 : fSrcStream (srcStream)
865 , fSinkStream (sinkStream)
866 {
867 RequireNotNull (srcStream);
868 RequireNotNull (sinkStream);
869 }
870 inline StyledTextIOWriter::SrcStream& StyledTextIOWriter::GetSrcStream () const
871 {
872 EnsureNotNull (fSrcStream);
873 return *fSrcStream;
874 }
875 inline StyledTextIOWriter::SinkStream& StyledTextIOWriter::GetSinkStream () const
876 {
877 EnsureNotNull (fSinkStream);
878 return *fSinkStream;
879 }
880
881 // class StyledTextIOReader::SinkStream
882 /*
883 @METHOD: StyledTextIOReader::SinkStream::GetCountOfTCharsInserted
884 @DESCRIPTION:
885 */
886 inline size_t StyledTextIOReader::SinkStream::GetCountOfTCharsInserted () const
887 {
888 return current_offset ();
889 }
890
891 // class StyledTextIOWriter::SrcStream::Table::CellInfo
892 inline StyledTextIOWriter::SrcStream::Table::CellInfo::CellInfo ()
893 : f_cellx (TWIPS (0))
894 , f_clcbpat (Color::kWhite)
895 {
896 }
897
898 // class StyledTextIOWriterSinkStream_Memory
899 inline const void* StyledTextIOWriterSinkStream_Memory::PeekAtData () const
900 {
901 return fData;
902 }
903 inline size_t StyledTextIOWriterSinkStream_Memory::GetLength () const
904 {
905 return fBytesUsed;
906 }
907
908}
909
910#endif /*_Stroika_Frameworks_Led_StyledTextIO_h_*/
#define AssertNotNull(p)
Definition Assertions.h:333
#define EnsureNotNull(p)
Definition Assertions.h:340
#define RequireNotNull(p)
Definition Assertions.h:347
#define AssertNotReached()
Definition Assertions.h:355