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