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