1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
|
/*************************************************************************
*
* $RCSfile: filerec.cxx,v $
*
* $Revision: 1.3 $
*
* last change: $Author: mhu $ $Date: 2002-06-28 17:48:20 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (the "License"); You may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at http://www.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
#pragma hdrstop
#include "filerec.hxx"
//========================================================================
SV_IMPL_VARARR( SfxUINT32s, UINT32 );
//========================================================================
/* Die folgenden Makros extrahieren Teilbereiche aus einem UINT32 Wert.
Diese UINT32-Werte werden anstelle der einzelnen Werte gestreamt,
um Calls zu sparen.
*/
#define SFX_REC_PRE(n) ( ((n) & 0x000000FF) )
#define SFX_REC_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
#define SFX_REC_TYP(n) ( ((n) & 0x000000FF) )
#define SFX_REC_VER(n) ( ((n) & 0x0000FF00) >> 8 )
#define SFX_REC_TAG(n) ( ((n) & 0xFFFF0000) >> 16 )
#define SFX_REC_CONTENT_VER(n) ( ((n) & 0x000000FF) )
#define SFX_REC_CONTENT_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
//-------------------------------------------------------------------------
/* Die folgenden Makros setzen Teilbereiche zu einem UINT32 Wert zusammen.
Diese UINT32-Werte werden anstelle der einzelnen Werte gestreamt,
um Calls zu sparen.
*/
#define SFX_REC_MINI_HEADER(nPreTag,nStartPos,nEndPos) \
( UINT32(nPreTag) | \
UINT32(nEndPos-nStartPos-SFX_REC_HEADERSIZE_MINI) << 8 )
#define SFX_REC_HEADER(nRecType,nContentTag,nContentVer) \
( UINT32(nRecType) | \
( UINT32(nContentVer) << 8 ) | \
( UINT32(nContentTag) << 16 ) )
#define SFX_REC_CONTENT_HEADER(nContentVer,n1StStartPos,nCurStartPos) \
( UINT32(nContentVer) | \
UINT32( nCurStartPos - n1StStartPos ) << 8 )
//=========================================================================
UINT32 SfxMiniRecordWriter::Close
(
FASTBOOL bSeekToEndOfRec /* TRUE (default)
Der Stream wird an das Ende des Records
positioniert.
FALSE
Der Stream wird an den Anfang des
Contents (also hinter den Header)
positioniert.
*/
)
/* [Beschreibung]
Diese Methode schlie\st den Record. Dabei wird haupts"achlich der
Header geschrieben.
Wurde der Header bereits geschrieben, hat der Aufruf keine Wirkung.
[R"uckgabewert]
UINT32 != 0
Position im Stream, die direkt hinter dem Record liegt.
'bSeekToEndOfRecord==TRUE'
=> R"uckgabewert == aktuelle Stream-Position nach Aufruf
== 0
Der Header war bereits geschrieben worden.
*/
{
// wurde der Header noch nicht geschrieben?
if ( !_bHeaderOk )
{
// Header an den Anfang des Records schreiben
UINT32 nEndPos = _pStream->Tell();
_pStream->Seek( _nStartPos );
*_pStream << SFX_REC_MINI_HEADER( _nPreTag, _nStartPos, nEndPos );
// je nachdem ans Ende des Records seeken oder hinter Header bleiben
if ( bSeekToEndOfRec )
_pStream->Seek( nEndPos );
// Header wurde JETZT geschrieben
_bHeaderOk = TRUE;
return nEndPos;
}
#ifdef DBG_UTIL
// mu\s Fix-Size-Record gepr"uft werden?
else if ( SFX_BOOL_DONTCARE == _bHeaderOk )
{
// Header auslesen, um Soll-Gr"o\se zu bestimmen
UINT32 nEndPos = _pStream->Tell();
_pStream->Seek( _nStartPos );
ULONG nHeader;
*_pStream >> nHeader;
_pStream->Seek( nEndPos );
// Soll-Gr"o\se mit Ist-Gr"o\se vergleichen
DBG_ASSERT( nEndPos - SFX_REC_OFS(nHeader) == _nStartPos + sizeof(UINT32),
"fixed record size incorrect" );
DbgOutf( "SfxFileRec: written record until %ul", nEndPos );
}
#endif
// Record war bereits geschlossen
return 0;
}
//=========================================================================
USHORT SfxMiniRecordReader::ScanRecordType
(
SvStream* pStream /* <SvStream> an dessen aktueller Position
ein Record liegt, dessen Typ erkannt werden
soll.
*/
)
/* [Beschreibung]
Mit dieser statischen Methode kann ermittelt werden, ob sich an der
aktuellen Position in einem Stream ein Record befindet, und der Typ
des Records kann ermittelt werden.
Die Position im Stream ist nach dem Aufruf aufver"andert.
[Anmerkung]
Die Record-Typen k"onnen zwar (abgesehen vom Drawing-Enginge-Record)
untereinander eindeutig erkannt werden, es besteht jedoch die Gefahr
der Verwechslung von Records mit normalen Daten. File-Formate sollten
darauf R"ucksicht nehmen. Handelt es sich um keinen Record, wird
am wahrscheinlichsten SFX_REC_TYPE_MINI zur"uckgeliefert, da dieser
Typ sich aufgrund seines sparsam kurzen Headers durch die k"urzeste
Kennung auszeichnet.
[R"uckgabewert]
USHORT SFX_REC_TYPE_EOR
An der aktuellen Position des Streams
steht eine End-Of-Records-Kennung.
SFX_REC_TYPE_MINI
Es handelt sich um einen SW3 kompatiblen
Mini-Record, dessen einzige Kennung sein
'Mini-Tag' ist.
SFX_REC_TYPE_SINGLE
Es handelt sich um einen Extended-Record
mit einem einzigen Content, der durch eine
Version und ein Tag n"aher gekennzeichnet
ist.
SFX_REC_TYPE_FIXSIZE
Es handelt sich um einen Extended-Record
mit mehreren Contents gleicher Gr"o\se,
die gemeinsam durch eine einzige Version
und ein einziges gemeinsames Tag n"aher
gekennzeichnet sind.
SFX_REC_TYPE_VARSIZE
Es handelt sich um einen Extended-Record
mit mehreren Contents variabler Gr"o\se,
die gemeinsam durch eine einzige Version
und ein einziges gemeinsames Tag n"aher
gekennzeichnet sind.
SFX_REC_TYPE_MIXTAGS
Es handelt sich um einen Extended-Record
mit mehreren Contents variabler Gr"o\se,
die jeweils durch ein eignes Tag und
eine eigene Versions-Nummer n"aher
gekennzeichnet sind.
SFX_REC_TYPE_DRAWENG
Es handelt sich wahrscheinlich um einen
Drawing-Engine-Record. Dieser Record-Typ
kann von den Klassen dieser Gruppe nicht
interpretiert werden.
*/
{
// die ersten 4 Bytes als Mini-Header lesen
ULONG nHeader;
*pStream >> nHeader;
// k"onnte es sich um einen extended-Record handeln?
USHORT nPreTag = SFX_REC_PRE(nHeader);
if ( SFX_REC_PRETAG_EXT == nPreTag )
{
// die n"achsten 4 Bytes als extended-Header lesen
*pStream >> nHeader;
// Stream-Position restaurieren
pStream->SeekRel(-8);
// liegt eine g"ultige Record-Kennung vor?
USHORT nType = SFX_REC_TYP(nHeader);
if ( nType >= SFX_REC_TYPE_FIRST && nType <= SFX_REC_TYPE_LAST )
// entsprechenden extended-Record-Typ zur"uckliefern
return nType;
// sonst ist der Record-Typ unbekannt
return SFX_REC_TYPE_NONE;
}
// Stream-Position restaurieren
pStream->SeekRel(-4);
// liegt eine End-Of-Record-Kennung vor?
if ( SFX_REC_PRETAG_EOR == nPreTag )
return nPreTag;
// liegt ein Drawin-Engine-Record vor?
if ( nHeader == UINT32(*"DRMD") || nHeader == UINT32(*"DRVW") )
return SFX_REC_TYPE_DRAWENG;
// alle anderen sind grunds"atzlich g"ultige Mini-Records
return SFX_REC_TYPE_MINI;
}
//-------------------------------------------------------------------------
FASTBOOL SfxMiniRecordReader::SetHeader_Impl( UINT32 nHeader )
/* [Beschreibung]
Interne Methode zum nachtr"aglichen Verarbeiten eines extern gelesenen
Headers. Falls der Header eine End-Of-Records-Kennung darstellt,
wird am Stream ein Errorcode gesetzt und FALSE zur"uckgeliefert. Im
Fehlerfall wird der Stream jedoch nicht auf den Record-Anfang zur"uck-
gesetzt.
*/
{
FASTBOOL bRet = TRUE;
// Record-Ende und Pre-Tag aus dem Header ermitteln
_nEofRec = _pStream->Tell() + SFX_REC_OFS(nHeader);
_nPreTag = SFX_REC_PRE(nHeader);
// wenn End-Of-Record-Kennung, dann Fehler
if ( _nPreTag == SFX_REC_PRETAG_EOR )
{
_pStream->SetError( ERRCODE_IO_WRONGFORMAT );
bRet = FALSE;
}
return bRet;
}
//-------------------------------------------------------------------------
SfxMiniRecordReader::SfxMiniRecordReader
(
SvStream* pStream /* <SvStream>, an dessen aktueller
Position sich ein <SfxMiniRecord>
befindet.
*/
)
/* [Beschreibung]
Dieser Ctor liest den Header eines <SfxMiniRecord> ab der aktuellen
Position von 'pStream'. Da grunds"atzlich fast 4-Byte Kombination ein
g"ultiger SfxMiniRecord-Header ist, bleiben die einzig m"oglichen
Fehler der EOF-Status des Streams, und ein SFX_REC_PRETAG_EOR
als Pre-Tag. Ein entsprechender Error-Code (ERRCODE_IO_EOF bzw.
ERRCODE_IO_WRONGFORMAT) ist dann am Stream gesetzt, dessen Position
dann au\serdem unver"andert ist.
*/
: _pStream( pStream ),
_bSkipped( FALSE )
{
// Header einlesen
UINT32 nStartPos = pStream->Tell(); // um im Fehlerfall zur"uck zu-seeken
DBG( DbgOutf( "SfxFileRec: reading record at %ul", nStartPos ) );
UINT32 nHeader;
*pStream >> nHeader;
// Headerdaten extrahieren
SetHeader_Impl( nHeader );
// Fehlerbehandlung
if ( pStream->IsEof() )
_nPreTag = SFX_REC_PRETAG_EOR;
else if ( _nPreTag == SFX_REC_PRETAG_EOR )
pStream->SetError( ERRCODE_IO_WRONGFORMAT );
if ( !IsValid() )
pStream->Seek( nStartPos );
}
//-------------------------------------------------------------------------
SfxMiniRecordReader::SfxMiniRecordReader
(
SvStream* pStream, /* <SvStream>, an dessen aktueller
Position sich ein <SfxMiniRecord>
befindet.
*/
BYTE nTag // Pre-Tag des gew"unschten Records
)
/* [Beschreibung]
Dieser Ctor interpretiert 'pStream' ab der aktuellen Position als
eine l"uckenlose Folge von, von dieser Klassen-Gruppe interpretierbaren,
Records. Der in dieser Folge erste als <SfxMiniRecord> interpretierbare
(also ggf. auch ein extended-Record) mit dem PreTag 'nTag' wird ge"offnet
und durch diese Instanz repr"asentiert.
Wird das Ende des Streams oder die Kennung SFX_REC_PRETAG_EOR
erreicht, bevor ein Record mit dem ge"unschten Pre-Tag gefunden wird,
ist die erzeugte Instanz ung"ultig ('IsValid() == FALSE'). Ein ent-
sprechender Error-Code (ERRCODE_IO_EOF bzw. ERRCODE_IO_WRONGFORMAT)
ist dann am Stream gesetzt, dessen Position ist dann au\serdem unver-
"andert.
Bei 'nTag==SFX_FILEREC_PRETAG_EOR' wird nicht versucht, einen Record
zu lesen, es wird sofort 'IsValid()' auf FALSE gesetzt und kein Error-Code
am Stream gesetzt. Dies ist dauzu gedacht, ohne 'new' und 'delete'
abw"rtskompatibel SfxMiniRecords einbauen zu k"onnen. Siehe dazu
<SfxItemSet::Load()>.
[Anwendungsvorschlag]
Wird dieser Ctor in einer bereits ausgelieferten Programmversion
verwendet, k"onnen in das File-Format jeweils davor kompatibel neue
Records mit einer anderen Kennung eingef"ugt werden. Diese werden
schlie\slich automatisch "uberlesen. Erkauft wird diese M"oglichkeit
allerdings mit etwas schlechterem Laufzeitverhalten im Vergleich mit
direktem 'drauf-los-lesen', der sich jedoch auf einen Vergleich zweier
Bytes reduziert, falls der gesuchte Record der erste in der Folge ist.
*/
: _pStream( pStream ),
_bSkipped( nTag == SFX_REC_PRETAG_EOR )
{
// ggf. ignorieren (s.o.)
if ( _bSkipped )
{
_nPreTag = nTag;
return;
}
// StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
UINT32 nStartPos = pStream->Tell();
// passenden Record suchen
while(TRUE)
{
// Header lesen
DBG( DbgOutf( "SfxFileRec: searching record at %ul", pStream->Tell() ) );
UINT32 nHeader;
*pStream >> nHeader;
// Headerdaten von Basisklasse extrahieren lassen
SetHeader_Impl( nHeader );
// ggf. Fehler behandeln
if ( pStream->IsEof() )
_nPreTag = SFX_REC_PRETAG_EOR;
else if ( _nPreTag == SFX_REC_PRETAG_EOR )
pStream->SetError( ERRCODE_IO_WRONGFORMAT );
else
{
// wenn gefunden, dann Schleife abbrechen
if ( _nPreTag == nTag )
break;
// sonst skippen und weitersuchen
pStream->Seek( _nEofRec );
continue;
}
// Fehler => zur"uck-seeken
pStream->Seek( nStartPos );
break;
}
}
//=========================================================================
SfxSingleRecordWriter::SfxSingleRecordWriter
(
BYTE nRecordType, // f"ur Subklassen
SvStream* pStream, // Stream, in dem der Record angelegt wird
UINT16 nContentTag, // Inhalts-Art-Kennung
BYTE nContentVer // Inhalts-Versions-Kennung
)
/* [Beschreibung]
Interner Ctor f"ur Subklassen.
*/
: SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT )
{
// Erweiterten Header hiner den des SfxMiniRec schreiben
*pStream << SFX_REC_HEADER(nRecordType, nContentTag, nContentVer);
}
//-------------------------------------------------------------------------
SfxSingleRecordWriter::SfxSingleRecordWriter
(
SvStream* pStream, // Stream, in dem der Record angelegt wird
UINT16 nContentTag, // Inhalts-Art-Kennung
BYTE nContentVer // Inhalts-Versions-Kennung
)
/* [Beschreibung]
Legt in 'pStream' einen 'SfxSingleRecord' an, dessen Content-Gr"o\se
nicht bekannt ist, sondern nach dam Streamen des Contents errechnet
werden soll.
*/
: SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT )
{
// Erweiterten Header hiner den des SfxMiniRec schreiben
*pStream << SFX_REC_HEADER( SFX_REC_TYPE_SINGLE, nContentTag, nContentVer);
}
//-------------------------------------------------------------------------
SfxSingleRecordWriter::SfxSingleRecordWriter
(
SvStream* pStream, // Stream, in dem der Record angelegt wird
UINT16 nContentTag, // Inhalts-Art-Kennung
BYTE nContentVer, // Inhalts-Versions-Kennung
UINT32 nContentSize // Gr"o\se des Inhalts in Bytes
)
/* [Beschreibung]
Legt in 'pStream' einen 'SfxSingleRecord' an, dessen Content-Gr"o\se
von vornherein bekannt ist.
*/
: SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT,
nContentSize + SFX_REC_HEADERSIZE_SINGLE )
{
// Erweiterten Header hinter den des SfxMiniRec schreiben
*pStream << SFX_REC_HEADER( SFX_REC_TYPE_SINGLE, nContentTag, nContentVer);
}
//=========================================================================
inline FASTBOOL SfxSingleRecordReader::ReadHeader_Impl( USHORT nTypes )
/* [Beschreibung]
Interne Methode zum Einlesen eines SfxMultiRecord-Headers, nachdem
die Basisklasse bereits initialisiert und deren Header gelesen ist.
Ggf. ist ein Error-Code am Stream gesetzt, im Fehlerfall wird jedoch
nicht zur"uckge-seekt.
*/
{
FASTBOOL bRet;
// Basisklassen-Header einlesen
UINT32 nHeader;
*_pStream >> nHeader;
if ( !SetHeader_Impl( nHeader ) )
bRet = FALSE;
else
{
// eigenen Header einlesen
*_pStream >> nHeader;
_nRecordVer = SFX_REC_VER(nHeader);
_nRecordTag = SFX_REC_TAG(nHeader);
// falscher Record-Typ?
_nRecordType = SFX_REC_TYP(nHeader);
bRet = 0 != ( nTypes & _nRecordType);
}
return bRet;
}
//-------------------------------------------------------------------------
SfxSingleRecordReader::SfxSingleRecordReader( SvStream *pStream )
: SfxMiniRecordReader()
{
// Startposition merken, um im Fehlerfall zur"uck-seeken zu k"onnen
UINT32 nStartPos = pStream->Tell();
DBG( DbgOutf( "SfxFileRec: reading record at %ul", nStartPos ) );
// Basisklasse initialisieren (nicht via Ctor, da der nur MiniRecs akzept.)
Construct_Impl( pStream );
// nur Header mit korrektem Record-Type akzeptieren
if ( !ReadHeader_Impl( SFX_REC_TYPE_SINGLE ) )
{
// Error-Code setzen und zur"uck-seeken
pStream->SeekRel( - SFX_REC_HEADERSIZE_SINGLE );
pStream->SetError( ERRCODE_IO_WRONGFORMAT );
}
}
//-------------------------------------------------------------------------
SfxSingleRecordReader::SfxSingleRecordReader( SvStream *pStream, USHORT nTag )
{
// StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
UINT32 nStartPos = pStream->Tell();
// richtigen Record suchen, ggf. Error-Code setzen und zur"uck-seeken
Construct_Impl( pStream );
if ( !FindHeader_Impl( SFX_REC_TYPE_SINGLE, nTag ) )
{
// Error-Code setzen und zur"uck-seeken
pStream->Seek( nStartPos );
pStream->SetError( ERRCODE_IO_WRONGFORMAT );
}
}
//-------------------------------------------------------------------------
FASTBOOL SfxSingleRecordReader::FindHeader_Impl
(
UINT16 nTypes, // arithm. Veroderung erlaubter Record-Typen
UINT16 nTag // zu findende Record-Art-Kennung
)
/* [Beschreibung]
Interne Methode zum lesen des Headers des ersten Record, der einem
der Typen in 'nTypes' entspricht und mit der Art-Kennung 'nTag'
gekennzeichnet ist.
Kann ein solcher Record nicht gefunden werden, wird am Stream ein
Errorcode gesetzt, zur"uck-geseekt und FALSE zur"uckgeliefert.
*/
{
// StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
UINT32 nStartPos = _pStream->Tell();
// richtigen Record suchen
while ( !_pStream->IsEof() )
{
// Header lesen
UINT32 nHeader;
DBG( DbgOutf( "SfxFileRec: searching record at %ul", _pStream->Tell() ) );
*_pStream >> nHeader;
if ( !SetHeader_Impl( nHeader ) )
// EOR => Such-Schleife abbreichen
break;
// Extended Record gefunden?
if ( _nPreTag == SFX_REC_PRETAG_EXT )
{
// Extended Header lesen
*_pStream >> nHeader;
_nRecordTag = SFX_REC_TAG(nHeader);
// richtigen Record gefunden?
if ( _nRecordTag == nTag )
{
// gefundener Record-Typ passend?
_nRecordType = SFX_REC_TYP(nHeader);
if ( nTypes & _nRecordType )
// ==> gefunden
return TRUE;
// error => Such-Schleife abbrechen
break;
}
}
// sonst skippen
if ( !_pStream->IsEof() )
_pStream->Seek( _nEofRec );
}
// Fehler setzen und zur"uck-seeken
_pStream->SetError( ERRCODE_IO_WRONGFORMAT );
_pStream->Seek( nStartPos );
return FALSE;
}
//=========================================================================
SfxMultiFixRecordWriter::SfxMultiFixRecordWriter
(
BYTE nRecordType, // Subklassen Record-Kennung
SvStream* pStream, // Stream, in dem der Record angelegt wird
UINT16 nContentTag, // Content-Art-Kennung
BYTE nContentVer, // Content-Versions-Kennung
UINT32 nContentSize // Gr"o\se jedes einzelnen Contents in Bytes
)
/* [Beschreibung]
Interne Methode f"ur Subklassen.
*/
: SfxSingleRecordWriter( nRecordType, pStream, nContentTag, nContentVer ),
_nContentCount( 0 )
{
// Platz f"ur eigenen Header
pStream->SeekRel( + SFX_REC_HEADERSIZE_MULTI );
}
//------------------------------------------------------------------------
SfxMultiFixRecordWriter::SfxMultiFixRecordWriter
(
SvStream* pStream, // Stream, in dem der Record angelegt wird
UINT16 nContentTag, // Content-Art-Kennung
BYTE nContentVer, // Content-Versions-Kennung
UINT32 nContentSize // Gr"o\se jedes einzelnen Contents in Bytes
)
/* [Beschreibung]
Legt in 'pStream' einen 'SfxMultiFixRecord' an, dessen Content-Gr"o\se
konstant und von vornherein bekannt ist.
*/
: SfxSingleRecordWriter( SFX_REC_TYPE_FIXSIZE,
pStream, nContentTag, nContentVer ),
_nContentCount( 0 )
{
// Platz f"ur eigenen Header
pStream->SeekRel( + SFX_REC_HEADERSIZE_MULTI );
}
//------------------------------------------------------------------------
UINT32 SfxMultiFixRecordWriter::Close( FASTBOOL bSeekToEndOfRec )
// siehe <SfxMiniRecordWriter>
{
// Header noch nicht geschrieben?
if ( !_bHeaderOk )
{
// Position hinter Record merken, um sie restaurieren zu k"onnen
UINT32 nEndPos = SfxSingleRecordWriter::Close( FALSE );
// gegen"uber SfxSingleRecord erweiterten Header schreiben
*_pStream << _nContentCount;
*_pStream << _nContentSize;
// je nachdem ans Ende des Records seeken oder hinter Header bleiben
if ( bSeekToEndOfRec )
_pStream->Seek(nEndPos);
return nEndPos;
}
// Record war bereits geschlossen
return 0;
}
//=========================================================================
SfxMultiVarRecordWriter::SfxMultiVarRecordWriter
(
BYTE nRecordType, // Record-Kennung der Subklasse
SvStream* pStream, // Stream, in dem der Record angelegt wird
UINT16 nRecordTag, // Gesamt-Art-Kennung
BYTE nRecordVer // Gesamt-Versions-Kennung
)
/* [Beschreibung]
Interner Ctor f"ur Subklassen.
*/
: SfxMultiFixRecordWriter( nRecordType, pStream, nRecordTag, nRecordVer, 0 ),
_nContentVer( 0 )
{
}
//-------------------------------------------------------------------------
SfxMultiVarRecordWriter::SfxMultiVarRecordWriter
(
SvStream* pStream, // Stream, in dem der Record angelegt wird
UINT16 nRecordTag, // Gesamt-Art-Kennung
BYTE nRecordVer // Gesamt-Versions-Kennung
)
/* [Beschreibung]
Legt in 'pStream' einen 'SfxMultiVarRecord' an, dessen Content-Gr"o\sen
weder bekannt sind noch identisch sein m"ussen, sondern jeweils nach dem
Streamen jedes einzelnen Contents errechnet werden sollen.
[Anmerkung]
Diese Methode ist nicht inline, da f"ur die Initialisierung eines
<SvULongs>-Members zu viel Code generiert werden w"urde.
*/
: SfxMultiFixRecordWriter( SFX_REC_TYPE_VARSIZE,
pStream, nRecordTag, nRecordVer, 0 ),
_nContentVer( 0 )
{
}
//-------------------------------------------------------------------------
SfxMultiVarRecordWriter::~SfxMultiVarRecordWriter()
/* [Beschreibung]
Der Dtor der Klasse <SfxMultiVarRecordWriter> schlie\st den Record
automatisch, falls <SfxMultiVarRecordWriter::Close()> nicht bereits
explizit gerufen wurde.
*/
{
// wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden
if ( !_bHeaderOk )
Close();
}
//-------------------------------------------------------------------------
void SfxMultiVarRecordWriter::FlushContent_Impl()
/* [Beschreibung]
Interne Methode zum Abschlie\sen eines einzelnen Contents.
*/
{
// Versions-Kennung und Positions-Offset des aktuellen Contents merken;
// das Positions-Offset ist relativ zur Startposition des ersten Contents
_aContentOfs.Insert(
SFX_REC_CONTENT_HEADER(_nContentVer,_nStartPos,_nContentStartPos),
_nContentCount-1 );
}
//-------------------------------------------------------------------------
void SfxMultiVarRecordWriter::NewContent()
// siehe <SfxMultiFixRecordWriter>
{
// schon ein Content geschrieben?
if ( _nContentCount )
FlushContent_Impl();
// neuen Content beginnen
_nContentStartPos = _pStream->Tell();
++_nContentCount;
}
//-------------------------------------------------------------------------
UINT32 SfxMultiVarRecordWriter::Close( FASTBOOL bSeekToEndOfRec )
// siehe <SfxMiniRecordWriter>
{
// Header noch nicht geschrieben?
if ( !_bHeaderOk )
{
// ggf. letzten Content abschlie\sen
if ( _nContentCount )
FlushContent_Impl();
// Content-Offset-Tabelle schreiben
UINT32 nContentOfsPos = _pStream->Tell();
//! darf man das so einr"ucken?
#if defined(__LITTLEENDIAN)
_pStream->Write( _aContentOfs.GetData(),
sizeof(UINT32)*_nContentCount );
#else
for ( USHORT n = 0; n < _nContentCount; ++n )
*_pStream << UINT32(_aContentOfs[n]);
#endif
// SfxMultiFixRecordWriter::Close() "uberspringen!
UINT32 nEndPos = SfxSingleRecordWriter::Close( FALSE );
// eigenen Header schreiben
*_pStream << _nContentCount;
if ( SFX_REC_TYPE_VARSIZE_RELOC == _nPreTag ||
SFX_REC_TYPE_MIXTAGS_RELOC == _nPreTag )
*_pStream << nContentOfsPos - ( _pStream->Tell() + sizeof(UINT32) );
else
*_pStream << nContentOfsPos;
// ans Ende des Records seeken bzw. am Ende des Headers bleiben
if ( bSeekToEndOfRec )
_pStream->Seek(nEndPos);
return nEndPos;
}
// Record war bereits vorher geschlossen
return 0;
}
//=========================================================================
void SfxMultiMixRecordWriter::NewContent
(
UINT16 nContentTag, // Kennung f"ur die Art des Contents
BYTE nContentVer // Kennung f"ur die Version des Contents
)
/* [Beschreibung]
Mit dieser Methode wird in den Record ein neuer Content eingef"ugt
und dessen Content-Tag sowie dessen Content-Version angegeben. Jeder,
auch der 1. Record mu\s durch Aufruf dieser Methode eingeleitet werden.
*/
{
// ggf. vorherigen Record abschlie\sen
if ( _nContentCount )
FlushContent_Impl();
// Tag vor den Content schreiben, Version und Startposition merken
_nContentStartPos = _pStream->Tell();
++_nContentCount;
*_pStream << nContentTag;
_nContentVer = nContentVer;
}
//=========================================================================
FASTBOOL SfxMultiRecordReader::ReadHeader_Impl()
/* [Beschreibung]
Interne Methode zum Einlesen eines SfxMultiRecord-Headers, nachdem
die Basisklasse bereits initialisiert und deren Header gelesen ist.
Ggf. ist ein Error-Code am Stream gesetzt, im Fehlerfall wird jedoch
nicht zur"uckge-seekt.
*/
{
// eigenen Header lesen
*_pStream >> _nContentCount;
*_pStream >> _nContentSize; // Fix: jedes einzelnen, Var|Mix: Tabellen-Pos.
// mu\s noch eine Tabelle mit Content-Offsets geladen werden?
if ( _nRecordType != SFX_REC_TYPE_FIXSIZE )
{
// Tabelle aus dem Stream einlesen
UINT32 nContentPos = _pStream->Tell();
if ( _nRecordType == SFX_REC_TYPE_VARSIZE_RELOC ||
_nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
_pStream->SeekRel( + _nContentSize );
else
_pStream->Seek( _nContentSize );
_pContentOfs = new UINT32[_nContentCount];
//! darf man jetzt so einr"ucken
#if defined(__LITTLEENDIAN)
_pStream->Read( _pContentOfs, sizeof(UINT32)*_nContentCount );
#else
for ( USHORT n = 0; n < _nContentCount; ++n )
*_pStream >> _pContentOfs[n];
#endif
_pStream->Seek( nContentPos );
}
// Header konnte gelesen werden, wenn am Stream kein Error gesetzt ist
return !_pStream->GetError();
}
//-------------------------------------------------------------------------
SfxMultiRecordReader::SfxMultiRecordReader( SvStream *pStream )
: _nContentNo(0), _pContentOfs( NULL )
{
// Position im Stream merken, um im Fehlerfall zur"uck-seeken zu k"onnen
_nStartPos = pStream->Tell();
// Basisklasse konstruieren (normaler Ctor w"urde nur SingleRecs lesen)
SfxSingleRecordReader::Construct_Impl( pStream );
// Header der Basisklasse lesen
if ( !SfxSingleRecordReader::ReadHeader_Impl( SFX_REC_TYPE_FIXSIZE |
SFX_REC_TYPE_VARSIZE | SFX_REC_TYPE_VARSIZE_RELOC |
SFX_REC_TYPE_MIXTAGS | SFX_REC_TYPE_MIXTAGS_RELOC ) ||
!ReadHeader_Impl() )
// als ung"ultig markieren und zur"uck-seeken
SetInvalid_Impl( _nStartPos );
}
//-------------------------------------------------------------------------
SfxMultiRecordReader::SfxMultiRecordReader( SvStream *pStream, UINT16 nTag )
: _nContentNo(0)
{
// Position im Stream merken, um im Fehlerfall zur"uck-seeken zu k"onnen
_nStartPos = pStream->Tell();
// passenden Record suchen und Basisklasse initialisieren
SfxSingleRecordReader::Construct_Impl( pStream );
if ( SfxSingleRecordReader::FindHeader_Impl( SFX_REC_TYPE_FIXSIZE |
SFX_REC_TYPE_VARSIZE | SFX_REC_TYPE_VARSIZE_RELOC |
SFX_REC_TYPE_MIXTAGS | SFX_REC_TYPE_MIXTAGS_RELOC,
nTag ) )
{
// eigenen Header dazu-lesen
if ( !ReadHeader_Impl() )
// nicht lesbar => als ung"ultig markieren und zur"uck-seeken
SetInvalid_Impl( _nStartPos);
}
}
//-------------------------------------------------------------------------
SfxMultiRecordReader::~SfxMultiRecordReader()
{
delete[] _pContentOfs;
}
//-------------------------------------------------------------------------
FASTBOOL SfxMultiRecordReader::GetContent()
/* [Beschreibung]
Positioniert den Stream an den Anfang des n"chsten bzw. beim 1. Aufruf
auf den Anfang des ersten Contents im Record und liest ggf. dessen
Header ein.
Liegt laut Record-Header kein Content mehr vor, wird FALSE zur"uck-
gegeben. Trotz einem TRUE-Returnwert kann am Stream ein Fehlercode
gesetzt sein, z.B. falls er unvorhergesehenerweise (kaputtes File)
zuende ist.
*/
{
// noch ein Content vorhanden?
if ( _nContentNo < _nContentCount )
{
// den Stream an den Anfang des Contents positionieren
UINT32 nOffset = _nRecordType == SFX_REC_TYPE_FIXSIZE
? _nContentNo * _nContentSize
: SFX_REC_CONTENT_OFS(_pContentOfs[_nContentNo]);
UINT32 nNewPos = _nStartPos + nOffset;
DBG_ASSERT( nNewPos >= _pStream->Tell(), "SfxMultiRecordReader::GetContent() - New position before current, to much data red!" );
// #99366#: correct stream pos in every case;
// the if clause was added by MT a long time ago,
// maybe to 'repair' other corrupt documents; but this
// gives errors when writing with 5.1 and reading with current
// versions, so we decided to remove the if clause (KA-05/17/2002)
// if ( nNewPos > _pStream->Tell() )
_pStream->Seek( nNewPos );
// ggf. Content-Header lesen
if ( _nRecordType == SFX_REC_TYPE_MIXTAGS ||
_nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
{
_nContentVer = SFX_REC_CONTENT_VER(_pContentOfs[_nContentNo]);
*_pStream >> _nContentTag;
}
// ContentNo weiterz"ahlen
++_nContentNo;
return TRUE;
}
return FALSE;
}
|