1 : /******************************************************************************
2 : * $Id: cpl_vsil_buffered_reader.cpp 22109 2011-04-03 18:39:59Z rouault $
3 : *
4 : * Project: VSI Virtual File System
5 : * Purpose: Implementation of buffered reader IO functions.
6 : * Author: Even Rouault, even.rouault at mines-paris.org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : /* The intent of this class is to be a wrapper around an underlying virtual */
31 : /* handle and add very basic caching of last read bytes, so that a backward */
32 : /* seek of a few bytes doesn't require a seek on the underlying virtual handle. */
33 : /* This enable us to improve dramatically the performance of CPLReadLine2L() on */
34 : /* a gzip file */
35 :
36 : #include "cpl_vsi_virtual.h"
37 :
38 : #define MAX_BUFFER_SIZE 65536
39 :
40 : CPL_CVSID("$Id: cpl_vsil_buffered_reader.cpp 22109 2011-04-03 18:39:59Z rouault $");
41 :
42 : class VSIBufferedReaderHandle : public VSIVirtualHandle
43 : {
44 : VSIVirtualHandle* poBaseHandle;
45 : char pabyBuffer[MAX_BUFFER_SIZE];
46 : GUIntBig nBufferOffset;
47 : int nBufferSize;
48 : GUIntBig nCurOffset;
49 : int bNeedBaseHandleSeek;
50 : int bEOF;
51 :
52 : public:
53 :
54 : VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle);
55 : ~VSIBufferedReaderHandle();
56 :
57 : virtual int Seek( vsi_l_offset nOffset, int nWhence );
58 : virtual vsi_l_offset Tell();
59 : virtual size_t Read( void *pBuffer, size_t nSize, size_t nMemb );
60 : virtual size_t Write( const void *pBuffer, size_t nSize, size_t nMemb );
61 : virtual int Eof();
62 : virtual int Flush();
63 : virtual int Close();
64 : };
65 :
66 : /************************************************************************/
67 : /* VSICreateBufferedReaderHandle() */
68 : /************************************************************************/
69 :
70 556 : VSIVirtualHandle* VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
71 : {
72 556 : return new VSIBufferedReaderHandle(poBaseHandle);
73 : }
74 :
75 : /************************************************************************/
76 : /* VSIBufferedReaderHandle() */
77 : /************************************************************************/
78 :
79 556 : VSIBufferedReaderHandle::VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
80 : {
81 556 : this->poBaseHandle = poBaseHandle;
82 556 : nBufferOffset = 0;
83 556 : nBufferSize = 0;
84 556 : nCurOffset = 0;
85 556 : bNeedBaseHandleSeek = FALSE;
86 556 : bEOF = FALSE;
87 556 : }
88 :
89 : /************************************************************************/
90 : /* ~VSIBufferedReaderHandle() */
91 : /************************************************************************/
92 :
93 556 : VSIBufferedReaderHandle::~VSIBufferedReaderHandle()
94 : {
95 556 : delete poBaseHandle;
96 556 : }
97 :
98 : /************************************************************************/
99 : /* Seek() */
100 : /************************************************************************/
101 :
102 146126 : int VSIBufferedReaderHandle::Seek( vsi_l_offset nOffset, int nWhence )
103 : {
104 : //CPLDebug( "BUFFERED", "Seek(%d,%d)", (int)nOffset, (int)nWhence);
105 146126 : bEOF = FALSE;
106 146126 : if (nWhence == SEEK_CUR)
107 118 : nCurOffset += nOffset;
108 146008 : else if (nWhence == SEEK_END)
109 : {
110 356 : poBaseHandle->Seek(nOffset, nWhence);
111 356 : nCurOffset = poBaseHandle->Tell();
112 356 : bNeedBaseHandleSeek = TRUE;
113 : }
114 : else
115 145652 : nCurOffset = nOffset;
116 :
117 146126 : return 0;
118 : }
119 :
120 : /************************************************************************/
121 : /* Tell() */
122 : /************************************************************************/
123 :
124 140192 : vsi_l_offset VSIBufferedReaderHandle::Tell()
125 : {
126 : //CPLDebug( "BUFFERED", "Tell() = %d", (int)nCurOffset);
127 140192 : return nCurOffset;
128 : }
129 : /************************************************************************/
130 : /* Read() */
131 : /************************************************************************/
132 :
133 148656 : size_t VSIBufferedReaderHandle::Read( void *pBuffer, size_t nSize, size_t nMemb )
134 : {
135 148656 : const size_t nTotalToRead = nSize * nMemb;
136 : //CPLDebug( "BUFFERED", "Read(%d)", (int)nTotalToRead);
137 :
138 148656 : if (nSize == 0)
139 0 : return 0;
140 :
141 148656 : if (nBufferSize != 0 &&
142 : nCurOffset >= nBufferOffset && nCurOffset <= nBufferOffset + nBufferSize)
143 : {
144 : /* We try to read from an offset located within the buffer */
145 144622 : const int nReadInBuffer = (int) MIN(nTotalToRead, nBufferOffset + nBufferSize - nCurOffset);
146 144622 : memcpy(pBuffer, pabyBuffer + nCurOffset - nBufferOffset, nReadInBuffer);
147 144622 : const int nToReadInFile = nTotalToRead - nReadInBuffer;
148 144622 : if (nToReadInFile > 0)
149 : {
150 : /* The beginning of the the data to read is located in the buffer */
151 : /* but the end must be read from the file */
152 144262 : if (bNeedBaseHandleSeek)
153 24 : poBaseHandle->Seek(nBufferOffset + nBufferSize, SEEK_SET);
154 144262 : bNeedBaseHandleSeek = FALSE;
155 : //CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
156 :
157 144262 : const int nReadInFile = poBaseHandle->Read((GByte*)pBuffer + nReadInBuffer, 1, nToReadInFile);
158 144262 : const int nRead = nReadInBuffer + nReadInFile;
159 :
160 144262 : nBufferSize = MIN(nRead, MAX_BUFFER_SIZE);
161 144262 : nBufferOffset = nCurOffset + nRead - nBufferSize;
162 144262 : memcpy(pabyBuffer, (GByte*)pBuffer + nRead - nBufferSize, nBufferSize);
163 :
164 144262 : nCurOffset += nRead;
165 : //CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
166 : //CPLAssert(poBaseHandle->Tell() == nCurOffset);
167 :
168 144262 : bEOF = poBaseHandle->Eof();
169 :
170 144262 : return nRead / nSize;
171 : }
172 : else
173 : {
174 : /* The data to read is completely located within the buffer */
175 360 : nCurOffset += nTotalToRead;
176 360 : return nTotalToRead / nSize;
177 : }
178 : }
179 : else
180 : {
181 : /* We try either to read before or after the buffer, so a seek is necessary */
182 4034 : poBaseHandle->Seek(nCurOffset, SEEK_SET);
183 4034 : bNeedBaseHandleSeek = FALSE;
184 4034 : const int nReadInFile = poBaseHandle->Read(pBuffer, 1, nTotalToRead);
185 4034 : nBufferSize = MIN(nReadInFile, MAX_BUFFER_SIZE);
186 4034 : nBufferOffset = nCurOffset + nReadInFile - nBufferSize;
187 4034 : memcpy(pabyBuffer, (GByte*)pBuffer + nReadInFile - nBufferSize, nBufferSize);
188 :
189 4034 : nCurOffset += nReadInFile;
190 : //CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
191 : //CPLAssert(poBaseHandle->Tell() == nCurOffset);
192 :
193 4034 : bEOF = poBaseHandle->Eof();
194 :
195 4034 : return nReadInFile / nSize;
196 : }
197 :
198 : }
199 :
200 : /************************************************************************/
201 : /* Write() */
202 : /************************************************************************/
203 :
204 0 : size_t VSIBufferedReaderHandle::Write( const void *pBuffer, size_t nSize, size_t nMemb )
205 : {
206 : CPLError(CE_Failure, CPLE_NotSupported,
207 0 : "VSIFWriteL is not supported on buffer reader streams\n");
208 0 : return 0;
209 : }
210 :
211 :
212 : /************************************************************************/
213 : /* Eof() */
214 : /************************************************************************/
215 :
216 268 : int VSIBufferedReaderHandle::Eof()
217 : {
218 268 : return bEOF;
219 : }
220 :
221 : /************************************************************************/
222 : /* Flush() */
223 : /************************************************************************/
224 :
225 0 : int VSIBufferedReaderHandle::Flush()
226 : {
227 0 : return 0;
228 : }
229 :
230 : /************************************************************************/
231 : /* Close() */
232 : /************************************************************************/
233 :
234 556 : int VSIBufferedReaderHandle::Close()
235 : {
236 556 : if (poBaseHandle)
237 : {
238 556 : poBaseHandle->Close();
239 556 : delete poBaseHandle;
240 556 : poBaseHandle = NULL;
241 : }
242 556 : return 0;
243 : }
|