Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
StyledTextIO.cpp
1/*/
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
6#include <bitset>
7#include <cctype>
8#include <climits>
9#include <cstdio> // for a couple sprintf() calls - could pretty easily be avoided
10
11#include "Stroika/Foundation/DataExchange/BadFormatException.h"
13#include "Stroika/Frameworks/Led/StyledTextEmbeddedObjects.h"
14#include "Stroika/Frameworks/Led/StyledTextImager.h"
15
16#include "StyledTextIO.h"
17
18using namespace Stroika::Foundation;
19using namespace Stroika::Frameworks;
20using namespace Stroika::Frameworks::Led;
21using namespace Stroika::Frameworks::Led::StyledTextIO;
22
23/*
24 ********************************************************************************
25 ************************ StyledTextIOReader::SinkStream ************************
26 ********************************************************************************
27 */
28
29/*
30@METHOD: StyledTextIOReader::SinkStream::StartTable
31@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
32*/
33void StyledTextIOReader::SinkStream::StartTable ()
34{
35}
36
37/*
38@METHOD: StyledTextIOReader::SinkStream::EndTable
39@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
40*/
41void StyledTextIOReader::SinkStream::EndTable ()
42{
43}
44
45/*
46@METHOD: StyledTextIOReader::SinkStream::StartTableRow
47@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
48*/
49void StyledTextIOReader::SinkStream::StartTableRow ()
50{
51}
52
53/*
54@METHOD: StyledTextIOReader::SinkStream::EndTableRow
55@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
56*/
57void StyledTextIOReader::SinkStream::EndTableRow ()
58{
59}
60
61/*
62@METHOD: StyledTextIOReader::SinkStream::StartTableCell
63@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
64 <p>Note about how this API handles <em>merged cells</em> (merge cells).
65 If two or more cells in a row are to be merged together - then the FileIO code that reads
66 them will generate a SINGLE StartTableCell/EndTableCell pair, passing the number of horizontally merged cells
67 as an argument to StartTableCell ('colSpan'). The total number of StartTableCell/EndTableCell
68 calls should correspond to the length of the
69 @'StyledTextIOReader::SinkStream::SetCellWidths' argument.
70 </p>
71*/
72void StyledTextIOReader::SinkStream::StartTableCell (size_t /*colSpan*/)
73{
74}
75
76/*
77@METHOD: StyledTextIOReader::SinkStream::EndTableCell
78@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
79*/
80void StyledTextIOReader::SinkStream::EndTableCell ()
81{
82}
83
84void StyledTextIOReader::SinkStream::SetJustification (Justification /*justification*/)
85{
86 // OVERRIDE, and ignore, since that feature isn't supported by this class
87}
88
89void StyledTextIOReader::SinkStream::SetStandardTabStopList (const StandardTabStopList& /*tabStops*/)
90{
91 // OVERRIDE, and ignore, since that feature isn't supported by this class
92}
93
94void StyledTextIOReader::SinkStream::SetFirstIndent (TWIPS /*tx*/)
95{
96 // OVERRIDE, and ignore, since that feature isn't supported by this class
97}
98
99void StyledTextIOReader::SinkStream::SetLeftMargin (TWIPS /*lhs*/)
100{
101 // OVERRIDE, and ignore, since that feature isn't supported by this class
102}
103
104void StyledTextIOReader::SinkStream::SetRightMargin (TWIPS /*rhs*/)
105{
106 // OVERRIDE, and ignore, since that feature isn't supported by this class
107}
108
109/*
110@METHOD: StyledTextIOReader::SinkStream::SetSpaceBefore
111@DESCRIPTION:
112*/
113void StyledTextIOReader::SinkStream::SetSpaceBefore (TWIPS /*sb*/)
114{
115 // OVERRIDE, and ignore, since that feature isn't supported by this class
116}
117
118/*
119@METHOD: StyledTextIOReader::SinkStream::SetSpaceAfter
120@DESCRIPTION:
121*/
122void StyledTextIOReader::SinkStream::SetSpaceAfter (TWIPS /*sa*/)
123{
124 // OVERRIDE, and ignore, since that feature isn't supported by this class
125}
126
127/*
128@METHOD: StyledTextIOReader::SinkStream::SetLineSpacing
129@DESCRIPTION:
130*/
131void StyledTextIOReader::SinkStream::SetLineSpacing (LineSpacing /*sl*/)
132{
133 // OVERRIDE, and ignore, since that feature isn't supported by this class
134}
135
136/*
137@METHOD: StyledTextIOReader::SinkStream::SetTextHidden
138@DESCRIPTION:
139*/
140void StyledTextIOReader::SinkStream::SetTextHidden (bool /*hidden*/)
141{
142 // OVERRIDE, and ignore, since that feature isn't supported by this class
143}
144
145/*
146@METHOD: StyledTextIOReader::SinkStream::SetListStyle
147@DESCRIPTION:
148*/
149void StyledTextIOReader::SinkStream::SetListStyle (ListStyle /*listStyle*/)
150{
151 // OVERRIDE, and ignore, since that feature isn't supported by this class
152}
153
154/*
155@METHOD: StyledTextIOReader::SinkStream::SetListIndentLevel
156@DESCRIPTION:
157*/
158void StyledTextIOReader::SinkStream::SetListIndentLevel (unsigned char /*indentLevel*/)
159{
160 // OVERRIDE, and ignore, since that feature isn't supported by this class
161}
162
163/*
164@METHOD: StyledTextIOReader::SinkStream::SetTableBorderColor
165@DESCRIPTION:
166*/
167void StyledTextIOReader::SinkStream::SetTableBorderColor (Color /*c*/)
168{
169 // OVERRIDE, and ignore, since that feature isn't supported by this class
170}
171
172/*
173@METHOD: StyledTextIOReader::SinkStream::SetTableBorderWidth
174@DESCRIPTION:
175*/
176void StyledTextIOReader::SinkStream::SetTableBorderWidth (TWIPS /*bWidth*/)
177{
178 // OVERRIDE, and ignore, since that feature isn't supported by this class
179}
180
181/*
182@METHOD: StyledTextIOReader::SinkStream::SetCellWidths
183@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
184 <p>Note that this must be called after @'StyledTextIOReader::SinkStream::StartTableRow' and before
185 and calls to @'StyledTextIOReader::SinkStream::StartTableCell'. The number and widths here must correspond to the
186 number of @'StyledTextIOReader::SinkStream::StartTableCell'/@'StyledTextIOReader::SinkStream::EndTableCell' pairs
187 of calls for the row. The number of actual
188 cells in the table created could be larger (due to implied cell merges from the
189 @'StyledTextIOReader::SinkStream::StartTableCell' call).
190 </p>
191*/
192void StyledTextIOReader::SinkStream::SetCellWidths (const vector<TWIPS>& /*cellWidths*/)
193{
194 // OVERRIDE, and ignore, since that feature isn't supported by this class
195}
196
197/*
198@METHOD: StyledTextIOReader::SinkStream::SetCellBackColor
199@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
200*/
201void StyledTextIOReader::SinkStream::SetCellBackColor (const Color /*c*/)
202{
203 // OVERRIDE, and ignore, since that feature isn't supported by this class
204}
205
206/*
207@METHOD: StyledTextIOReader::SinkStream::SetDefaultCellMarginsForCurrentRow
208@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
209*/
210void StyledTextIOReader::SinkStream::SetDefaultCellMarginsForCurrentRow (TWIPS /*top*/, TWIPS /*left*/, TWIPS /*bottom*/, TWIPS /*right*/)
211{
212 // OVERRIDE, and ignore, since that feature isn't supported by this class
213}
214
215/*
216@METHOD: StyledTextIOReader::SinkStream::SetDefaultCellSpacingForCurrentRow
217@DESCRIPTION: <p>Default is to do ignore. Override to implement tables.</p>
218*/
219void StyledTextIOReader::SinkStream::SetDefaultCellSpacingForCurrentRow (TWIPS /*top*/, TWIPS /*left*/, TWIPS /*bottom*/, TWIPS /*right*/)
220{
221 // OVERRIDE, and ignore, since that feature isn't supported by this class
222}
223
224/*
225 ********************************************************************************
226 ********************* StyledTextIOReader::BadInputHandler **********************
227 ********************************************************************************
228 */
229
230/*
231@METHOD: StyledTextIOReader::BadInputHandler::HandleBadlyFormattedInput
232@DESCRIPTION: <p>This routine is called whenever this is badly formatted input text to the reader.
233 By default - this routine does nothing (unless the unrecoverable argument is 'true').</p>
234 <p>This is a change of behavior from Led 2.3. In Led 2.3 - format errors would always throw
235 by calling @'Led_ThrowBadFormatDataException'. Instead - this method now calls this virtual method of @'StyledTextIOReader::BadInputHandler' - which your
236 subclass can OVERRIDE to throw @'Led_ThrowBadFormatDataException' - if thats the behavior you want. You can replace the error handler associated with
237 a particular @'StyledTextIOReader' by calling @'StyledTextIOReader::SetBadInputHandler'.</p>
238*/
239void StyledTextIOReader::BadInputHandler::HandleBadlyFormattedInput (const StyledTextIOReader& /*reader*/, bool unrecoverable)
240{
241 if (unrecoverable) {
242 Execution::Throw (DataExchange::BadFormatException::kThe);
243 }
244}
245
246/*
247 ********************************************************************************
248 *************************** StyledTextIOWriter::SrcStream **********************
249 ********************************************************************************
250 */
251
252/*
253@METHOD: StyledTextIOWriter::SrcStream::GetJustification
254@DESCRIPTION:
255*/
256Justification StyledTextIOWriter::SrcStream::GetJustification () const
257{
258 return eLeftJustify;
259}
260
261/*
262@METHOD: StyledTextIOWriter::SrcStream::GetStandardTabStopList
263@DESCRIPTION:
264*/
265StandardTabStopList StyledTextIOWriter::SrcStream::GetStandardTabStopList () const
266{
267 return StandardTabStopList{};
268}
269
270/*
271@METHOD: StyledTextIOWriter::SrcStream::GetFirstIndent
272@DESCRIPTION:
273*/
274TWIPS StyledTextIOWriter::SrcStream::GetFirstIndent () const
275{
276 return TWIPS{0};
277}
278
279/*
280@METHOD: StyledTextIOWriter::SrcStream::GetMargins
281@DESCRIPTION:
282*/
283void StyledTextIOWriter::SrcStream::GetMargins (TWIPS* lhs, TWIPS* rhs) const
284{
285 RequireNotNull (lhs);
286 RequireNotNull (rhs);
287 *lhs = TWIPS{0};
288 *rhs = TWIPS (6 * 1440); // Not sure what I should return here??? maybe special case and not write anything to output file if returns zero? LGP-990221
289}
290
291/*
292@METHOD: StyledTextIOWriter::SrcStream::GetSpaceBefore
293@DESCRIPTION:
294*/
295TWIPS StyledTextIOWriter::SrcStream::GetSpaceBefore () const
296{
297 return TWIPS{0};
298}
299
300/*
301@METHOD: StyledTextIOWriter::SrcStream::GetSpaceAfter
302@DESCRIPTION:
303*/
304TWIPS StyledTextIOWriter::SrcStream::GetSpaceAfter () const
305{
306 return TWIPS{0};
307}
308
309/*
310@METHOD: StyledTextIOWriter::SrcStream::GetLineSpacing
311@DESCRIPTION:
312*/
313LineSpacing StyledTextIOWriter::SrcStream::GetLineSpacing () const
314{
315 return LineSpacing ();
316}
317
318/*
319@METHOD: StyledTextIOWriter::SrcStream::GetListStyleInfo
320@DESCRIPTION:
321*/
322void StyledTextIOWriter::SrcStream::GetListStyleInfo (ListStyle* listStyle, unsigned char* indentLevel) const
323{
324 RequireNotNull (listStyle);
325 RequireNotNull (indentLevel);
326 *listStyle = eListStyle_None;
327 *indentLevel = 0;
328}
329
330/*
331@METHOD: StyledTextIOWriter::SrcStream::GetSoftLineBreakCharacter
332@DESCRIPTION: <p>Returns the special character which should be treated (in RTF output) as the SOFT-RETURN line
333 break character (in RTF \line).</p>
334*/
335Led_tChar StyledTextIOWriter::SrcStream::GetSoftLineBreakCharacter () const
336{
337 return 0; // bogus value - this class doesn't know about this stuff... LGP 991227
338}
339
340/*
341@METHOD: StyledTextIOWriter::SrcStream::GetHidableTextRuns
342@DESCRIPTION:
343*/
344DiscontiguousRun<bool> StyledTextIOWriter::SrcStream::GetHidableTextRuns () const
345{
346 return DiscontiguousRun<bool> ();
347}
348
349/*
350 ********************************************************************************
351 *************************** StyledTextIOSrcStream_Memory ***********************
352 ********************************************************************************
353 */
354StyledTextIOSrcStream_Memory::StyledTextIOSrcStream_Memory (const void* data, size_t nBytes)
355 : StyledTextIOReader::SrcStream ()
356 , fData (data)
357 , fDataEnd (((char*)data) + nBytes)
358 , fBytesInBuffer (nBytes)
359 , fCurPtr (data) //,
360// fBytesLeft (nBytes)
361{
362}
363
364size_t StyledTextIOSrcStream_Memory::current_offset () const
365{
366 return (((char*)fCurPtr - (char*)fData));
367}
368
369void StyledTextIOSrcStream_Memory::seek_to (size_t to)
370{
371 Require (to >= 0);
372 to = min (to, fBytesInBuffer);
373 // fBytesLeft = fBytesInBuffer - to;
374 fCurPtr = ((char*)fData) + to;
375}
376
377size_t StyledTextIOSrcStream_Memory::read (void* buffer, size_t bytes)
378{
379 RequireNotNull (buffer);
380
381#if 1
382 char* curBytePtr = (char*)fCurPtr;
383 size_t curIdx = curBytePtr - ((char*)fData);
384 size_t bytesLeft = fBytesInBuffer - curIdx;
385 bytes = min (bytesLeft, bytes);
386 (void)::memcpy (buffer, curBytePtr, bytes);
387 fCurPtr = curBytePtr + bytes;
388 return bytes;
389#else
390 bytes = min (fBytesLeft, bytes);
391 (void)::memcpy (buffer, fCurPtr, bytes);
392 fCurPtr = ((char*)fCurPtr) + bytes;
393 fBytesLeft -= bytes;
394 return bytes;
395#endif
396}
397
398size_t StyledTextIOSrcStream_Memory::read1 (char* c)
399{
400 RequireNotNull (c);
401 char* curBytePtr = (char*)fCurPtr;
402 if (curBytePtr != fDataEnd) {
403 *c = *curBytePtr;
404 fCurPtr = curBytePtr + 1;
405 return 1;
406 }
407 return 0;
408}
409
410/*
411 ********************************************************************************
412 ******************** StyledTextIOWriterSinkStream_Memory ***********************
413 ********************************************************************************
414 */
415StyledTextIOWriterSinkStream_Memory::StyledTextIOWriterSinkStream_Memory ()
416 : StyledTextIOWriter::SinkStream ()
417 , fData (nullptr)
418 , fBytesUsed (0)
419 , fBytesAllocated (0)
420 , fCurPtr (nullptr)
421{
422}
423
424StyledTextIOWriterSinkStream_Memory::~StyledTextIOWriterSinkStream_Memory ()
425{
426 delete[] fData;
427}
428
429size_t StyledTextIOWriterSinkStream_Memory::current_offset () const
430{
431 return (fCurPtr - fData);
432}
433
434void StyledTextIOWriterSinkStream_Memory::seek_to (size_t to)
435{
436 Require (to >= 0);
437 to = min (to, fBytesUsed);
438 fCurPtr = fData + to;
439}
440
441void StyledTextIOWriterSinkStream_Memory::write (const void* buffer, size_t bytes)
442{
443 const size_t kMemBlockOverhead = 40; // wild guess as to how much overhead this is in a memory request.
444 // This is helpful so that we request the largest block size possible
445 // from the underlying OS storage without any waste. If the number is wrong -
446 // things will still work - but will be less memory efficient.
447 const size_t kChunkSize = 16 * 1024; // alloc in this size chunks - at least...
448
449 RequireNotNull (buffer);
450
451 Assert (fBytesUsed <= fBytesAllocated);
452
453 /*
454 * Now, re-alloc the pointer if we need even more space...
455 */
456 size_t curOffset = fCurPtr - fData;
457 if (curOffset + bytes > fBytesAllocated) {
458 /*
459 * Avoid quadratic copying - so if size bigger than fixed amount, then increase size allocated by some
460 * factor (so N*log N entries copied).
461 */
462 size_t newSize = ((static_cast<size_t> ((fBytesAllocated + bytes) * 1.5) + kChunkSize - 1 + kMemBlockOverhead) / kChunkSize) * kChunkSize -
463 kMemBlockOverhead; // round to next larger chunksize
464 Assert (newSize > fBytesAllocated);
465 Assert (newSize >= fBytesAllocated + bytes);
466 char* buf = new char[newSize];
467 if (fData != nullptr) {
468 ::memcpy (buf, fData, fBytesUsed);
469 }
470 delete[] fData;
471 fData = buf;
472 fCurPtr = buf + curOffset;
473 fBytesAllocated = newSize;
474 }
475
476 /*
477 * Then use up what space we have left.
478 */
479 memcpy (fCurPtr, buffer, bytes);
480 buffer = ((char*)buffer) + bytes;
481 fCurPtr = ((char*)fCurPtr) + bytes;
482 fBytesUsed = max (size_t (fCurPtr - fData), fBytesUsed);
483}
484
485/*
486 ********************************************************************************
487 ***************************** StyledTextIOReader *******************************
488 ********************************************************************************
489 */
490string StyledTextIOReader::GrabString (size_t from, size_t to)
491{
492 size_t onEntrySeekPos = GetSrcStream ().current_offset ();
493
494 size_t effectiveTo = to;
495 if (effectiveTo == size_t (-1)) {
496 effectiveTo = onEntrySeekPos;
497 }
498 Require (from <= effectiveTo);
499
500 size_t strLen = effectiveTo - from;
501 Memory::StackBuffer<char> buf{Memory::eUninitialized, strLen + 1};
502 GetSrcStream ().seek_to (from);
503 if (GetSrcStream ().read (buf.data (), strLen) != strLen) {
504 GetSrcStream ().seek_to (onEntrySeekPos);
505 HandleBadlyFormattedInput (true);
506 }
507 GetSrcStream ().seek_to (onEntrySeekPos);
508 buf[strLen] = '\0';
509 return string{buf.data ()};
510}
511
512/*
513 ********************************************************************************
514 ******************************* StyledTextIOWriter *****************************
515 ********************************************************************************
516 */
517void StyledTextIOWriter::write (const void* data, size_t nBytes)
518{
519 GetSinkStream ().write (data, nBytes);
520}
521
522void StyledTextIOWriter::write (char c)
523{
524 GetSinkStream ().write (&c, 1);
525}
526
527void StyledTextIOWriter::write (const char* str)
528{
529 RequireNotNull (str);
530 GetSinkStream ().write (str, strlen (str));
531}
532
533void StyledTextIOWriter::write (const string& str)
534{
535 GetSinkStream ().write (str.c_str (), str.length ());
536}
537
538#if qStroika_Frameworks_Led_SupportGDI
539/*
540 ********************************************************************************
541 ***************************** EmbeddingSinkStream ******************************
542 ********************************************************************************
543 */
544EmbeddingSinkStream::EmbeddingSinkStream (StyledTextIOWriter::SinkStream& realSinkStream)
545 : fRealSinkStream{realSinkStream}
546{
547}
548
549void EmbeddingSinkStream::write (const void* buffer, size_t bytes)
550{
551 fRealSinkStream.write (buffer, bytes);
552}
553#endif
#define RequireNotNull(p)
Definition Assertions.h:347
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
Definition Throw.inl:43