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 #ifndef _SFXFILEREC_HXX 29 #define _SFXFILEREC_HXX 30 31 //========================================================================= 32 33 #include "svl/svldllapi.h" 34 #include <tools/debug.hxx> 35 #include <tools/stream.hxx> 36 #include <svl/svarray.hxx> 37 38 SV_DECL_VARARR( SfxUINT32s, sal_uInt32, 8, 8 ) 39 40 //------------------------------------------------------------------------ 41 42 #define SFX_BOOL_DONTCARE sal_Bool(2) // Don't-Care-Wert f"ur BOOLs 43 44 #define SFX_REC_PRETAG_EXT sal_uInt8(0x00) // Pre-Tag f"ur Extended-Records 45 #define SFX_REC_PRETAG_EOR sal_uInt8(0xFF) // Pre-Tag f"ur End-Of-Records 46 47 #define SFX_REC_TYPE_NONE sal_uInt8(0x00) // unbekannter Record-Typ 48 #define SFX_REC_TYPE_FIRST sal_uInt8(0x01) 49 #define SFX_REC_TYPE_SINGLE sal_uInt8(0x01) // Single-Content-Record 50 #define SFX_REC_TYPE_FIXSIZE sal_uInt8(0x02) // Fix-Size-Multi-Content-Record 51 #define SFX_REC_TYPE_VARSIZE_RELOC sal_uInt8(0x03) // variable Rec-Size 52 #define SFX_REC_TYPE_VARSIZE sal_uInt8(0x04) // alt (nicht verschiebbar) 53 #define SFX_REC_TYPE_MIXTAGS_RELOC sal_uInt8(0x07) // Mixed Tag Content-Record 54 #define SFX_REC_TYPE_MIXTAGS sal_uInt8(0x08) // alt (nicht verschiebbar) 55 #define SFX_REC_TYPE_LAST sal_uInt8(0x08) 56 #define SFX_REC_TYPE_MINI 0x100 // Mini-Record 57 #define SFX_REC_TYPE_DRAWENG 0x400 // Drawing-Engine-Record 58 #define SFX_REC_TYPE_EOR 0xF00 // End-Of-Records 59 60 //------------------------------------------------------------------------ 61 62 #define SFX_REC_HEADERSIZE_MINI 4 // Gr"o\se des Mini-Record-Headers 63 #define SFX_REC_HEADERSIZE_SINGLE 4 // zzgl. HEADERSIZE_MINI => 8 64 #define SFX_REC_HEADERSIZE_MULTI 6 // zzgl. HEADERSIZE_SINGLE => 14 65 66 //------------------------------------------------------------------------ 67 68 #ifndef DBG 69 #ifdef DBG_UTIL 70 #define DBG(x) x 71 #else 72 #define DBG(x) 73 #endif 74 #endif 75 76 //------------------------------------------------------------------------ 77 78 /* [Fileformat] 79 80 Jeder Record beginnt mit einem Byte, dem sogenannten 'Pre-Tag'. 81 82 Ist dieses 'Pre-Tag' == 0x00, dann handelt es sich um einen Extended- 83 Record, dessen Typ durch ein weiteres Byte an Position 5 n�her 84 beschrieben wird: 85 86 0x01: SfxSingleRecord 87 0x02: SfxMultiFixRecord 88 0x03+0x04: SfxMultiVarRecord 89 0x07+0x08: SfxMultiMixRecord 90 (Alle weiteren Record-Typ-Kennungen sind reserviert.) 91 92 I.d.R. werden File-Formate schon aus Performance-Gr"unden so aufgebaut, 93 da\s beim Lesen jeweils vorher schon feststeht, welcher Record-Typ 94 vorliegt. Diese Kennung dient daher hautps"achlich der "Uberpr"ufung 95 und File-Viewern, die das genaue File-Format (unterhalb der Records) 96 nicht kennen. 97 98 Der 'SfxMiniRecordReader' verf"ugt dazu auch "uber eine statische 99 Methode 'ScanRecordType()', mit der festgestellt werden kann, welcher 100 Record-Typ in dem "ubergebenen Stream zu finden ist. 101 102 Ein 'Pre-Tag' mit dem Wert 0xFF ist als Terminator reserviert. 103 Terminatoren werden verwendet, um das Suchen nach einem speziellen 104 Record zu terminieren, d.h. ist er bis dorthin nicht gefunden, wird 105 auch nicht weitergesucht. 106 107 Bei allen anderen Werten des 'Pre-Tags' (also von 0x01 bis 0xFE) 108 handelt es sich um einen zum SW3 kompatbilen Record, der hier 109 'SfxMiniRecord' genannt wird, er kann daher mit einem <SfxMiniRecordReader> 110 gelesen werden. 111 112 Beginnt ein Record mit 0x44 k"onnte es sich um einen Drawing-Engine- 113 Record handeln. Dies ist dann der Fall, wenn die folgenden drei Bytes 114 die Zeichenkette 'RMD' bzw. 'RVW' ergeben (zusammen mit 'D'==0x44 115 ergibt dies die K"urzel f"ur 'DRaw-MoDel' bzw. 'DRaw-VieW'). Records 116 dieser Art k"onnen von den hier dargestellten Klassen weder gelesen, 117 noch in irgendeiner Weise interpretiert werden. Einzig die Methode 118 'ScanRecordType()' kann sie erkennen - weitere Behandlung obliegt 119 jedoch der Anwendungsprogrammierung. 120 121 Diese drei Bytes an den Positionen 2 bis 4 enthalten normalerweise 122 die Gr"o\se des Records ohne Pre-Tag und Gr"o\sen-Bytes selbst, 123 also die Restgr"o\se nach diesem 4-Byte-Header. 124 125 Struktur des Mini-Records: 126 127 1 sal_uInt8 Pre-Tag 128 3 sal_uInt8 OffsetToEndOfRec 129 OffsetToEndOfRec* 1 sal_uInt8 Content 130 131 Bei den Extended-Reords folgt auf diesen 4-Byte-Header ein erweiterter 132 Header, der zun"achst den o.g. Record-Typ, dann eine Versions-Kennung 133 sowie ein Tag enth"alt, welches den Inhalt kennzeichnet. 134 135 Struktur des Extended-Records: 136 137 1 sal_uInt8 Pre-Tag (==0x00) 138 3 sal_uInt8 OffsetToEndOfRec 139 OffsetToEndOfRec* 1 sal_uInt8 Content 140 1 sal_uInt8 Record-Type 141 1 sal_uInt8 Version 142 2 sal_uInt8 Tag 143 ContentSize* 1 sal_uInt8 Content 144 145 (ContentSize = OffsetToEndOfRec - 8) 146 147 [Anmerkung] 148 149 Der Aufbau der Records wird wie folgt begr"undet: 150 151 Der SW-Record-Typ war zuerst vorhanden, mu\ste also 1:1 "ubernommen 152 werden. Zum Gl"uck wurden einige Record-Tags nicht verwendet, (Z.B. 153 0x00 und 0xFF). 154 => 1. Byte 0x00 kann als Kennung f"ur erweiterten Record verwendet werden 155 => 1. Byte 0xFF kann f"ur besondere Zwecke verwendet werden 156 157 Egal welcher Record-Typ vorliegt, sollte eine Erkennung des Typs, ein 158 Auslesen des Headers und ein "uberpspringen des Records m"oglich sein, 159 ohne zu"uck-seeken zu m"ussen und ohne "uberfl"ussige Daten lesen zu 160 m"ussen. 161 => die Bytes 2-4 werden bei allen Records als Offset zum Ende des 162 Records interpretiert, so da\s die Gesamt-Recors-Size sich wie 163 folgt berechnet: sizeof(sal_uInt32) + OffsetToEndOfRec 164 165 Die Records sollten einfach zu parsen un einheitlich aufgebaut sein. 166 => Sie bauen aufeinander auf, so ist z.B. der SfxMiniRecord in jedem 167 anderen enthalten. 168 169 Die Records sollten auch von denen der Drawing Enginge unterscheidbar 170 sein. Diese beginnen mit 'DRMD' und 'DRVW'. 171 => Mini-Records mit dem Pre-Tag 'D' d"urfen maximal 4MB gro\s sein, 172 um nicht in diesen Kennungs-Bereich zu reichen. 173 174 [Erweiterungen] 175 176 Es ist geplant das File-Format so zu erweitern, da\s das High-Nibble 177 des Record-Typs der erweiterten Records besondere Aufgaben "ubernehmen 178 soll. Zum Beispiel ist geplant, Record-Contents als 'nur aus Records 179 bestehend' zu kennzeichnen. Ein File-Viewer k"onnte sich dann automatisch 180 durch solche Strukturen 'hangeln', ohne Gefahr zu laufen, auf Daten 181 zu sto\sen, die sich zwar als Records interpretieren lassen, aber 182 tats"achlis als 'flache' Daten geschrieben wurden. Die m"ogliche 183 Erweiterung wird schon jetzt insofern vorbereitet, als da\s das 184 High-Nibble des Typs bei Vergleichen nicht ber"ucksichtigt wird. 185 */ 186 187 //------------------------------------------------------------------------ 188 189 class SVL_DLLPUBLIC SfxMiniRecordWriter 190 191 /* [Beschreibung] 192 193 Mit Instanzen dieser Klasse kann ein einfacher Record in einen Stream 194 geschrieben werden, der sich durch ein sal_uInt8-Tag identifiziert, sowie 195 seine eigene L"ange speichert und somit auch von "alteren Versionen 196 bzw. Readern, die diesen Record-Type (Tag) nicht kennen, "ubersprungen 197 werden kann. Es wird keine Version-Nummer gespeichert. 198 199 Alternativ kann die Gr"o\se fest angegeben werden oder sie wird 200 automatisch aus der Differenz der Tell()-Angaben vor und nach dem 201 Streamen des Inhalts ermittelt. 202 203 Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen 204 neue Versionen die Daten der "alteren immer komplett enthalten, 205 es d"urfen allenfalls neue Daten hintenan geh"angt werden! 206 207 [Fileformat] 208 209 1* sal_uInt8 Content-Tag (!= 0) 210 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes 211 SizeOfContent* sal_uInt8 Content 212 213 [Beispiel] 214 215 { 216 SfxMiniRecordWriter aRecord( pStream, MY_TAG_X ); 217 *aRecord << aMember1; 218 *aRecord << aMember2; 219 } 220 */ 221 222 { 223 protected: 224 SvStream* _pStream; // <SvStream>, in dem der Record liegt 225 sal_uInt32 _nStartPos; // Start-Position des Gesamt-Records im Stream 226 FASTBOOL _bHeaderOk; /* sal_True, wenn der Header schon geschrieben ist; 227 bei DBG_UTIL wird SFX_BOOL_DONTCARE ver- 228 wendet, um die Gr"o\se von Fix-Sized-Records 229 zu pr"ufen. */ 230 sal_uInt8 _nPreTag; // in den Header zu schreibendes 'Pre-Tag' 231 232 public: 233 inline SfxMiniRecordWriter( SvStream *pStream, 234 sal_uInt8 nTag ); 235 inline SfxMiniRecordWriter( SvStream *pStream, sal_uInt8 nTag, 236 sal_uInt32 nSize ); 237 238 inline ~SfxMiniRecordWriter(); 239 240 inline SvStream& operator*() const; 241 242 inline void Reset(); 243 244 sal_uInt32 Close( FASTBOOL bSeekToEndOfRec = sal_True ); 245 246 private: 247 // not implementend, not allowed 248 SfxMiniRecordWriter( const SfxMiniRecordWriter& ); 249 SfxMiniRecordWriter& operator=(const SfxMiniRecordWriter&); 250 }; 251 252 //------------------------------------------------------------------------ 253 254 class SVL_DLLPUBLIC SfxMiniRecordReader 255 256 /* [Beschreibung] 257 258 Mit Instanzen dieser Klasse kann ein einfacher Record aus einem Stream 259 gelesen werden, der mit der Klasse <SfxRecordWriter> geschrieben wurde. 260 261 Es ist auch m"oglich, den Record zu "uberspringen, ohne sein internes 262 Format zu kennen. 263 264 [Beispiel] 265 266 { 267 SfxMiniRecordReader aRecord( pStream ); 268 switch ( aRecord.GetTag() ) 269 { 270 case MY_TAG_X: 271 *aRecord >> aMember1; 272 *aRecord >> aMember2; 273 break; 274 275 ... 276 } 277 } 278 */ 279 280 { 281 protected: 282 SvStream* _pStream; // <SvStream>, aus dem gelesen wird 283 sal_uInt32 _nEofRec; // Position direkt hinter dem Record 284 FASTBOOL _bSkipped; // sal_True: der Record wurde explizit geskippt 285 sal_uInt8 _nPreTag; // aus dem Header gelesenes Pre-Tag 286 287 // Drei-Phasen-Ctor f"ur Subklassen 288 SfxMiniRecordReader() {} 289 void Construct_Impl( SvStream *pStream, sal_uInt8 nTag ) 290 { 291 _pStream = pStream; 292 _bSkipped = sal_False; 293 _nPreTag = nTag; 294 } 295 inline FASTBOOL SetHeader_Impl( sal_uInt32 nHeader ); 296 297 // als ung"ultig markieren und zur"uck-seeken 298 void SetInvalid_Impl( sal_uInt32 nRecordStartPos ) 299 { 300 _nPreTag = SFX_REC_PRETAG_EOR; 301 _pStream->Seek( nRecordStartPos ); 302 } 303 304 public: 305 static sal_uInt16 ScanRecordType( SvStream *pStream ); 306 307 SfxMiniRecordReader( SvStream *pStream ); 308 SfxMiniRecordReader( SvStream *pStream, sal_uInt8 nTag ); 309 inline ~SfxMiniRecordReader(); 310 311 inline sal_uInt8 GetTag() const; 312 inline FASTBOOL IsValid() const; 313 314 inline SvStream& operator*() const; 315 316 inline void Skip(); 317 318 private: 319 // not implementend, not allowed 320 SfxMiniRecordReader( const SfxMiniRecordReader& ); 321 SfxMiniRecordReader& operator=(const SfxMiniRecordReader&); 322 }; 323 324 //------------------------------------------------------------------------ 325 326 class SVL_DLLPUBLIC SfxSingleRecordWriter: public SfxMiniRecordWriter 327 328 /* [Beschreibung] 329 330 Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben 331 werden, dessen einziger Inhalt sich durch ein sal_uInt16-Tag und eine 332 sal_uInt8-Versions-Nummer identifiziert, sowie seine eigene L"ange speichert 333 und somit auch von "alteren Versionen bzw. Readern, die diesen 334 Record-Type (Tag) nicht kennen, "ubersprungen werden kann. 335 336 Alternativ kann die Gr"o\se fest angegeben werden oder sie wird 337 automatisch aus der Differenz der Tell()-Angaben vor und nach dem 338 Streamen des Inhalts ermittelt. 339 340 Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen 341 neue Versionen die Daten der "alteren immer komplett enthalten, 342 es d"urfen allenfalls neue Daten hintenan geh"angt werden! 343 344 [Fileformat] 345 346 1* sal_uInt8 Pre-Tag (!= 0) 347 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes 348 1* sal_uInt8 Record-Type (==SFX_REC_TYPE_SINGLE) 349 1* sal_uInt8 Content-Version 350 1* sal_uInt16 Content-Tag 351 SizeOfContent* sal_uInt8 Content 352 353 [Beispiel] 354 355 { 356 SfxSingleRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION ); 357 *aRecord << aMember1; 358 *aRecord << aMember2; 359 } 360 */ 361 362 { 363 protected: 364 SfxSingleRecordWriter( sal_uInt8 nRecordType, 365 SvStream *pStream, 366 sal_uInt16 nTag, sal_uInt8 nCurVer ); 367 368 public: 369 SfxSingleRecordWriter( SvStream *pStream, 370 sal_uInt16 nTag, sal_uInt8 nCurVer ); 371 SfxSingleRecordWriter( SvStream *pStream, 372 sal_uInt16 nTag, sal_uInt8 nCurVer, 373 sal_uInt32 nSize ); 374 375 inline void Reset(); 376 377 sal_uInt32 Close( FASTBOOL bSeekToEndOfRec = sal_True ); 378 }; 379 380 //------------------------------------------------------------------------ 381 382 class SVL_DLLPUBLIC SfxSingleRecordReader: public SfxMiniRecordReader 383 384 /* [Beschreibung] 385 386 Mit Instanzen dieser Klasse kann ein einfacher Record aus einem Stream 387 gelesen werden, der mit der Klasse <SfxSingleRecordWriter> geschrieben 388 wurde. 389 390 Es ist auch m"oglich, den Record zu "uberspringen, ohne sein internes 391 Format zu kennen. 392 393 [Beispiel] 394 395 { 396 SfxSingleRecordReader aRecord( pStream ); 397 switch ( aRecord.GetTag() ) 398 { 399 case MY_TAG_X: 400 aRecord >> aMember1; 401 if ( aRecord.HasVersion(2) ) 402 *aRecord >> aMember2; 403 break; 404 405 ... 406 } 407 } 408 */ 409 410 { 411 protected: 412 sal_uInt16 _nRecordTag; // Art des Gesamt-Inhalts 413 sal_uInt8 _nRecordVer; // Version des Gesamt-Inhalts 414 sal_uInt8 _nRecordType; // Record Type aus dem Header 415 416 // Drei-Phasen-Ctor f"ur Subklassen 417 SfxSingleRecordReader() {} 418 void Construct_Impl( SvStream *pStream ) 419 { 420 SfxMiniRecordReader::Construct_Impl( 421 pStream, SFX_REC_PRETAG_EXT ); 422 } 423 FASTBOOL FindHeader_Impl( sal_uInt16 nTypes, sal_uInt16 nTag ); 424 FASTBOOL ReadHeader_Impl( sal_uInt16 nTypes ); 425 426 public: 427 SfxSingleRecordReader( SvStream *pStream ); 428 SfxSingleRecordReader( SvStream *pStream, sal_uInt16 nTag ); 429 430 inline sal_uInt16 GetTag() const; 431 432 inline sal_uInt8 GetVersion() const; 433 inline FASTBOOL HasVersion( sal_uInt16 nVersion ) const; 434 }; 435 436 //------------------------------------------------------------------------ 437 438 class SVL_DLLPUBLIC SfxMultiFixRecordWriter: public SfxSingleRecordWriter 439 440 /* [Beschreibung] 441 442 Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben 443 werden, der seine eigene L"ange speichert und somit auch von "alteren 444 Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen, 445 "ubersprungen werden kann. 446 447 Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben 448 Version, die einmalig (stellvertretend f"ur alle) im Header des Records 449 identifiziert werden. Alle Inhalte haben eine vorher bekannte und 450 identische L"ange. 451 452 Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen 453 neue Versionen die Daten der "alteren immer komplett enthalten, 454 es d"urfen allenfalls neue Daten hinten angeh"angt werden! Hier sind 455 damit selbstverst"andlich nur die Daten der einzelnen Inhalte gemeint, 456 die Anzahl der Inhalte ist selbstverst"andlich variabel und sollte 457 von lesenden Applikationen auch so behandelt werden. 458 459 [Fileformat] 460 461 1* sal_uInt8 Pre-Tag (==0) 462 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes 463 1* sal_uInt8 Record-Type (==SFX_REC_TYPE_FIXSIZE) 464 1* sal_uInt8 Content-Version 465 1* sal_uInt16 Content-Tag 466 1* sal_uInt16 NumberOfContents 467 1* sal_uInt32 SizeOfEachContent 468 NumberOfContents* ( 469 SizeOfEachContent sal_uInt8 Content 470 ) 471 472 [Beispiel] 473 474 { 475 SfxMultiFixRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION ); 476 for ( sal_uInt16 n = 0; n < Count(); ++n ) 477 { 478 aRecord.NewContent(); 479 *aRecord << aMember1[n]; 480 *aRecord << aMember2[n]; 481 } 482 } 483 */ 484 485 { 486 protected: 487 sal_uInt32 _nContentStartPos; /* Startposition des jeweiligen 488 Contents - nur bei DBG_UTIL 489 und f"ur Subklassen */ 490 sal_uInt32 _nContentSize; // Gr"o\se jedes Contents 491 sal_uInt16 _nContentCount; // jeweilige Anzahl der Contents 492 493 SfxMultiFixRecordWriter( sal_uInt8 nRecordType, 494 SvStream *pStream, 495 sal_uInt16 nTag, sal_uInt8 nCurVer, 496 sal_uInt32 nContentSize ); 497 498 public: 499 SfxMultiFixRecordWriter( SvStream *pStream, 500 sal_uInt16 nTag, sal_uInt8 nCurVer, 501 sal_uInt32 nContentSize ); 502 inline ~SfxMultiFixRecordWriter(); 503 504 inline void NewContent(); 505 506 inline void Reset(); 507 508 sal_uInt32 Close( FASTBOOL bSeekToEndOfRec = sal_True ); 509 }; 510 511 //------------------------------------------------------------------------ 512 513 class SVL_DLLPUBLIC SfxMultiVarRecordWriter: public SfxMultiFixRecordWriter 514 515 /* [Beschreibung] 516 517 Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben 518 werden, der seine eigene L"ange speichert und somit auch von "alteren 519 Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen, 520 "ubersprungen werden kann. 521 522 Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben 523 Version, die einmalig (stellvertretend f"ur alle) im Header des Records 524 identifiziert werden. Die L"ange f"ur jeden einzelnen Inhalt wird 525 automatisch berechnet und gespeichert, so da\s auch einzelne Inhalte 526 "ubersprungen werden k"onnen, ohne sie interpretieren zu m"ussen. 527 528 Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen 529 neue Versionen die Daten der "alteren immer komplett enthalten, 530 es d"urfen allenfalls neue Daten hinten angeh"angt werden! 531 532 [Fileformat] 533 534 1* sal_uInt8 Pre-Tag (==0) 535 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes 536 1* sal_uInt8 Record-Type (==SFX_FILETYPE_TYPE_VARSIZE) 537 1* sal_uInt8 Content-Version 538 1* sal_uInt16 Content-Tag 539 1* sal_uInt16 NumberOfContents 540 1* sal_uInt32 OffsetToOfsTable 541 NumberOfContents* ( 542 ContentSize* sal_uInt8 Content 543 ) 544 NumberOfContents* sal_uInt32 ContentOfs (je per <<8 verschoben) 545 546 [Beispiel] 547 548 { 549 SfxMultiVarRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION ); 550 for ( sal_uInt16 n = 0; n < Count(); ++n ) 551 { 552 aRecord.NewContent(); 553 *aRecord << aMember1[n]; 554 *aRecord << aMember2[n]; 555 } 556 } 557 */ 558 559 { 560 protected: 561 SfxUINT32s _aContentOfs; 562 sal_uInt16 _nContentVer; // nur f"ur SfxMultiMixRecordWriter 563 564 SfxMultiVarRecordWriter( sal_uInt8 nRecordType, 565 SvStream *pStream, 566 sal_uInt16 nRecordTag, 567 sal_uInt8 nRecordVer ); 568 569 void FlushContent_Impl(); 570 571 public: 572 SfxMultiVarRecordWriter( SvStream *pStream, 573 sal_uInt16 nRecordTag, 574 sal_uInt8 nRecordVer ); 575 virtual ~SfxMultiVarRecordWriter(); 576 577 void NewContent(); 578 579 virtual sal_uInt32 Close( FASTBOOL bSeekToEndOfRec = sal_True ); 580 }; 581 582 //------------------------------------------------------------------------ 583 584 class SVL_DLLPUBLIC SfxMultiMixRecordWriter: public SfxMultiVarRecordWriter 585 586 /* [Beschreibung] 587 588 Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben 589 werden, der seine eigene L"ange speichert und somit auch von "alteren 590 Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen, 591 "ubersprungen werden kann. 592 593 Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben 594 Version, die einmalig (stellvertretend f"ur alle) im Header des Records 595 identifiziert werden. Alle Inhalte haben eine vorher bekannte und 596 identische L"ange. 597 598 Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen 599 neue Versionen die Daten der "alteren immer komplett enthalten, 600 es d"urfen allenfalls neue Daten hinten angeh"angt werden! 601 602 [Fileformat] 603 604 1* sal_uInt8 Pre-Tag (==0) 605 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes 606 1* sal_uInt8 Record-Type (==SFX_REC_TYPE_MIXTAGS) 607 1* sal_uInt8 Content-Version 608 1* sal_uInt16 Record-Tag 609 1* sal_uInt16 NumberOfContents 610 1* sal_uInt32 OffsetToOfsTable 611 NumberOfContents* ( 612 1* sal_uInt16 Content-Tag 613 ContentSize* sal_uInt8 Content 614 ) 615 NumberOfContents* sal_uInt32 ( ContentOfs << 8 + Version ) 616 */ 617 618 { 619 public: 620 inline SfxMultiMixRecordWriter( SvStream *pStream, 621 sal_uInt16 nRecordTag, 622 sal_uInt8 nRecordVer ); 623 624 void NewContent( sal_uInt16 nTag, sal_uInt8 nVersion ); 625 626 // private: geht nicht, da einige Compiler dann auch vorherige privat machen 627 void NewContent() 628 { DBG_ERROR( "NewContent() only allowed with args" ); } 629 }; 630 631 //------------------------------------------------------------------------ 632 633 class SVL_DLLPUBLIC SfxMultiRecordReader: public SfxSingleRecordReader 634 635 /* [Beschreibung] 636 637 Mit Instanzen dieser Klasse kann ein aus mehreren Contents bestehender 638 Record aus einem Stream gelesen werden, der mit einer der Klassen 639 <SfxMultiFixRecordWriter>, <SfxMultiVarRecordWriter> oder 640 <SfxMultiMixRecordWriter> geschrieben wurde. 641 642 Es ist auch m"oglich, den Record oder einzelne Contents zu "uberspringen, 643 ohne das jeweilis interne Format zu kennen. 644 645 [Beispiel] 646 647 { 648 SfxMultiRecordReader aRecord( pStream ); 649 for ( sal_uInt16 nRecNo = 0; aRecord.GetContent(); ++nRecNo ) 650 { 651 switch ( aRecord.GetTag() ) 652 { 653 case MY_TAG_X: 654 X *pObj = new X; 655 *aRecord >> pObj.>aMember1; 656 if ( aRecord.HasVersion(2) ) 657 *aRecord >> pObj->aMember2; 658 Append( pObj ); 659 break; 660 661 ... 662 } 663 } 664 } 665 */ 666 667 { 668 sal_uInt32 _nStartPos; // Start-Position des Records 669 sal_uInt32* _pContentOfs; // Offsets der Startpositionen 670 sal_uInt32 _nContentSize; // Size jedes einzelnen / Tabellen-Pos 671 sal_uInt16 _nContentCount; // Anzahl der Contents im Record 672 sal_uInt16 _nContentNo; /* der Index des aktuellen Contents 673 enth"alt jeweils den Index des 674 Contents, der beim n"achsten 675 GetContent() geholt wird */ 676 sal_uInt16 _nContentTag; // Art-Kennung des aktuellen Contents 677 sal_uInt8 _nContentVer; // Versions-Kennung des akt. Contents 678 679 FASTBOOL ReadHeader_Impl(); 680 681 public: 682 SfxMultiRecordReader( SvStream *pStream ); 683 SfxMultiRecordReader( SvStream *pStream, sal_uInt16 nTag ); 684 ~SfxMultiRecordReader(); 685 686 FASTBOOL GetContent(); 687 inline sal_uInt16 GetContentTag(); 688 inline sal_uInt8 GetContentVersion() const; 689 inline FASTBOOL HasContentVersion( sal_uInt16 nVersion ) const; 690 691 inline sal_uInt32 ContentCount() const; 692 }; 693 694 //========================================================================= 695 696 inline SfxMiniRecordWriter::SfxMiniRecordWriter 697 ( 698 SvStream* pStream, // Stream, in dem der Record angelegt wird 699 sal_uInt8 nTag // Record-Tag zwischen 0x01 und 0xFE 700 ) 701 702 /* [Beschreibung] 703 704 Legt in 'pStream' einen 'SfxMiniRecord' an, dessen Content-Gr"o\se 705 nicht bekannt ist, sondern nach dam Streamen des Contents errechnet 706 werden soll. 707 */ 708 709 : _pStream( pStream ), 710 _nStartPos( pStream->Tell() ), 711 _bHeaderOk(sal_False), 712 _nPreTag( nTag ) 713 { 714 DBG_ASSERT( _nPreTag != 0xFF, "invalid Tag" ); 715 DBG( DbgOutf( "SfxFileRec: writing record to %ul", pStream->Tell() ) ); 716 717 pStream->SeekRel( + SFX_REC_HEADERSIZE_MINI ); 718 } 719 720 //------------------------------------------------------------------------- 721 722 inline SfxMiniRecordWriter::SfxMiniRecordWriter 723 ( 724 SvStream* pStream, // Stream, in dem der Record angelegt wird 725 sal_uInt8 nTag, // Record-Tag zwischen 0x01 und 0xFE 726 sal_uInt32 nSize // Gr"o\se der Daten in Bytes 727 ) 728 729 /* [Beschreibung] 730 731 Legt in 'pStream' einen 'SfxMiniRecord' an, dessen Content-Gr"o\se 732 von vornherein bekannt ist. 733 */ 734 735 : _pStream( pStream ), 736 // _nTag( uninitialized ), 737 // _nStarPos( uninitialized ), 738 _bHeaderOk(SFX_BOOL_DONTCARE) 739 { 740 DBG_ASSERT( nTag != 0 && nTag != 0xFF, "invalid Tag" ); 741 DBG(_nStartPos = pStream->Tell()); 742 DBG( DbgOutf( "SfxFileRec: writing record to %ul", _nStartPos ) ); 743 744 *pStream << ( ( nTag << 24 ) | nSize ); 745 } 746 747 //------------------------------------------------------------------------- 748 749 inline SfxMiniRecordWriter::~SfxMiniRecordWriter() 750 751 /* [Beschreibung] 752 753 Der Dtor der Klasse <SfxMiniRecordWriter> schlie\st den Record 754 automatisch, falls <SfxMiniRecordWriter::Close()> nicht bereits 755 explizit gerufen wurde. 756 */ 757 758 { 759 // wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden 760 if ( !_bHeaderOk DBG(||sal_True) ) 761 Close(); 762 } 763 764 //------------------------------------------------------------------------- 765 766 inline SvStream& SfxMiniRecordWriter::operator*() const 767 768 /* [Beschreibung] 769 770 Dieser Operator liefert den Stream, in dem der Record liegt. 771 Der Record darf noch nicht geschlossen worden sein. 772 */ 773 774 { 775 DBG_ASSERT( !_bHeaderOk, "getting Stream of closed record" ); 776 return *_pStream; 777 } 778 779 //------------------------------------------------------------------------- 780 781 inline void SfxMiniRecordWriter::Reset() 782 { 783 _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI ); 784 _bHeaderOk = sal_False; 785 } 786 787 //========================================================================= 788 789 inline SfxMiniRecordReader::~SfxMiniRecordReader() 790 791 /* [Beschreibung] 792 793 Der Dtor der Klasse <SfxMiniRecordReader> positioniert den Stream 794 automatisch auf die Position direkt hinter dem Record, falls nicht 795 <SfxMiniRecordReader::Skip()> bereits explizit gerufen wurde. 796 */ 797 798 { 799 // noch nicht explizit ans Ende gesprungen? 800 if ( !_bSkipped ) 801 Skip(); 802 } 803 804 //------------------------------------------------------------------------- 805 806 inline void SfxMiniRecordReader::Skip() 807 808 /* [Beschreibung] 809 810 Mit dieser Methode wird der Stream direkt hinter das Ende des Records 811 positioniert. 812 */ 813 814 { 815 _pStream->Seek(_nEofRec); 816 _bSkipped = sal_True; 817 } 818 819 //------------------------------------------------------------------------- 820 821 inline sal_uInt8 SfxMiniRecordReader::GetTag() const 822 823 /* [Beschreibung] 824 825 Liefert des aus dem Header gelesene Pre-Tag des Records. Dieses kann 826 auch SFX_REC_PRETAG_EXT oder SFX_REC_PRETAG_EOR sein, im 827 letzteren Fall ist am Stream der Fehlercode ERRCODE_IO_WRONGFORMAT 828 gesetzt. SFX_REC_PRETAG_EXT ist g"ultig, da diese extended-Records 829 nur eine Erweiterung des SfxMiniRecord darstellen. 830 */ 831 832 { 833 return _nPreTag; 834 } 835 836 //------------------------------------------------------------------------- 837 838 inline FASTBOOL SfxMiniRecordReader::IsValid() const 839 840 /* [Beschreibung] 841 842 Hiermit kann abgefragt werden, ob der Record erfolgreich aus dem 843 Stream konstruiert werden konnte, der Header also f"ur diesen Record-Typ 844 passend war. 845 */ 846 847 { 848 return _nPreTag != SFX_REC_PRETAG_EOR; 849 } 850 851 //------------------------------------------------------------------------- 852 853 inline SvStream& SfxMiniRecordReader::operator*() const 854 855 /* [Beschreibung] 856 857 Dieser Operator liefert den Stream in dem der Record liegt. 858 Die aktuelle Position des Streams mu\s innerhalb des Records liegen. 859 */ 860 861 { 862 DBG_ASSERT( _pStream->Tell() < _nEofRec, "read behind record" ); 863 return *_pStream; 864 } 865 866 //========================================================================= 867 868 inline sal_uInt32 SfxSingleRecordWriter::Close( FASTBOOL bSeekToEndOfRec ) 869 870 // siehe <SfxMiniRecordWriter::Close(FASTBOOL)> 871 872 { 873 sal_uInt32 nRet = 0; 874 875 // wurde der Header noch nicht geschrieben? 876 if ( !_bHeaderOk ) 877 { 878 // Basisklassen-Header schreiben 879 sal_uInt32 nEndPos = SfxMiniRecordWriter::Close( bSeekToEndOfRec ); 880 881 // ggf. ans Ende des eigenen Headers seeken oder hinter Rec bleiben 882 if ( !bSeekToEndOfRec ) 883 _pStream->SeekRel( SFX_REC_HEADERSIZE_SINGLE ); 884 nRet = nEndPos; 885 } 886 #ifdef DBG_UTIL 887 else 888 // Basisklassen-Header pr"ufen 889 SfxMiniRecordWriter::Close( bSeekToEndOfRec ); 890 #endif 891 892 // Record war bereits geschlossen 893 // nRet = 0; 894 return nRet; 895 } 896 897 //------------------------------------------------------------------------- 898 899 inline void SfxSingleRecordWriter::Reset() 900 { 901 _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI + 902 SFX_REC_HEADERSIZE_SINGLE ); 903 _bHeaderOk = sal_False; 904 } 905 906 //========================================================================= 907 908 inline sal_uInt16 SfxSingleRecordReader::GetTag() const 909 910 /* [Beschreibung] 911 912 Liefert des aus dem Header gelesene Tag f"ur den Gesamt-Record. 913 */ 914 915 { 916 return _nRecordTag; 917 } 918 919 //------------------------------------------------------------------------- 920 921 inline sal_uInt8 SfxSingleRecordReader::GetVersion() const 922 923 /* [Beschreibung] 924 925 Liefert die Version des aus dem Stream gelesenen Records. 926 */ 927 928 { 929 return _nRecordVer; 930 } 931 932 //------------------------------------------------------------------------- 933 934 inline FASTBOOL SfxSingleRecordReader::HasVersion( sal_uInt16 nVersion ) const 935 936 /* [Beschreibung] 937 938 Stellt fest, ob der aus dem Stream gelese Record in der Version 939 'nVersion' oder h"oher vorliegt. 940 */ 941 942 { 943 return _nRecordVer >= nVersion; 944 } 945 946 //========================================================================= 947 948 inline SfxMultiFixRecordWriter::~SfxMultiFixRecordWriter() 949 950 /* [Beschreibung] 951 952 Der Dtor der Klasse <SfxMultiFixRecordWriter> schlie\st den Record 953 automatisch, falls <SfxMutiFixRecordWriter::Close()> nicht bereits 954 explizit gerufen wurde. 955 */ 956 957 { 958 // wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden 959 if ( !_bHeaderOk ) 960 Close(); 961 } 962 963 //------------------------------------------------------------------------- 964 965 inline void SfxMultiFixRecordWriter::NewContent() 966 967 /* [Beschreibung] 968 969 Mit dieser Methode wird in den Record ein neuer Content eingef"ugt. 970 Jeder, auch der 1. Record mu\s durch Aufruf dieser Methode eingeleitet 971 werden. 972 */ 973 974 { 975 #ifdef DBG_UTIL 976 sal_uLong nOldStartPos; 977 // Startposition des aktuellen Contents merken - Achtung Subklassen! 978 nOldStartPos = _nContentStartPos; 979 #endif 980 _nContentStartPos = _pStream->Tell(); 981 982 #ifdef DBG_UTIL 983 // ist ein vorhergehender Content vorhanden? 984 if ( _nContentCount ) 985 { 986 // pr"ufen, ob der vorhergehende die Soll-Gr"o\se eingehalten hat 987 DBG_ASSERT( _nContentStartPos - nOldStartPos == _nContentSize, 988 "wrong content size detected" ); 989 } 990 #endif 991 992 // Anzahl mitz"ahlen 993 ++_nContentCount; 994 } 995 996 //========================================================================= 997 998 inline SfxMultiMixRecordWriter::SfxMultiMixRecordWriter 999 ( 1000 SvStream* pStream, // Stream, in dem der Record angelegt wird 1001 sal_uInt16 nRecordTag, // Gesamt-Record-Art-Kennung 1002 sal_uInt8 nRecordVer // Gesamt-Record-Versions-Kennung 1003 ) 1004 1005 /* [Beschreibung] 1006 1007 Legt in 'pStream' einen 'SfxMultiMixRecord' an, f"ur dessen Contents 1008 je eine separate Kennung f"ur Art (Tag) und Version gespeichert wird. 1009 Die Gr"o\sen der einzelnen Contents werden automatisch ermittelt. 1010 */ 1011 1012 : SfxMultiVarRecordWriter( SFX_REC_TYPE_MIXTAGS, 1013 pStream, nRecordTag, nRecordVer ) 1014 { 1015 } 1016 1017 //========================================================================= 1018 1019 inline void SfxMultiFixRecordWriter::Reset() 1020 { 1021 _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI + 1022 SFX_REC_HEADERSIZE_SINGLE + 1023 SFX_REC_HEADERSIZE_MULTI ); 1024 _bHeaderOk = sal_False; 1025 } 1026 1027 //========================================================================= 1028 1029 inline sal_uInt16 SfxMultiRecordReader::GetContentTag() 1030 1031 /* [Beschreibung] 1032 1033 Diese Methode liefert die Art-Kennung des zuletzt mit der Methode 1034 <SfxMultiRecordReder::GetContent()> ge"offneten Contents. 1035 */ 1036 1037 { 1038 return _nContentTag; 1039 } 1040 1041 //------------------------------------------------------------------------- 1042 1043 inline sal_uInt8 SfxMultiRecordReader::GetContentVersion() const 1044 1045 /* [Beschreibung] 1046 1047 Diese Methode liefert die Version-Kennung des zuletzt mit der Methode 1048 <SfxMultiRecordReder::GetContent()> ge"offneten Contents. 1049 */ 1050 1051 { 1052 return _nContentVer; 1053 } 1054 1055 //------------------------------------------------------------------------- 1056 1057 inline FASTBOOL SfxMultiRecordReader::HasContentVersion( sal_uInt16 nVersion ) const 1058 1059 /* [Beschreibung] 1060 1061 Diese Methode stellt fest, ob die Version 'nVersion' in der Version des 1062 zuletzt mit der Methode <SfxMultiRecordReder::GetContent()> ge"offneten 1063 Contents enthalten ist. 1064 */ 1065 1066 { 1067 return _nContentVer >= nVersion; 1068 } 1069 1070 //------------------------------------------------------------------------- 1071 1072 inline sal_uInt32 SfxMultiRecordReader::ContentCount() const 1073 1074 /* [Beschreibung] 1075 1076 Diese Methode liefert die Anzahl im Record befindlichen Contents. 1077 */ 1078 1079 { 1080 return _nContentCount; 1081 } 1082 1083 #endif 1084 1085