1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/fileback.cpp
3 // Purpose: Back an input stream with memory or a file
4 // Author: Mike Wetherell
5 // Copyright: (c) 2006 Mike Wetherell
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
18 #include "wx/private/fileback.h"
25 #include "wx/private/filename.h"
27 // Prefer wxFFile unless wxFile has large file support but wxFFile does not.
29 #if wxUSE_FFILE && (defined wxHAS_LARGE_FFILES || !defined wxHAS_LARGE_FILES)
30 typedef wxFFile wxBFFile
;
31 static const bool wxBadSeek
= false;
33 typedef wxFile wxBFFile
;
34 static const wxFileOffset wxBadSeek
= wxInvalidOffset
;
37 /////////////////////////////////////////////////////////////////////////////
38 // Backing file implementation
40 class wxBackingFileImpl
43 wxBackingFileImpl(wxInputStream
*stream
,
45 const wxString
& prefix
);
48 void Release() { if (--m_refcount
== 0) delete this; }
49 wxBackingFileImpl
*AddRef() { m_refcount
++; return this; }
51 wxStreamError
ReadAt(wxFileOffset pos
, void *buffer
, size_t *size
);
52 wxFileOffset
GetLength() const;
57 wxInputStream
*m_stream
;
58 wxStreamError m_parenterror
;
67 wxFileOffset m_filelen
;
70 wxBackingFileImpl::wxBackingFileImpl(wxInputStream
*stream
,
72 const wxString
& prefix
)
75 m_parenterror(wxSTREAM_NO_ERROR
),
82 wxFileOffset len
= m_stream
->GetLength();
84 if (len
>= 0 && len
+ size_t(1) < m_bufsize
)
85 m_bufsize
= size_t(len
+ 1);
88 m_buf
= new char[m_bufsize
];
91 wxBackingFileImpl::~wxBackingFileImpl()
96 if (!m_filename
.empty())
97 wxRemoveFile(m_filename
);
100 wxStreamError
wxBackingFileImpl::ReadAt(wxFileOffset pos
,
104 size_t reqestedSize
= *size
;
107 // size1 is the number of bytes it will read directly from the backing
108 // file. size2 is any remaining bytes not yet backed, these are returned
109 // from the buffer or read from the parent stream.
112 if (pos
+ reqestedSize
<= m_filelen
+ size_t(0)) {
113 size1
= reqestedSize
;
115 } else if (pos
< m_filelen
) {
116 size1
= size_t(m_filelen
- pos
);
117 size2
= reqestedSize
- size1
;
120 size2
= reqestedSize
;
124 return wxSTREAM_READ_ERROR
;
126 // read the backing file
128 if (m_file
.Seek(pos
) == wxBadSeek
)
129 return wxSTREAM_READ_ERROR
;
131 ssize_t n
= m_file
.Read(buffer
, size1
);
138 return wxSTREAM_READ_ERROR
;
141 // read from the buffer or parent stream
144 while (*size
< reqestedSize
)
146 // if pos is further ahead than the parent has been read so far,
147 // then read forward in the parent stream
148 while (pos
- m_filelen
+ size_t(0) >= m_buflen
)
150 // if the parent is small enough, don't use a backing file
151 // just the buffer memory
152 if (!m_stream
&& m_filelen
== 0)
153 return m_parenterror
;
155 // before refilling the buffer write out the current buffer
156 // to the backing file if there is anything in it
159 if (!m_file
.IsOpened())
160 if (!wxCreateTempFile(m_prefix
, &m_file
, &m_filename
))
161 return wxSTREAM_READ_ERROR
;
163 if (m_file
.Seek(m_filelen
) == wxBadSeek
)
164 return wxSTREAM_READ_ERROR
;
166 size_t count
= m_file
.Write(m_buf
, m_buflen
);
169 if (count
< m_buflen
) {
175 m_parenterror
= wxSTREAM_READ_ERROR
;
176 return m_parenterror
;
187 return m_parenterror
;
190 m_buflen
= m_stream
->Read(m_buf
, m_bufsize
).LastRead();
192 if (m_buflen
< m_bufsize
) {
193 m_parenterror
= m_stream
->GetLastError();
194 if (m_parenterror
== wxSTREAM_NO_ERROR
)
195 m_parenterror
= wxSTREAM_EOF
;
200 // copy to the user's buffer
201 size_t start
= size_t(pos
- m_filelen
);
202 size_t len
= wxMin(m_buflen
- start
, reqestedSize
- *size
);
204 memcpy((char*)buffer
+ *size
, m_buf
+ start
, len
);
210 return wxSTREAM_NO_ERROR
;
213 wxFileOffset
wxBackingFileImpl::GetLength() const
215 if (m_parenterror
!= wxSTREAM_EOF
) {
217 return m_stream
->GetLength();
219 return m_filelen
+ m_buflen
;
223 /////////////////////////////////////////////////////////////////////////////
224 // Backing File, the handle part
226 wxBackingFile::wxBackingFile(wxInputStream
*stream
,
228 const wxString
& prefix
)
229 : m_impl(new wxBackingFileImpl(stream
, bufsize
, prefix
))
233 wxBackingFile::wxBackingFile(const wxBackingFile
& backer
)
234 : m_impl(backer
.m_impl
? backer
.m_impl
->AddRef() : NULL
)
238 wxBackingFile
& wxBackingFile::operator=(const wxBackingFile
& backer
)
240 if (backer
.m_impl
!= m_impl
) {
244 m_impl
= backer
.m_impl
;
253 wxBackingFile::~wxBackingFile()
260 /////////////////////////////////////////////////////////////////////////////
263 wxBackedInputStream::wxBackedInputStream(const wxBackingFile
& backer
)
269 wxFileOffset
wxBackedInputStream::GetLength() const
271 return m_backer
.m_impl
->GetLength();
274 wxFileOffset
wxBackedInputStream::FindLength() const
276 wxFileOffset len
= GetLength();
278 if (len
== wxInvalidOffset
&& IsOk()) {
279 // read a byte at 7ff...ffe
280 wxFileOffset pos
= 1;
281 pos
<<= sizeof(pos
) * 8 - 1;
285 m_backer
.m_impl
->ReadAt(pos
, &ch
, &size
);
292 size_t wxBackedInputStream::OnSysRead(void *buffer
, size_t size
)
297 m_lasterror
= m_backer
.m_impl
->ReadAt(m_pos
, buffer
, &size
);
302 wxFileOffset
wxBackedInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
312 wxFileOffset len
= GetLength();
313 if (len
== wxInvalidOffset
)
314 return wxInvalidOffset
;
328 wxFileOffset
wxBackedInputStream::OnSysTell() const
333 #endif // wxUSE_FILESYSTEM