1 /** \file lvstream.h 2 \brief stream classes interface 3 4 CoolReader Engine 5 6 (c) Vadim Lopatin, 2000-2006 7 This source code is distributed under the terms of 8 GNU General Public License. 9 See LICENSE file for details. 10 11 * In addition, as a special exception, the copyright holders give 12 * permission to link the code of portions of this program with the 13 * UNRAR library under certain conditions as described in each 14 * individual source file, and distribute linked combinations 15 * including the two. 16 * You must obey the GNU General Public License in all respects 17 * for all of the code used other than OpenSSL. If you modify 18 * file(s) with this exception, you may extend this exception to your 19 * version of the file(s), but you are not obligated to do so. If you 20 * do not wish to do so, delete this exception statement from your 21 * version. If you delete this exception statement from all source 22 * files in the program, then also delete it here. 23 24 */ 25 26 27 #ifndef __LVSTREAM_H_INCLUDED__ 28 #define __LVSTREAM_H_INCLUDED__ 29 30 #include "lvtypes.h" 31 #include "lvref.h" 32 #include "lvstring.h" 33 #include "lvarray.h" 34 #include "lvptrvec.h" 35 #include "crtimerutil.h" 36 37 #if LVLONG_FILE_SUPPORT == 1 38 typedef lUInt64 lvsize_t; ///< file size type 39 typedef lInt64 lvoffset_t; ///< file offset type 40 typedef lUInt64 lvpos_t; ///< file position type 41 #else 42 typedef lUInt32 lvsize_t; ///< file size type 43 typedef lInt32 lvoffset_t; ///< file offset type 44 typedef lUInt32 lvpos_t; ///< file position type 45 #endif 46 47 #define LV_INVALID_SIZE ((lvsize_t)(-1)) 48 49 /// Seek origins enum 50 enum lvseek_origin_t { 51 LVSEEK_SET = 0, ///< seek relatively to beginning of file 52 LVSEEK_CUR = 1, ///< seek relatively to current position 53 LVSEEK_END = 2 ///< seek relatively to end of file 54 }; 55 56 /// I/O errors enum 57 enum lverror_t { 58 LVERR_OK = 0, ///< no error 59 LVERR_FAIL, ///< failed (unknown error) 60 LVERR_EOF, ///< end of file reached 61 LVERR_NOTFOUND, ///< file not found 62 LVERR_NOTIMPL ///< method is not implemented 63 }; 64 65 /// File open modes enum 66 enum lvopen_mode_t { 67 LVOM_ERROR=0, ///< to indicate error state 68 LVOM_CLOSED, ///< to indicate closed state 69 LVOM_READ, ///< readonly mode, use for r/o mmap 70 LVOM_WRITE, ///< writeonly mode 71 LVOM_APPEND, ///< append (readwrite) mode, use for r/w mmap 72 LVOM_READWRITE ///< readwrite mode 73 }; 74 75 #define LVOM_MASK 7 76 #define LVOM_FLAG_SYNC 0x10 77 78 class LVContainer; 79 class LVStream; 80 81 class LVStorageObject : public LVRefCounter 82 { 83 public: 84 // construction/destruction 85 //LVStorageObject() { } ~LVStorageObject()86 virtual ~LVStorageObject() { } 87 // storage object methods 88 /// returns true for container (directory), false for stream (file) 89 virtual bool IsContainer(); 90 /// returns stream/container name, may be NULL if unknown 91 virtual const lChar32 * GetName(); 92 /// sets stream/container name, may be not implemented for some objects 93 virtual void SetName(const lChar32 * name); 94 /// returns parent container, if opened from container 95 virtual LVContainer * GetParentContainer(); 96 /// returns object size (file size or directory entry count) 97 virtual lverror_t GetSize( lvsize_t * pSize ) = 0; 98 /// returns object size (file size or directory entry count) 99 virtual lvsize_t GetSize( ); 100 }; 101 102 /// Read or write buffer for stream region 103 class LVStreamBuffer : public LVRefCounter 104 { 105 public: 106 /// get pointer to read-only buffer, returns NULL if unavailable 107 virtual const lUInt8 * getReadOnly() = 0; 108 /// get pointer to read-write buffer, returns NULL if unavailable 109 virtual lUInt8 * getReadWrite() = 0; 110 /// get buffer size 111 virtual lvsize_t getSize() = 0; 112 /// flush on destroy ~LVStreamBuffer()113 virtual ~LVStreamBuffer() { 114 close(); // NOLINT: Call to virtual function during destruction 115 } 116 /// detach from stream, write changes if necessary close()117 virtual bool close() { return true; } 118 }; 119 120 typedef LVFastRef<LVStreamBuffer> LVStreamBufferRef; 121 122 /// Stream base class 123 class LVStream : public LVStorageObject 124 { 125 public: 126 127 /// Get read buffer (optimal for mmap) 128 virtual LVStreamBufferRef GetReadBuffer( lvpos_t pos, lvpos_t size ); 129 /// Get read/write buffer (optimal for mmap) 130 virtual LVStreamBufferRef GetWriteBuffer( lvpos_t pos, lvpos_t size ); 131 132 /// Get stream open mode 133 /** \return lvopen_mode_t open mode */ GetMode()134 virtual lvopen_mode_t GetMode() { return LVOM_READ; } 135 136 /// Set stream mode, supported not by all streams 137 /** \return LVERR_OK if change is ok */ SetMode(lvopen_mode_t)138 virtual lverror_t SetMode( lvopen_mode_t ) { return LVERR_NOTIMPL; } 139 /// flushes unsaved data from buffers to file, with optional flush of OS buffers Flush(bool)140 virtual lverror_t Flush( bool /*sync*/ ) { return LVERR_OK; } Flush(bool sync,CRTimerUtil &)141 virtual lverror_t Flush( bool sync, CRTimerUtil & /*timeout*/ ) { return Flush(sync); } 142 143 /// Seek (change file pos) 144 /** 145 \param offset is file offset (bytes) relateve to origin 146 \param origin is offset base 147 \param pNewPos points to place to store new file position 148 \return lverror_t status: LVERR_OK if success 149 */ 150 virtual lverror_t Seek( lvoffset_t offset, lvseek_origin_t origin, lvpos_t * pNewPos ) = 0; 151 152 /// Tell current file position 153 /** 154 \param pNewPos points to place to store file position 155 \return lverror_t status: LVERR_OK if success 156 */ Tell(lvpos_t * pPos)157 virtual lverror_t Tell( lvpos_t * pPos ) { return Seek(0, LVSEEK_CUR, pPos); } 158 159 /// Set file position 160 /** 161 \param p is new position 162 \return lverror_t status: LVERR_OK if success 163 */ 164 //virtual lverror_t SetPos(lvpos_t p) { return Seek(p, LVSEEK_SET, NULL); } SetPos(lvpos_t p)165 virtual lvpos_t SetPos(lvpos_t p) { lvpos_t pos; return (Seek(p, LVSEEK_SET, &pos)==LVERR_OK)?pos:(lvpos_t)(~0); } 166 167 /// Get file position 168 /** 169 \return lvpos_t file position 170 */ GetPos()171 virtual lvpos_t GetPos() 172 { 173 lvpos_t pos; 174 if (Seek(0, LVSEEK_CUR, &pos)==LVERR_OK) 175 return pos; 176 else 177 return (lvpos_t)(~0); 178 } 179 180 /// Get file size 181 /** 182 \return lvsize_t file size 183 */ GetSize()184 virtual lvsize_t GetSize() 185 { 186 lvpos_t pos = GetPos(); 187 lvsize_t sz = 0; 188 Seek(0, LVSEEK_END, &sz); 189 SetPos(pos); 190 return sz; 191 } 192 GetSize(lvsize_t * pSize)193 virtual lverror_t GetSize( lvsize_t * pSize ) 194 { 195 *pSize = GetSize(); 196 return LVERR_OK; 197 } 198 199 /// Set file size 200 /** 201 \param size is new file size 202 \return lverror_t status: LVERR_OK if success 203 */ 204 virtual lverror_t SetSize( lvsize_t size ) = 0; 205 206 /// Read 207 /** 208 \param buf is buffer to place bytes read from stream 209 \param count is number of bytes to read from stream 210 \param nBytesRead is place to store real number of bytes read from stream 211 \return lverror_t status: LVERR_OK if success 212 */ 213 virtual lverror_t Read( void * buf, lvsize_t count, lvsize_t * nBytesRead ) = 0; 214 Read(lUInt8 * buf)215 virtual bool Read( lUInt8 * buf ) 216 { 217 lvsize_t nBytesRead; 218 if ( Read( buf, sizeof(lUInt8), &nBytesRead )==LVERR_OK && nBytesRead==sizeof(lUInt8) ) 219 return true; 220 return false; 221 } 222 Read(lUInt16 * buf)223 virtual bool Read( lUInt16 * buf ) 224 { 225 lvsize_t nBytesRead; 226 if ( Read( buf, sizeof(lUInt16), &nBytesRead )==LVERR_OK && nBytesRead==sizeof(lUInt16) ) 227 return true; 228 return false; 229 } 230 Read(lUInt32 * buf)231 virtual bool Read( lUInt32 * buf ) 232 { 233 lvsize_t nBytesRead; 234 if ( Read( buf, sizeof(lUInt32), &nBytesRead )==LVERR_OK && nBytesRead==sizeof(lUInt32) ) 235 return true; 236 return false; 237 } 238 ReadByte()239 virtual int ReadByte() 240 { 241 unsigned char buf[1]; 242 lvsize_t sz = 0; 243 if ( Read( buf, 1, &sz ) == LVERR_OK && sz == 1 ) 244 return buf[0]; 245 return -1; 246 } 247 248 /// Write 249 /** 250 \param buf is data to write to stream 251 \param count is number of bytes to write 252 \param nBytesWritten is place to store real number of bytes written to stream 253 \return lverror_t status: LVERR_OK if success 254 */ 255 virtual lverror_t Write( const void * buf, lvsize_t count, lvsize_t * nBytesWritten ) = 0; 256 257 /// Check whether end of file is reached 258 /** 259 \return true if end of file reached 260 */ 261 virtual bool Eof() = 0; 262 263 /// writes array 264 lverror_t Write( LVArray<lUInt32> & array ); 265 266 /// calculate crc32 code for stream, if possible 267 virtual lverror_t getcrc32( lUInt32 & dst ); 268 /// calculate crc32 code for stream, returns 0 for error or empty stream getcrc32()269 inline lUInt32 getcrc32() { lUInt32 res = 0; getcrc32( res ); return res; } 270 271 /// set write bytes limit to call flush(true) automatically after writing of each sz bytes setAutoSyncSize(lvsize_t)272 virtual void setAutoSyncSize(lvsize_t /*sz*/) { } 273 274 /// Constructor LVStream()275 LVStream() { } 276 277 /// Destructor ~LVStream()278 virtual ~LVStream() { } 279 }; 280 281 /// Stream reference 282 typedef LVFastRef<LVStream> LVStreamRef; 283 284 /// base proxy class for streams: redirects all calls to base stream 285 class StreamProxy : public LVStream { 286 protected: 287 LVStreamRef _base; 288 public: StreamProxy(LVStreamRef baseStream)289 StreamProxy(LVStreamRef baseStream) : _base(baseStream) { } ~StreamProxy()290 virtual ~StreamProxy() { } 291 292 /// Seek (change file pos) 293 /** 294 \param offset is file offset (bytes) relateve to origin 295 \param origin is offset base 296 \param pNewPos points to place to store new file position 297 \return lverror_t status: LVERR_OK if success 298 */ Seek(lvoffset_t offset,lvseek_origin_t origin,lvpos_t * pNewPos)299 virtual lverror_t Seek( lvoffset_t offset, lvseek_origin_t origin, lvpos_t * pNewPos ) { 300 return _base->Seek(offset, origin, pNewPos); 301 } 302 303 /// Tell current file position 304 /** 305 \param pNewPos points to place to store file position 306 \return lverror_t status: LVERR_OK if success 307 */ Tell(lvpos_t * pPos)308 virtual lverror_t Tell( lvpos_t * pPos ) { return _base->Tell(pPos); } 309 310 /// Set file position 311 /** 312 \param p is new position 313 \return lverror_t status: LVERR_OK if success 314 */ 315 //virtual lverror_t SetPos(lvpos_t p) { return Seek(p, LVSEEK_SET, NULL); } SetPos(lvpos_t p)316 virtual lvpos_t SetPos(lvpos_t p) { return _base->SetPos(p); } 317 318 /// Get file position 319 /** 320 \return lvpos_t file position 321 */ GetPos()322 virtual lvpos_t GetPos() { return _base->GetPos(); } 323 GetSize()324 virtual lvsize_t GetSize() 325 { 326 return _base->GetSize(); 327 } 328 GetSize(lvsize_t * pSize)329 virtual lverror_t GetSize( lvsize_t * pSize ) 330 { 331 return _base->GetSize(pSize); 332 } 333 SetSize(lvsize_t size)334 virtual lverror_t SetSize( lvsize_t size ) { return _base->SetSize(size); } 335 Read(void * buf,lvsize_t count,lvsize_t * nBytesRead)336 virtual lverror_t Read( void * buf, lvsize_t count, lvsize_t * nBytesRead ) { 337 return _base->Read(buf, count, nBytesRead); 338 } 339 340 /// Write 341 /** 342 \param buf is data to write to stream 343 \param count is number of bytes to write 344 \param nBytesWritten is place to store real number of bytes written to stream 345 \return lverror_t status: LVERR_OK if success 346 */ Write(const void * buf,lvsize_t count,lvsize_t * nBytesWritten)347 virtual lverror_t Write( const void * buf, lvsize_t count, lvsize_t * nBytesWritten ) { 348 return _base->Write(buf, count, nBytesWritten); 349 } 350 Eof()351 virtual bool Eof() { 352 return _base->Eof(); 353 } 354 355 }; 356 357 358 /// Writes lString32 string to stream 359 inline LVStream & operator << (LVStream & stream, const lString32 & str) 360 { 361 if (!str.empty()) 362 stream.Write( str.c_str(), sizeof(lChar32)*str.length(), NULL); 363 return stream; 364 } 365 366 /// Writes lString8 string to stream 367 inline LVStream & operator << (LVStream & stream, const lString8 & str) 368 { 369 if (!str.empty()) 370 stream.Write( str.c_str(), sizeof(lChar8)*str.length(), NULL); 371 return stream; 372 } 373 374 /// Writes lChar32 string to stream 375 inline LVStream & operator << (LVStream & stream, const lChar32 * str) 376 { 377 if (str) 378 stream.Write( str, sizeof(lChar32)*lStr_len(str), NULL); 379 return stream; 380 } 381 382 /// Writes lChar8 string to stream 383 inline LVStream & operator << (LVStream & stream, const lChar8 * str) 384 { 385 if (str) 386 stream.Write( str, sizeof(lChar8)*lStr_len(str), NULL); 387 return stream; 388 } 389 390 /// Writes lUInt32 to stream 391 inline LVStream & operator << (LVStream & stream, lUInt32 d ) 392 { 393 stream.Write( &d, sizeof(d), NULL); 394 return stream; 395 } 396 397 /// Writes lUInt16 to stream 398 inline LVStream & operator << (LVStream & stream, lUInt16 d ) 399 { 400 stream.Write( &d, sizeof(d), NULL); 401 return stream; 402 } 403 404 /// Writes lUInt8 to stream 405 inline LVStream & operator << (LVStream & stream, lUInt8 d ) 406 { 407 stream.Write( &d, sizeof(d), NULL); 408 return stream; 409 } 410 411 /// Writes value array to stream 412 template <typename T> 413 inline LVStream & operator << (LVStream & stream, LVArray<T> & array ) 414 { 415 stream.Write( array.ptr(), sizeof(T)*array.length(), NULL); 416 return stream; 417 } 418 419 class LVNamedStream : public LVStream 420 { 421 protected: 422 lString32 m_fname; 423 lString32 m_filename; 424 lString32 m_path; 425 lvopen_mode_t m_mode; 426 lUInt32 _crc; 427 bool _crcFailed; 428 lvsize_t _autosyncLimit; 429 lvsize_t _bytesWritten; handleAutoSync(lvsize_t bytesWritten)430 virtual void handleAutoSync(lvsize_t bytesWritten) { 431 _bytesWritten += bytesWritten; 432 if (_autosyncLimit==0) 433 return; 434 if (_bytesWritten>_autosyncLimit) { 435 Flush(true); 436 _bytesWritten = 0; 437 } 438 } 439 440 public: LVNamedStream()441 LVNamedStream() : m_mode(LVOM_ERROR), _crc(0), _crcFailed(false), _autosyncLimit(0), _bytesWritten(0) { } 442 /// set write bytes limit to call flush(true) automatically after writing of each sz bytes setAutoSyncSize(lvsize_t sz)443 virtual void setAutoSyncSize(lvsize_t sz) { _autosyncLimit = sz; } 444 /// returns stream/container name, may be NULL if unknown 445 virtual const lChar32 * GetName(); 446 /// sets stream/container name, may be not implemented for some objects 447 virtual void SetName(const lChar32 * name); 448 /// returns open mode GetMode()449 virtual lvopen_mode_t GetMode() 450 { 451 return (lvopen_mode_t)(m_mode & LVOM_MASK); 452 } 453 /// calculate crc32 code for stream, if possible 454 virtual lverror_t getcrc32( lUInt32 & dst ); 455 }; 456 457 458 class LVStreamProxy : public LVStream 459 { 460 protected: 461 LVStream * m_base_stream; 462 public: GetName()463 virtual const lChar32 * GetName() 464 { return m_base_stream->GetName(); } GetMode()465 virtual lvopen_mode_t GetMode() 466 { return m_base_stream->GetMode(); } Seek(lvoffset_t offset,lvseek_origin_t origin,lvpos_t * pNewPos)467 virtual lverror_t Seek( lvoffset_t offset, lvseek_origin_t origin, lvpos_t * pNewPos ) 468 { return m_base_stream->Seek(offset, origin, pNewPos); } Tell(lvpos_t * pPos)469 virtual lverror_t Tell( lvpos_t * pPos ) 470 { return m_base_stream->Tell(pPos); } 471 //virtual lverror_t SetPos(lvpos_t p) SetPos(lvpos_t p)472 virtual lvpos_t SetPos(lvpos_t p) 473 { return m_base_stream->SetPos(p); } GetPos()474 virtual lvpos_t GetPos() 475 { return m_base_stream->GetPos(); } SetSize(lvsize_t size)476 virtual lverror_t SetSize( lvsize_t size ) 477 { return m_base_stream->SetSize(size); } Read(void * buf,lvsize_t count,lvsize_t * nBytesRead)478 virtual lverror_t Read( void * buf, lvsize_t count, lvsize_t * nBytesRead ) 479 { return m_base_stream->Read(buf, count, nBytesRead); } Write(const void * buf,lvsize_t count,lvsize_t * nBytesWritten)480 virtual lverror_t Write( const void * buf, lvsize_t count, lvsize_t * nBytesWritten ) 481 { return m_base_stream->Write(buf, count, nBytesWritten); } Eof()482 virtual bool Eof() 483 { return m_base_stream->Eof(); } LVStreamProxy(LVStream * stream)484 LVStreamProxy( LVStream * stream ) : m_base_stream(stream) { } ~LVStreamProxy()485 ~LVStreamProxy() { delete m_base_stream; } 486 }; 487 488 class LVTextStream : public LVStreamProxy 489 { 490 public: 491 virtual lvopen_mode_t GetMode(); 492 virtual lverror_t Seek( lvoffset_t offset, lvseek_origin_t origin, lvpos_t * pNewPos ); 493 virtual lverror_t Tell( lvpos_t * pPos ); 494 virtual lvpos_t SetPos(lvpos_t p); 495 virtual lvpos_t GetPos(); 496 virtual lverror_t SetSize( lvsize_t size ); 497 virtual lverror_t Read( void * buf, lvsize_t count, lvsize_t * nBytesRead ); 498 virtual lverror_t Write( const void * buf, lvsize_t count, lvsize_t * nBytesWritten ); 499 virtual bool Eof(); LVTextStream(LVStream * stream)500 LVTextStream( LVStream * stream ) : LVStreamProxy(stream) 501 { } 502 }; 503 504 class LVContainerItemInfo 505 { 506 public: 507 virtual lvsize_t GetSize() const = 0; 508 virtual const lChar32 * GetName() const = 0; 509 virtual lUInt32 GetFlags() const = 0; 510 virtual bool IsContainer() const = 0; LVContainerItemInfo()511 LVContainerItemInfo() {} ~LVContainerItemInfo()512 virtual ~LVContainerItemInfo() {} 513 }; 514 515 class LVContainer : public LVStorageObject 516 { 517 public: 518 virtual LVContainer * GetParentContainer() = 0; 519 //virtual const LVContainerItemInfo * GetObjectInfo(const char32_t * pname); 520 virtual const LVContainerItemInfo * GetObjectInfo(int index) = 0; 521 virtual const LVContainerItemInfo * operator [] (int index) { return GetObjectInfo(index); } 522 virtual int GetObjectCount() const = 0; 523 virtual LVStreamRef OpenStream( const lChar32 * fname, lvopen_mode_t mode ) = 0; LVContainer()524 LVContainer() {} ~LVContainer()525 virtual ~LVContainer() { } 526 }; 527 528 class LVCommonContainerItemInfo : public LVContainerItemInfo 529 { 530 friend class LVDirectoryContainer; 531 friend class LVArcContainer; 532 protected: 533 lvsize_t m_size; 534 lString32 m_name; 535 lUInt32 m_flags; 536 bool m_is_container; 537 lUInt32 m_srcpos; 538 lUInt32 m_srcsize; 539 lUInt32 m_srcflags; 540 public: GetSize()541 virtual lvsize_t GetSize() const { return m_size; } GetName()542 virtual const lChar32 * GetName() const { return m_name.empty()?NULL:m_name.c_str(); } GetFlags()543 virtual lUInt32 GetFlags() const { return m_flags; } IsContainer()544 virtual bool IsContainer() const { return m_is_container; } GetSrcPos()545 lUInt32 GetSrcPos() { return m_srcpos; } GetSrcSize()546 lUInt32 GetSrcSize() { return m_srcsize; } GetSrcFlags()547 lUInt32 GetSrcFlags() { return m_srcflags; } SetSrc(lUInt32 pos,lUInt32 size,lUInt32 flags)548 void SetSrc( lUInt32 pos, lUInt32 size, lUInt32 flags ) 549 { 550 m_srcpos = pos; 551 m_srcsize = size; 552 m_srcflags = flags; 553 } SetName(const lChar32 * name)554 void SetName( const lChar32 * name ) 555 { 556 m_name = name; 557 } 558 void SetItemInfo( lString32 fname, lvsize_t size, lUInt32 flags, bool isContainer = false ) 559 { 560 m_name = fname; 561 m_size = size; 562 m_flags = flags; 563 m_is_container = isContainer; 564 } LVCommonContainerItemInfo()565 LVCommonContainerItemInfo() : m_size(0), m_flags(0), m_is_container(false), 566 m_srcpos(0), m_srcsize(0), m_srcflags(0) 567 { 568 } ~LVCommonContainerItemInfo()569 virtual ~LVCommonContainerItemInfo () 570 { 571 } 572 }; 573 574 class LVNamedContainer : public LVContainer 575 { 576 protected: 577 lString32 m_fname; 578 lString32 m_filename; 579 lString32 m_path; 580 lChar32 m_path_separator; 581 LVPtrVector<LVCommonContainerItemInfo> m_list; 582 public: IsContainer()583 virtual bool IsContainer() 584 { 585 return true; 586 } 587 /// returns stream/container name, may be NULL if unknown GetName()588 virtual const lChar32 * GetName() 589 { 590 if (m_fname.empty()) 591 return NULL; 592 return m_fname.c_str(); 593 } 594 /// sets stream/container name, may be not implemented for some objects SetName(const lChar32 * name)595 virtual void SetName(const lChar32 * name) 596 { 597 m_fname = name; 598 m_filename.clear(); 599 m_path.clear(); 600 if (m_fname.empty()) 601 return; 602 const lChar32 * fn = m_fname.c_str(); 603 604 const lChar32 * p = fn + m_fname.length() - 1; 605 for ( ;p>fn; p--) { 606 if (p[-1] == '/' || p[-1]=='\\') 607 { 608 m_path_separator = p[-1]; 609 break; 610 } 611 } 612 int pos = (int)(p - fn); 613 if (p > fn) 614 m_path = m_fname.substr(0, pos); 615 m_filename = m_fname.substr(pos, m_fname.length() - pos); 616 } LVNamedContainer()617 LVNamedContainer() : m_path_separator( 618 #ifdef _LINUX 619 '/' 620 #else 621 '\\' 622 #endif 623 ) 624 { 625 } ~LVNamedContainer()626 virtual ~LVNamedContainer() 627 { 628 } Add(LVCommonContainerItemInfo * item)629 void Add( LVCommonContainerItemInfo * item ) 630 { 631 m_list.add( item ); 632 } Clear()633 void Clear() 634 { 635 m_list.clear(); 636 } 637 }; 638 639 class LVArcContainerBase : public LVNamedContainer 640 { 641 protected: 642 LVContainer * m_parent; 643 LVStreamRef m_stream; 644 public: OpenStream(const char32_t *,lvopen_mode_t)645 virtual LVStreamRef OpenStream( const char32_t *, lvopen_mode_t ) 646 { 647 return LVStreamRef(); 648 } GetParentContainer()649 virtual LVContainer * GetParentContainer() 650 { 651 return (LVContainer*)m_parent; 652 } GetObjectInfo(int index)653 virtual const LVContainerItemInfo * GetObjectInfo(int index) 654 { 655 if (index>=0 && index<m_list.length()) 656 return m_list[index]; 657 return NULL; 658 } GetObjectInfo(lString32 name)659 virtual const LVContainerItemInfo * GetObjectInfo(lString32 name) 660 { 661 for ( int i=0; i<m_list.length(); i++ ) 662 if (m_list[i]->GetName()==name ) 663 return m_list[i]; 664 return NULL; 665 } GetObjectCount()666 virtual int GetObjectCount() const 667 { 668 return m_list.length(); 669 } GetSize(lvsize_t * pSize)670 virtual lverror_t GetSize( lvsize_t * pSize ) 671 { 672 if (m_fname.empty()) 673 return LVERR_FAIL; 674 *pSize = GetObjectCount(); 675 return LVERR_OK; 676 } LVArcContainerBase(LVStreamRef stream)677 LVArcContainerBase( LVStreamRef stream ) : m_parent(NULL), m_stream(stream) 678 { 679 } ~LVArcContainerBase()680 virtual ~LVArcContainerBase() 681 { 682 SetName(NULL); 683 Clear(); 684 } 685 virtual int ReadContents() = 0; 686 687 }; 688 689 class LVStreamFragment : public LVNamedStream 690 { 691 private: 692 LVStreamRef m_stream; 693 lvsize_t m_start; 694 lvsize_t m_size; 695 lvpos_t m_pos; 696 public: LVStreamFragment(LVStreamRef stream,lvsize_t start,lvsize_t size)697 LVStreamFragment( LVStreamRef stream, lvsize_t start, lvsize_t size ) 698 : m_stream(stream), m_start(start), m_size(size), m_pos(0) 699 { 700 } Eof()701 virtual bool Eof() 702 { 703 return m_pos >= m_size; 704 } GetSize()705 virtual lvsize_t GetSize() 706 { 707 return m_size; 708 } 709 Seek(lvoffset_t pos,lvseek_origin_t origin,lvpos_t * newPos)710 virtual lverror_t Seek(lvoffset_t pos, lvseek_origin_t origin, lvpos_t* newPos) 711 { 712 if ( origin==LVSEEK_SET ) 713 pos += m_start; 714 else if ( origin==LVSEEK_END ) { 715 origin = LVSEEK_SET; 716 pos = m_start + m_size; 717 } 718 lverror_t res = m_stream->Seek( pos, origin, &m_pos ); 719 if (res == LVERR_OK) 720 m_pos -= m_start; 721 if (newPos) 722 { 723 *newPos = m_pos; 724 } 725 return res; 726 } Write(const void *,lvsize_t,lvsize_t *)727 virtual lverror_t Write(const void*, lvsize_t, lvsize_t*) 728 { 729 return LVERR_NOTIMPL; 730 } Read(void * buf,lvsize_t size,lvsize_t * pBytesRead)731 virtual lverror_t Read(void* buf, lvsize_t size, lvsize_t* pBytesRead) 732 { 733 lvsize_t bytesRead = 0; 734 lvpos_t p; 735 lverror_t res = m_stream->Seek( m_pos+m_start, LVSEEK_SET, &p ); 736 if ( res!=LVERR_OK ) 737 return res; 738 res = m_stream->Read( buf, size, &bytesRead ); 739 if (res == LVERR_OK) 740 m_pos += bytesRead; 741 if (pBytesRead) 742 *pBytesRead = bytesRead; 743 return res; 744 } SetSize(lvsize_t)745 virtual lverror_t SetSize(lvsize_t) 746 { 747 return LVERR_NOTIMPL; 748 } 749 }; 750 751 /// Container reference 752 typedef LVFastRef<LVContainer> LVContainerRef; 753 754 /// Open file stream 755 /** 756 \param pathname is file name to open (unicode) 757 \param mode is mode file should be opened in 758 \return reference to opened stream if success, NULL if error 759 */ 760 LVStreamRef LVOpenFileStream( const lChar32 * pathname, int mode ); 761 762 /// Open file stream 763 /** 764 \param pathname is file name to open (utf8 codepage) 765 \param mode is mode file should be opened in 766 \return reference to opened stream if success, NULL if error 767 */ 768 LVStreamRef LVOpenFileStream( const lChar8 * pathname, int mode ); 769 770 /// Open memory mapped file 771 /** 772 \param pathname is file name to open (unicode) 773 \param mode is mode file should be opened in (LVOM_READ or LVOM_APPEND only) 774 \param minSize is minimum file size for R/W mode 775 \return reference to opened stream if success, NULL if error 776 */ 777 LVStreamRef LVMapFileStream( const lChar32 * pathname, lvopen_mode_t mode, lvsize_t minSize ); 778 779 /// Open memory mapped file 780 /** 781 \param pathname is file name to open (unicode) 782 \param mode is mode file should be opened in (LVOM_READ or LVOM_APPEND only) 783 \param minSize is minimum file size for R/W mode 784 \return reference to opened stream if success, NULL if error 785 */ 786 LVStreamRef LVMapFileStream( const lChar8 * pathname, lvopen_mode_t mode, lvsize_t minSize ); 787 788 789 /// Open archieve from stream 790 /** 791 \param stream is archieve file stream 792 \return reference to opened archieve if success, NULL reference if error 793 */ 794 #if (USE_ZLIB==1) 795 LVContainerRef LVOpenArchieve( LVStreamRef stream ); 796 #endif 797 798 /// Creates memory stream 799 /** 800 \param buf is pointer to buffer, if NULL, empty read/write memory stream will be created 801 \param bufSize is buffer size, in bytes 802 \param createCopy if true, read/write copy of specified data is being created, otherwise non-managed readonly buffer is being used as is 803 \param mode is open mode 804 \return reference to opened stream if success, NULL reference if error 805 */ 806 LVStreamRef LVCreateMemoryStream( void * buf = NULL, int bufSize = 0, bool createCopy = false, lvopen_mode_t mode = LVOM_READ ); 807 /// Creates memory stream as copy of another stream. 808 LVStreamRef LVCreateMemoryStream( LVStreamRef srcStream ); 809 /// Creates memory stream as copy of file contents. 810 LVStreamRef LVCreateMemoryStream( lString32 filename ); 811 /// Creates memory stream as copy of string contents 812 LVStreamRef LVCreateStringStream( lString8 data ); 813 /// Creates memory stream as copy of string contents 814 LVStreamRef LVCreateStringStream( lString32 data ); 815 816 /// creates cache buffers for stream, to write data by big blocks to optimize Flash drives writing performance 817 LVStreamRef LVCreateBlockWriteStream( LVStreamRef baseStream, int blockSize, int blockCount ); 818 819 LVContainerRef LVOpenDirectory( const lChar32 * path, const char32_t * mask = U"*.*" ); 820 LVContainerRef LVOpenDirectory(const lString32& path, const char32_t * mask = U"*.*" ); 821 LVContainerRef LVOpenDirectory(const lString8& path, const char32_t * mask = U"*.*" ); 822 823 bool LVDirectoryIsEmpty(const lString8& path); 824 bool LVDirectoryIsEmpty(const lString32& path); 825 826 /// Create directory if not exist 827 bool LVCreateDirectory( lString32 path ); 828 /// delete file, return true if file found and successfully deleted 829 bool LVDeleteFile( lString32 filename ); 830 /// delete file, return true if file found and successfully deleted 831 bool LVDeleteFile( lString8 filename ); 832 /// delete directory, return true if directory is found and successfully deleted 833 bool LVDeleteDirectory( lString32 filename ); 834 /// delete directory, return true if directory is found and successfully deleted 835 bool LVDeleteDirectory( lString8 filename ); 836 /// rename file 837 bool LVRenameFile(lString32 oldname, lString32 newname); 838 /// rename file 839 bool LVRenameFile(lString8 oldname, lString8 newname); 840 841 /// copies content of in stream to out stream 842 lvsize_t LVPumpStream( LVStreamRef out, LVStreamRef in ); 843 /// copies content of in stream to out stream 844 lvsize_t LVPumpStream( LVStream * out, LVStream * in ); 845 846 /// creates buffered stream object for stream 847 LVStreamRef LVCreateBufferedStream( LVStreamRef stream, int bufSize ); 848 /// creates TCR decoder stream for stream 849 LVStreamRef LVCreateTCRDecoderStream( LVStreamRef stream ); 850 851 /// returns path part of pathname (appended with / or \ delimiter) 852 lString32 LVExtractPath( lString32 pathName, bool appendEmptyPath=true ); 853 /// returns path part of pathname (appended with / or \ delimiter) 854 lString8 LVExtractPath( lString8 pathName, bool appendEmptyPath=true ); 855 /// removes first path part from pathname and returns it 856 lString32 LVExtractFirstPathElement( lString32 & pathName ); 857 /// removes last path part from pathname and returns it 858 lString32 LVExtractLastPathElement( lString32 & pathName ); 859 /// returns filename part of pathname 860 lString32 LVExtractFilename( lString32 pathName ); 861 /// returns filename part of pathname 862 lString8 LVExtractFilename( lString8 pathName ); 863 /// returns filename part of pathname without extension 864 lString32 LVExtractFilenameWithoutExtension( lString32 pathName ); 865 /// appends path delimiter character to end of path, if absent 866 void LVAppendPathDelimiter( lString32 & pathName ); 867 /// appends path delimiter character to end of path, if absent 868 void LVAppendPathDelimiter( lString8 & pathName ); 869 /// removes path delimiter from end of path, if present 870 void LVRemoveLastPathDelimiter( lString8 & pathName ); 871 /// removes path delimiter from end of path, if present 872 void LVRemoveLastPathDelimiter( lString32 & pathName ); 873 /// replaces any found / or \\ separator with specified one 874 void LVReplacePathSeparator( lString32 & pathName, lChar32 separator ); 875 /// removes path delimiter character from end of path, if exists 876 void LVRemovePathDelimiter( lString32 & pathName ); 877 /// removes path delimiter character from end of path, if exists 878 void LVRemovePathDelimiter( lString8 & pathName ); 879 /// returns path delimiter character 880 lChar32 LVDetectPathDelimiter( lString32 pathName ); 881 /// returns path delimiter character 882 char LVDetectPathDelimiter( lString8 pathName ); 883 /// returns true if absolute path is specified 884 bool LVIsAbsolutePath( lString32 pathName ); 885 /// returns full path to file identified by pathName, with base directory == basePath 886 lString32 LVMakeRelativeFilename( lString32 basePath, lString32 pathName ); 887 // resolve relative links 888 lString32 LVCombinePaths( lString32 basePath, lString32 newPath ); 889 890 /// tries to split full path name into archive name and file name inside archive using separator "@/" or "@\" 891 bool LVSplitArcName(lString32 fullPathName, lString32 & arcPathName, lString32 & arcItemPathName); 892 /// tries to split full path name into archive name and file name inside archive using separator "@/" or "@\" 893 bool LVSplitArcName(lString8 fullPathName, lString8 & arcPathName, lString8 & arcItemPathName); 894 895 /// returns true if specified file exists 896 bool LVFileExists( const lString32 & pathName ); 897 /// returns true if specified file exists 898 bool LVFileExists( const lString8 & pathName ); 899 /// returns true if specified directory exists 900 bool LVDirectoryExists( const lString32 & pathName ); 901 /// returns true if specified directory exists 902 bool LVDirectoryExists( const lString8 & pathName ); 903 /// returns true if directory exists and your app can write to directory 904 bool LVDirectoryIsWritable(const lString32 & pathName); 905 906 907 /// factory to handle filesystem access for paths started with ASSET_PATH_PREFIX (@ sign) 908 class LVAssetContainerFactory { 909 public: 910 virtual LVContainerRef openAssetContainer(lString32 path) = 0; 911 virtual LVStreamRef openAssetStream(lString32 path) = 0; LVAssetContainerFactory()912 LVAssetContainerFactory() {} ~LVAssetContainerFactory()913 virtual ~LVAssetContainerFactory() {} 914 }; 915 916 #define ASSET_PATH_PREFIX '@' 917 /// set container to handle filesystem access for paths started with ASSET_PATH_PREFIX (@ sign) 918 void LVSetAssetContainerFactory(LVAssetContainerFactory * asset); 919 920 #endif // __LVSTREAM_H_INCLUDED__ 921