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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 959 SfxMultiRecordReader::~SfxMultiRecordReader() 960 { 961 delete[] _pContentOfs; 962 } 963 964 //------------------------------------------------------------------------- 965 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