Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <svl/filerec.hxx>
21 : #include <osl/endian.h>
22 :
23 :
24 : /* Die folgenden Makros extrahieren Teilbereiche aus einem sal_uInt32 Wert.
25 : Diese sal_uInt32-Werte werden anstelle der einzelnen Werte gestreamt,
26 : um Calls zu sparen.
27 : */
28 :
29 : #define SFX_REC_PRE(n) ( ((n) & 0x000000FF) )
30 : #define SFX_REC_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
31 : #define SFX_REC_TYP(n) ( ((n) & 0x000000FF) )
32 : #define SFX_REC_VER(n) ( ((n) & 0x0000FF00) >> 8 )
33 : #define SFX_REC_TAG(n) ( ((n) & 0xFFFF0000) >> 16 )
34 :
35 : #define SFX_REC_CONTENT_VER(n) ( ((n) & 0x000000FF) )
36 : #define SFX_REC_CONTENT_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
37 :
38 :
39 : /* Die folgenden Makros setzen Teilbereiche zu einem sal_uInt32 Wert zusammen.
40 : Diese sal_uInt32-Werte werden anstelle der einzelnen Werte gestreamt,
41 : um Calls zu sparen.
42 : */
43 :
44 0 : static void lclWriteMiniHeader(SvStream *p, sal_uInt32 nPreTag, sal_uInt32 nStartPos, sal_uInt32 nEndPos)
45 : {
46 : (*p).WriteUInt32( sal_uInt32(nPreTag) |
47 0 : sal_uInt32(nEndPos-nStartPos-SFX_REC_HEADERSIZE_MINI) << 8 );
48 0 : }
49 :
50 0 : static void lclWriteHeader(SvStream *p, sal_uInt32 nRecType, sal_uInt32 nContentTag, sal_uInt32 nContentVer)
51 : {
52 0 : (*p).WriteUInt32( sal_uInt32(nRecType) |
53 0 : ( sal_uInt32(nContentVer) << 8 ) |
54 0 : ( sal_uInt32(nContentTag) << 16 ) );
55 0 : }
56 :
57 : #define SFX_REC_CONTENT_HEADER(nContentVer,n1StStartPos,nCurStartPos) \
58 : ( sal_uInt32(nContentVer) | \
59 : sal_uInt32( nCurStartPos - n1StStartPos ) << 8 )
60 :
61 :
62 0 : sal_uInt32 SfxMiniRecordWriter::Close
63 : (
64 : bool bSeekToEndOfRec /* true (default)
65 : Der Stream wird an das Ende des Records
66 : positioniert.
67 :
68 : false
69 : Der Stream wird an den Anfang des
70 : Contents (also hinter den Header)
71 : positioniert.
72 : */
73 : )
74 :
75 : /* [Beschreibung]
76 :
77 : Diese Methode schlie\st den Record. Dabei wird haupts"achlich der
78 : Header geschrieben.
79 :
80 : Wurde der Header bereits geschrieben, hat der Aufruf keine Wirkung.
81 :
82 :
83 : [R"uckgabewert]
84 :
85 : sal_uInt32 != 0
86 : Position im Stream, die direkt hinter dem Record liegt.
87 : 'bSeekToEndOfRecord==sal_True'
88 : => R"uckgabewert == aktuelle Stream-Position nach Aufruf
89 :
90 : == 0
91 : Der Header war bereits geschrieben worden.
92 : */
93 :
94 : {
95 : // wurde der Header noch nicht geschrieben?
96 0 : if ( !_bHeaderOk )
97 : {
98 : // Header an den Anfang des Records schreiben
99 0 : sal_uInt32 nEndPos = _pStream->Tell();
100 0 : _pStream->Seek( _nStartPos );
101 0 : lclWriteMiniHeader(_pStream, _nPreTag, _nStartPos, nEndPos );
102 :
103 : // je nachdem ans Ende des Records seeken oder hinter Header bleiben
104 0 : if ( bSeekToEndOfRec )
105 0 : _pStream->Seek( nEndPos );
106 :
107 : // Header wurde JETZT geschrieben
108 0 : _bHeaderOk = true;
109 0 : return nEndPos;
110 : }
111 :
112 : // Record war bereits geschlossen
113 0 : return 0;
114 : }
115 :
116 0 : bool SfxMiniRecordReader::SetHeader_Impl( sal_uInt32 nHeader )
117 :
118 : /* [Beschreibung]
119 :
120 : Interne Methode zum nachtr"aglichen Verarbeiten eines extern gelesenen
121 : Headers. Falls der Header eine End-Of-Records-Kennung darstellt,
122 : wird am Stream ein Errorcode gesetzt und sal_False zur"uckgeliefert. Im
123 : Fehlerfall wird der Stream jedoch nicht auf den Record-Anfang zur"uck-
124 : gesetzt.
125 : */
126 :
127 : {
128 0 : bool bRet = true;
129 :
130 : // Record-Ende und Pre-Tag aus dem Header ermitteln
131 0 : _nEofRec = _pStream->Tell() + SFX_REC_OFS(nHeader);
132 0 : _nPreTag = sal::static_int_cast< sal_uInt8 >(SFX_REC_PRE(nHeader));
133 :
134 : // wenn End-Of-Record-Kennung, dann Fehler
135 0 : if ( _nPreTag == SFX_REC_PRETAG_EOR )
136 : {
137 0 : _pStream->SetError( ERRCODE_IO_WRONGFORMAT );
138 0 : bRet = true;
139 : }
140 0 : return bRet;
141 : }
142 :
143 0 : SfxMiniRecordReader::SfxMiniRecordReader
144 : (
145 : SvStream* pStream, /* <SvStream>, an dessen aktueller
146 : Position sich ein <SfxMiniRecord>
147 : befindet.
148 : */
149 : sal_uInt8 nTag // Pre-Tag des gew"unschten Records
150 : )
151 :
152 : /* [Beschreibung]
153 :
154 : Dieser Ctor interpretiert 'pStream' ab der aktuellen Position als
155 : eine l"uckenlose Folge von, von dieser Klassen-Gruppe interpretierbaren,
156 : Records. Der in dieser Folge erste als <SfxMiniRecord> interpretierbare
157 : (also ggf. auch ein extended-Record) mit dem PreTag 'nTag' wird ge"offnet
158 : und durch diese Instanz repr"asentiert.
159 :
160 : Wird das Ende des Streams oder die Kennung SFX_REC_PRETAG_EOR
161 : erreicht, bevor ein Record mit dem ge"unschten Pre-Tag gefunden wird,
162 : ist die erzeugte Instanz ung"ultig ('IsValid() == sal_False'). Ein ent-
163 : sprechender Error-Code (ERRCODE_IO_EOF bzw. ERRCODE_IO_WRONGFORMAT)
164 : ist dann am Stream gesetzt, dessen Position ist dann au\serdem unver-
165 : "andert.
166 :
167 : Bei 'nTag==SFX_FILEREC_PRETAG_EOR' wird nicht versucht, einen Record
168 : zu lesen, es wird sofort 'IsValid()' auf sal_False gesetzt und kein Error-Code
169 : am Stream gesetzt. Dies ist dauzu gedacht, ohne 'new' und 'delete'
170 : abw"rtskompatibel SfxMiniRecords einbauen zu k"onnen. Siehe dazu
171 : <SfxItemSet::Load()>.
172 :
173 :
174 : [Anwendungsvorschlag]
175 :
176 : Wird dieser Ctor in einer bereits ausgelieferten Programmversion
177 : verwendet, k"onnen in das File-Format jeweils davor kompatibel neue
178 : Records mit einer anderen Kennung eingef"ugt werden. Diese werden
179 : schlie\slich automatisch "uberlesen. Erkauft wird diese M"oglichkeit
180 : allerdings mit etwas schlechterem Laufzeitverhalten im Vergleich mit
181 : direktem 'drauf-los-lesen', der sich jedoch auf einen Vergleich zweier
182 : Bytes reduziert, falls der gesuchte Record der erste in der Folge ist.
183 : */
184 :
185 : : _pStream(pStream)
186 : , _nEofRec(0)
187 0 : , _bSkipped(nTag == SFX_REC_PRETAG_EOR)
188 : {
189 : // ggf. ignorieren (s.o.)
190 0 : if ( _bSkipped )
191 : {
192 0 : _nPreTag = nTag;
193 0 : return;
194 : }
195 :
196 : // StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
197 0 : sal_uInt32 nStartPos = pStream->Tell();
198 :
199 : // passenden Record suchen
200 : while(true)
201 : {
202 : // Header lesen
203 : SAL_INFO("svl", "SfxFileRec: searching record at " << pStream->Tell());
204 : sal_uInt32 nHeader;
205 0 : pStream->ReadUInt32( nHeader );
206 :
207 : // Headerdaten von Basisklasse extrahieren lassen
208 0 : SetHeader_Impl( nHeader );
209 :
210 : // ggf. Fehler behandeln
211 0 : if ( pStream->IsEof() )
212 0 : _nPreTag = SFX_REC_PRETAG_EOR;
213 0 : else if ( _nPreTag == SFX_REC_PRETAG_EOR )
214 0 : pStream->SetError( ERRCODE_IO_WRONGFORMAT );
215 : else
216 : {
217 : // wenn gefunden, dann Schleife abbrechen
218 0 : if ( _nPreTag == nTag )
219 0 : break;
220 :
221 : // sonst skippen und weitersuchen
222 0 : pStream->Seek( _nEofRec );
223 0 : continue;
224 : }
225 :
226 : // Fehler => zur"uck-seeken
227 0 : pStream->Seek( nStartPos );
228 0 : break;
229 0 : }
230 : }
231 :
232 :
233 0 : SfxSingleRecordWriter::SfxSingleRecordWriter
234 : (
235 : sal_uInt8 nRecordType, // f"ur Subklassen
236 : SvStream* pStream, // Stream, in dem der Record angelegt wird
237 : sal_uInt16 nContentTag, // Inhalts-Art-Kennung
238 : sal_uInt8 nContentVer // Inhalts-Versions-Kennung
239 : )
240 :
241 : /* [Beschreibung]
242 :
243 : Interner Ctor f"ur Subklassen.
244 : */
245 :
246 0 : : SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT )
247 : {
248 : // Erweiterten Header hiner den des SfxMiniRec schreiben
249 0 : lclWriteHeader(pStream, nRecordType, nContentTag, nContentVer);
250 0 : }
251 :
252 :
253 : inline bool SfxSingleRecordReader::ReadHeader_Impl( sal_uInt16 nTypes )
254 :
255 : /* [Beschreibung]
256 :
257 : Interne Methode zum Einlesen eines SfxMultiRecord-Headers, nachdem
258 : die Basisklasse bereits initialisiert und deren Header gelesen ist.
259 : Ggf. ist ein Error-Code am Stream gesetzt, im Fehlerfall wird jedoch
260 : nicht zur"uckge-seekt.
261 : */
262 :
263 : {
264 : bool bRet;
265 :
266 : // Basisklassen-Header einlesen
267 : sal_uInt32 nHeader=0;
268 : _pStream->ReadUInt32( nHeader );
269 : if ( !SetHeader_Impl( nHeader ) )
270 : bRet = false;
271 : else
272 : {
273 : // eigenen Header einlesen
274 : _pStream->ReadUInt32( nHeader );
275 : _nRecordVer = sal::static_int_cast< sal_uInt8 >(SFX_REC_VER(nHeader));
276 : _nRecordTag = sal::static_int_cast< sal_uInt16 >(SFX_REC_TAG(nHeader));
277 :
278 : // falscher Record-Typ?
279 : _nRecordType = sal::static_int_cast< sal_uInt8 >(SFX_REC_TYP(nHeader));
280 : bRet = 0 != ( nTypes & _nRecordType);
281 : }
282 : return bRet;
283 : }
284 :
285 :
286 0 : bool SfxSingleRecordReader::FindHeader_Impl
287 : (
288 : sal_uInt16 nTypes, // arithm. Veroderung erlaubter Record-Typen
289 : sal_uInt16 nTag // zu findende Record-Art-Kennung
290 : )
291 :
292 : /* [Beschreibung]
293 :
294 : Interne Methode zum lesen des Headers des ersten Record, der einem
295 : der Typen in 'nTypes' entspricht und mit der Art-Kennung 'nTag'
296 : gekennzeichnet ist.
297 :
298 : Kann ein solcher Record nicht gefunden werden, wird am Stream ein
299 : Errorcode gesetzt, zur"uck-geseekt und sal_False zur"uckgeliefert.
300 : */
301 :
302 : {
303 : // StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
304 0 : sal_uInt32 nStartPos = _pStream->Tell();
305 :
306 : // richtigen Record suchen
307 0 : while ( !_pStream->IsEof() )
308 : {
309 : // Header lesen
310 : sal_uInt32 nHeader;
311 : SAL_INFO("svl", "SfxFileRec: searching record at " << _pStream->Tell());
312 0 : _pStream->ReadUInt32( nHeader );
313 0 : if ( !SetHeader_Impl( nHeader ) )
314 : // EOR => Such-Schleife abbreichen
315 0 : break;
316 :
317 : // Extended Record gefunden?
318 0 : if ( _nPreTag == SFX_REC_PRETAG_EXT )
319 : {
320 : // Extended Header lesen
321 0 : _pStream->ReadUInt32( nHeader );
322 0 : _nRecordTag = sal::static_int_cast< sal_uInt16 >(SFX_REC_TAG(nHeader));
323 :
324 : // richtigen Record gefunden?
325 0 : if ( _nRecordTag == nTag )
326 : {
327 : // gefundener Record-Typ passend?
328 : _nRecordType = sal::static_int_cast< sal_uInt8 >(
329 0 : SFX_REC_TYP(nHeader));
330 0 : if ( nTypes & _nRecordType )
331 : // ==> gefunden
332 0 : return true;
333 :
334 : // error => Such-Schleife abbrechen
335 0 : break;
336 : }
337 : }
338 :
339 : // sonst skippen
340 0 : if ( !_pStream->IsEof() )
341 0 : _pStream->Seek( _nEofRec );
342 : }
343 :
344 : // Fehler setzen und zur"uck-seeken
345 0 : _pStream->SetError( ERRCODE_IO_WRONGFORMAT );
346 0 : _pStream->Seek( nStartPos );
347 0 : return false;
348 : }
349 :
350 :
351 0 : SfxMultiFixRecordWriter::SfxMultiFixRecordWriter
352 : (
353 : sal_uInt8 nRecordType, // Subklassen Record-Kennung
354 : SvStream* pStream, // Stream, in dem der Record angelegt wird
355 : sal_uInt16 nContentTag, // Content-Art-Kennung
356 : sal_uInt8 nContentVer // Content-Versions-Kennung
357 : )
358 :
359 : /* [Beschreibung]
360 :
361 : Interne Methode f"ur Subklassen.
362 : */
363 :
364 : : SfxSingleRecordWriter( nRecordType, pStream, nContentTag, nContentVer )
365 : , _nContentStartPos(0)
366 : , _nContentSize(0)
367 0 : , _nContentCount(0)
368 : {
369 : // Platz f"ur eigenen Header
370 0 : pStream->SeekRel( + SFX_REC_HEADERSIZE_MULTI );
371 0 : }
372 :
373 :
374 0 : sal_uInt32 SfxMultiFixRecordWriter::Close( bool bSeekToEndOfRec )
375 :
376 : // siehe <SfxMiniRecordWriter>
377 :
378 : {
379 : // Header noch nicht geschrieben?
380 0 : if ( !_bHeaderOk )
381 : {
382 : // Position hinter Record merken, um sie restaurieren zu k"onnen
383 0 : sal_uInt32 nEndPos = SfxSingleRecordWriter::Close( false );
384 :
385 : // gegen"uber SfxSingleRecord erweiterten Header schreiben
386 0 : _pStream->WriteUInt16( _nContentCount );
387 0 : _pStream->WriteUInt32( _nContentSize );
388 :
389 : // je nachdem ans Ende des Records seeken oder hinter Header bleiben
390 0 : if ( bSeekToEndOfRec )
391 0 : _pStream->Seek(nEndPos);
392 0 : return nEndPos;
393 : }
394 :
395 : // Record war bereits geschlossen
396 0 : return 0;
397 : }
398 :
399 :
400 0 : SfxMultiVarRecordWriter::SfxMultiVarRecordWriter
401 : (
402 : sal_uInt8 nRecordType, // Record-Kennung der Subklasse
403 : SvStream* pStream, // Stream, in dem der Record angelegt wird
404 : sal_uInt16 nRecordTag, // Gesamt-Art-Kennung
405 : sal_uInt8 nRecordVer // Gesamt-Versions-Kennung
406 : )
407 :
408 : /* [Beschreibung]
409 :
410 : Interner Ctor f"ur Subklassen.
411 : */
412 :
413 : : SfxMultiFixRecordWriter( nRecordType, pStream, nRecordTag, nRecordVer ),
414 0 : _nContentVer( 0 )
415 : {
416 0 : }
417 :
418 :
419 0 : SfxMultiVarRecordWriter::SfxMultiVarRecordWriter
420 : (
421 : SvStream* pStream, // Stream, in dem der Record angelegt wird
422 : sal_uInt16 nRecordTag, // Gesamt-Art-Kennung
423 : sal_uInt8 nRecordVer // Gesamt-Versions-Kennung
424 : )
425 :
426 : /* [Beschreibung]
427 :
428 : Legt in 'pStream' einen 'SfxMultiVarRecord' an, dessen Content-Gr"o\sen
429 : weder bekannt sind noch identisch sein m"ussen, sondern jeweils nach dem
430 : Streamen jedes einzelnen Contents errechnet werden sollen.
431 :
432 :
433 : [Anmerkung]
434 :
435 : Diese Methode ist nicht inline, da f"ur die Initialisierung eines
436 : <SvULongs>-Members zu viel Code generiert werden w"urde.
437 : */
438 :
439 : : SfxMultiFixRecordWriter( SFX_REC_TYPE_VARSIZE,
440 : pStream, nRecordTag, nRecordVer ),
441 0 : _nContentVer( 0 )
442 : {
443 0 : }
444 :
445 :
446 0 : SfxMultiVarRecordWriter::~SfxMultiVarRecordWriter()
447 :
448 : /* [Beschreibung]
449 :
450 : Der Dtor der Klasse <SfxMultiVarRecordWriter> schlie\st den Record
451 : automatisch, falls <SfxMultiVarRecordWriter::Close()> nicht bereits
452 : explizit gerufen wurde.
453 : */
454 :
455 : {
456 : // wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden
457 0 : if ( !_bHeaderOk )
458 0 : Close();
459 0 : }
460 :
461 :
462 0 : void SfxMultiVarRecordWriter::FlushContent_Impl()
463 :
464 : /* [Beschreibung]
465 :
466 : Interne Methode zum Abschlie\sen eines einzelnen Contents.
467 : */
468 :
469 : {
470 : // Versions-Kennung und Positions-Offset des aktuellen Contents merken;
471 : // das Positions-Offset ist relativ zur Startposition des ersten Contents
472 : assert(_aContentOfs.size() == static_cast<size_t>(_nContentCount)-1);
473 0 : _aContentOfs.resize(_nContentCount-1);
474 : _aContentOfs.push_back(
475 0 : SFX_REC_CONTENT_HEADER(_nContentVer,_nStartPos,_nContentStartPos));
476 0 : }
477 :
478 :
479 0 : void SfxMultiVarRecordWriter::NewContent()
480 :
481 : // siehe <SfxMultiFixRecordWriter>
482 :
483 : {
484 : // schon ein Content geschrieben?
485 0 : if ( _nContentCount )
486 0 : FlushContent_Impl();
487 :
488 : // neuen Content beginnen
489 0 : _nContentStartPos = _pStream->Tell();
490 0 : ++_nContentCount;
491 0 : }
492 :
493 :
494 0 : sal_uInt32 SfxMultiVarRecordWriter::Close( bool bSeekToEndOfRec )
495 :
496 : // siehe <SfxMiniRecordWriter>
497 :
498 : {
499 : // Header noch nicht geschrieben?
500 0 : if ( !_bHeaderOk )
501 : {
502 : // ggf. letzten Content abschlie\sen
503 0 : if ( _nContentCount )
504 0 : FlushContent_Impl();
505 :
506 : // Content-Offset-Tabelle schreiben
507 0 : sal_uInt32 nContentOfsPos = _pStream->Tell();
508 : //! darf man das so einr"ucken?
509 0 : for ( sal_uInt16 n = 0; n < _nContentCount; ++n )
510 0 : _pStream->WriteUInt32( _aContentOfs[n] );
511 :
512 : // SfxMultiFixRecordWriter::Close() "uberspringen!
513 0 : sal_uInt32 nEndPos = SfxSingleRecordWriter::Close( false );
514 :
515 : // eigenen Header schreiben
516 0 : _pStream->WriteUInt16( _nContentCount );
517 0 : if ( SFX_REC_TYPE_VARSIZE_RELOC == _nPreTag ||
518 0 : SFX_REC_TYPE_MIXTAGS_RELOC == _nPreTag )
519 0 : _pStream->WriteUInt32( static_cast<sal_uInt32>(nContentOfsPos - ( _pStream->Tell() + sizeof(sal_uInt32) )) );
520 : else
521 0 : _pStream->WriteUInt32( nContentOfsPos );
522 :
523 : // ans Ende des Records seeken bzw. am Ende des Headers bleiben
524 0 : if ( bSeekToEndOfRec )
525 0 : _pStream->Seek(nEndPos);
526 0 : return nEndPos;
527 : }
528 :
529 : // Record war bereits vorher geschlossen
530 0 : return 0;
531 : }
532 :
533 :
534 0 : void SfxMultiMixRecordWriter::NewContent
535 : (
536 : sal_uInt16 nContentTag, // Kennung f"ur die Art des Contents
537 : sal_uInt8 nContentVer // Kennung f"ur die Version des Contents
538 : )
539 :
540 : /* [Beschreibung]
541 :
542 : Mit dieser Methode wird in den Record ein neuer Content eingef"ugt
543 : und dessen Content-Tag sowie dessen Content-Version angegeben. Jeder,
544 : auch der 1. Record mu\s durch Aufruf dieser Methode eingeleitet werden.
545 : */
546 :
547 : {
548 : // ggf. vorherigen Record abschlie\sen
549 0 : if ( _nContentCount )
550 0 : FlushContent_Impl();
551 :
552 : // Tag vor den Content schreiben, Version und Startposition merken
553 0 : _nContentStartPos = _pStream->Tell();
554 0 : ++_nContentCount;
555 0 : _pStream->WriteUInt16( nContentTag );
556 0 : _nContentVer = nContentVer;
557 0 : }
558 :
559 :
560 0 : bool SfxMultiRecordReader::ReadHeader_Impl()
561 :
562 : /* [Beschreibung]
563 :
564 : Interne Methode zum Einlesen eines SfxMultiRecord-Headers, nachdem
565 : die Basisklasse bereits initialisiert und deren Header gelesen ist.
566 : Ggf. ist ein Error-Code am Stream gesetzt, im Fehlerfall wird jedoch
567 : nicht zur"uckge-seekt.
568 : */
569 :
570 : {
571 : // eigenen Header lesen
572 0 : _pStream->ReadUInt16( _nContentCount );
573 0 : _pStream->ReadUInt32( _nContentSize ); // Fix: jedes einzelnen, Var|Mix: Tabellen-Pos.
574 :
575 : // mu\s noch eine Tabelle mit Content-Offsets geladen werden?
576 0 : if ( _nRecordType != SFX_REC_TYPE_FIXSIZE )
577 : {
578 : // Tabelle aus dem Stream einlesen
579 0 : sal_uInt32 nContentPos = _pStream->Tell();
580 0 : if ( _nRecordType == SFX_REC_TYPE_VARSIZE_RELOC ||
581 0 : _nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
582 0 : _pStream->SeekRel( + _nContentSize );
583 : else
584 0 : _pStream->Seek( _nContentSize );
585 0 : _pContentOfs = new sal_uInt32[_nContentCount];
586 0 : memset(_pContentOfs, 0, _nContentCount*sizeof(sal_uInt32));
587 : //! darf man jetzt so einr"ucken
588 : #if defined(OSL_LITENDIAN)
589 0 : _pStream->Read( _pContentOfs, sizeof(sal_uInt32)*_nContentCount );
590 : #else
591 : for ( sal_uInt16 n = 0; n < _nContentCount; ++n )
592 : _pStream->ReadUInt32( _pContentOfs[n] );
593 : #endif
594 0 : _pStream->Seek( nContentPos );
595 : }
596 :
597 : // Header konnte gelesen werden, wenn am Stream kein Error gesetzt ist
598 0 : return !_pStream->GetError();
599 : }
600 :
601 :
602 0 : SfxMultiRecordReader::SfxMultiRecordReader( SvStream *pStream, sal_uInt16 nTag )
603 : : _pContentOfs(0)
604 : , _nContentSize(0)
605 : , _nContentCount(0)
606 : , _nContentNo(0)
607 : , _nContentTag( 0 )
608 0 : , _nContentVer( 0 )
609 : {
610 : // Position im Stream merken, um im Fehlerfall zur"uck-seeken zu k"onnen
611 0 : _nStartPos = pStream->Tell();
612 :
613 : // passenden Record suchen und Basisklasse initialisieren
614 0 : SfxSingleRecordReader::Construct_Impl( pStream );
615 0 : if ( SfxSingleRecordReader::FindHeader_Impl( SFX_REC_TYPE_FIXSIZE |
616 : SFX_REC_TYPE_VARSIZE | SFX_REC_TYPE_VARSIZE_RELOC |
617 : SFX_REC_TYPE_MIXTAGS | SFX_REC_TYPE_MIXTAGS_RELOC,
618 0 : nTag ) )
619 : {
620 : // eigenen Header dazu-lesen
621 0 : if ( !ReadHeader_Impl() )
622 : // nicht lesbar => als ung"ultig markieren und zur"uck-seeken
623 0 : SetInvalid_Impl( _nStartPos);
624 : }
625 0 : }
626 :
627 :
628 0 : SfxMultiRecordReader::~SfxMultiRecordReader()
629 : {
630 0 : delete[] _pContentOfs;
631 0 : }
632 :
633 :
634 0 : bool SfxMultiRecordReader::GetContent()
635 :
636 : /* [Beschreibung]
637 :
638 : Positioniert den Stream an den Anfang des n"chsten bzw. beim 1. Aufruf
639 : auf den Anfang des ersten Contents im Record und liest ggf. dessen
640 : Header ein.
641 :
642 : Liegt laut Record-Header kein Content mehr vor, wird sal_False zur"uck-
643 : gegeben. Trotz einem sal_True-Returnwert kann am Stream ein Fehlercode
644 : gesetzt sein, z.B. falls er unvorhergesehenerweise (kaputtes File)
645 : zuende ist.
646 : */
647 :
648 : {
649 : // noch ein Content vorhanden?
650 0 : if ( _nContentNo < _nContentCount )
651 : {
652 : // den Stream an den Anfang des Contents positionieren
653 0 : sal_uInt32 nOffset = _nRecordType == SFX_REC_TYPE_FIXSIZE
654 0 : ? _nContentNo * _nContentSize
655 0 : : SFX_REC_CONTENT_OFS(_pContentOfs[_nContentNo]);
656 0 : sal_uInt32 nNewPos = _nStartPos + nOffset;
657 : DBG_ASSERT( nNewPos >= _pStream->Tell(), "SfxMultiRecordReader::GetContent() - New position before current, to much data red!" );
658 :
659 : // #99366#: correct stream pos in every case;
660 : // the if clause was added by MT a long time ago,
661 : // maybe to 'repair' other corrupt documents; but this
662 : // gives errors when writing with 5.1 and reading with current
663 : // versions, so we decided to remove the if clause (KA-05/17/2002)
664 : // if ( nNewPos > _pStream->Tell() )
665 0 : _pStream->Seek( nNewPos );
666 :
667 : // ggf. Content-Header lesen
668 0 : if ( _nRecordType == SFX_REC_TYPE_MIXTAGS ||
669 0 : _nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
670 : {
671 : _nContentVer = sal::static_int_cast< sal_uInt8 >(
672 0 : SFX_REC_CONTENT_VER(_pContentOfs[_nContentNo]));
673 0 : _pStream->ReadUInt16( _nContentTag );
674 : }
675 :
676 : // ContentNo weiterz"ahlen
677 0 : ++_nContentNo;
678 0 : return true;
679 : }
680 :
681 0 : return false;
682 : }
683 :
684 :
685 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|