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