1 | /* This file is part of Strigi Desktop Search |
2 | * |
3 | * Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info> |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Library General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Library General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Library General Public License |
16 | * along with this library; see the file COPYING.LIB. If not, write to |
17 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | * Boston, MA 02110-1301, USA. |
19 | */ |
20 | #ifndef STRIGI_STREAMBASE_H |
21 | #define STRIGI_STREAMBASE_H |
22 | |
23 | #include <stdio.h> |
24 | #include <string> |
25 | #include <strigi/strigiconfig.h> |
26 | |
27 | #define INT32MAX 0x7FFFFFFFL |
28 | |
29 | namespace Strigi { |
30 | |
31 | /** Used to indicate the current status of a Stream */ |
32 | enum StreamStatus { |
33 | Ok /**< Stream is capable of being read from */, |
34 | Eof /**< The end of the Stream has been reached */, |
35 | Error /**< An error occurred. Use error() to find out more information */ |
36 | }; |
37 | |
38 | // java mapping: long=int64, int=int32, byte=uint8_t |
39 | /** |
40 | * The base of all Streams. Do not inherit directly from this class, |
41 | * but from (an instance of) StreamBase |
42 | * |
43 | * This class contains all the non-virtual StreamBase methods |
44 | * that don't depend on a specific Stream type |
45 | * |
46 | * Developer comment: This is needed because of win32 compilation. |
47 | * When we want to access a function outside a lib, we have to export them, |
48 | * but we can't export the template class because this would be somewhat |
49 | * stupid / does not work by design :) |
50 | * Because of this I've introduced this StreamBaseBase class |
51 | */ |
52 | class STREAMS_EXPORT StreamBaseBase { //krazy:exclude=dpointer |
53 | protected: |
54 | /** The size of the stream (-1 if unknown) */ |
55 | int64_t m_size; |
56 | /** The position of the stream */ |
57 | int64_t m_position; |
58 | /** |
59 | * @brief String representation of the last error, or |
60 | * an empty string otherwise |
61 | */ |
62 | std::string m_error; |
63 | /** The status of the stream - see StreamStatus */ |
64 | StreamStatus m_status; |
65 | public: |
66 | /** |
67 | * @brief Constructor: initialises everything to sane defaults |
68 | **/ |
69 | StreamBaseBase() :m_size(-1), m_position(0), m_status(Ok) {} |
70 | /** |
71 | * @brief Destructor |
72 | **/ |
73 | virtual ~StreamBaseBase() {} |
74 | /** |
75 | * @brief Return a string representation of the last error. |
76 | * If no error has occurred, an empty string is returned. |
77 | **/ |
78 | const char* error() const { return m_error.c_str(); } |
79 | /** |
80 | * @brief Return the status of the stream. |
81 | **/ |
82 | StreamStatus status() const { return m_status; } |
83 | /** |
84 | * @brief Get the current position in the stream. |
85 | * The value obtained from this function can be used to reset the stream. |
86 | **/ |
87 | int64_t position() const { return m_position; } |
88 | /** |
89 | * @brief Return the size of the stream. |
90 | * |
91 | * The size of the stream is always known if the end of the stream |
92 | * has been reached. In all other cases, this may return -1 to |
93 | * indicate the size of the stream is unknown. |
94 | * |
95 | * @return the size of the stream, if it is known, or -1 if the size |
96 | * of the stream is unknown |
97 | **/ |
98 | int64_t size() const { return m_size; } |
99 | }; |
100 | |
101 | /** |
102 | * @brief Base class for stream read access to a data source. |
103 | * |
104 | * This class is based on the interface java.io.InputStream. It provides |
105 | * a uniform interface for accessing streamed resources. |
106 | * |
107 | * The main difference with the Java equivalent is a performance improvement. |
108 | * When reading data, data is not copied into a buffer provided by the caller, |
109 | * but a pointer to the read data is provided. This makes this interface |
110 | * especially useful for deriving from it and implementing filters or |
111 | * transformers. |
112 | */ |
113 | template <class T> |
114 | class StreamBase : public StreamBaseBase { |
115 | public: |
116 | StreamBase() { } |
117 | virtual ~StreamBase(){} |
118 | /** |
119 | * @brief Reads items from the stream and sets @p start to point to |
120 | * the first item that was read. |
121 | * |
122 | * Note: unless stated otherwise in the documentation for that method, |
123 | * this pointer will no longer be valid after calling another method of |
124 | * this class. The pointer will also no longer be valid after the class |
125 | * is destroyed. |
126 | * |
127 | * The functions inherited from StreamBaseBase do not invalidate the pointer. |
128 | * |
129 | * At least @p min items will be read from the stream, unless an error occurs |
130 | * or the end of the stream is reached. Under no circumstances will more than |
131 | * @p max items be read. |
132 | * |
133 | * If the end of the stream is reached before @p min items are read, the |
134 | * read is still considered successful and the number of items read will |
135 | * be returned. |
136 | * |
137 | * @param start pointer passed by reference that will be set to point to |
138 | * the retrieved array of items. If the end of the stream |
139 | * is encountered or an error occurs, the value of @p start |
140 | * is undefined |
141 | * @param min the minimal number of items to read from the stream. This |
142 | * value should be larger than 0. If it is 0 or smaller, the |
143 | * result is undefined |
144 | * @param max the maximal number of items to read from the stream. |
145 | * If this value is smaller than @p min, there is no limit on |
146 | * the number of items that can be read |
147 | * @return the number of items that were read. @c -1 is returned if |
148 | * end of the stream has already been reached. @c -2 is returned |
149 | * if an error has occurred |
150 | **/ |
151 | virtual int32_t read(const T*& start, int32_t min, int32_t max) = 0; |
152 | /** |
153 | * @brief Skip @p ntoskip items. |
154 | * |
155 | * If an error occurs, or the end of the stream is encountered, fewer |
156 | * than @p ntoskip items may be skipped. This can be checked by comparing |
157 | * the return value to @p ntoskip. |
158 | * |
159 | * Calling this function invalidates the data pointer that was obtained from |
160 | * StreamBase::read. |
161 | * |
162 | * @param ntoskip the number of items that should be skipped |
163 | * @return the number of items skipped |
164 | **/ |
165 | virtual int64_t skip(int64_t ntoskip); |
166 | /** |
167 | * @brief Repositions this stream to a given position. |
168 | * |
169 | * A call to StreamBase::reset is only guaranteed to be successful when |
170 | * the requested position lies within the segment of a stream |
171 | * corresponding to a valid pointer obtained from StreamBase::read. |
172 | * In this case, the pointer will not be invalidated. |
173 | * |
174 | * Calling this function invalidates the data pointer that was obtained from |
175 | * StreamBase::read unless the conditions outlined above apply. |
176 | * |
177 | * To read n items, leaving the stream at the same position as before, you |
178 | * can do the following: |
179 | * @code |
180 | * int64_t start = stream.position(); |
181 | * if ( stream.read(data, min, max) > 0 ) { |
182 | * stream.reset(start); |
183 | * // The data pointer is still valid here |
184 | * } |
185 | * @endcode |
186 | * |
187 | * @param pos the position in the stream you want to go to, relative to |
188 | * the start of the stream |
189 | * @return the new position in the stream |
190 | **/ |
191 | virtual int64_t reset(int64_t pos) = 0; |
192 | }; |
193 | |
194 | |
195 | /** Abstract class for a stream of bytes */ |
196 | typedef StreamBase<char> InputStream; |
197 | |
198 | /** Abstract class for a stream of Unicode characters */ |
199 | typedef StreamBase<wchar_t> Reader; |
200 | |
201 | |
202 | template <class T> |
203 | int64_t |
204 | StreamBase<T>::skip(int64_t ntoskip) { |
205 | const T* begin; |
206 | int32_t nread; |
207 | int64_t skipped = 0; |
208 | while (ntoskip > 0) { |
209 | // make sure we do not overflow uint32_t |
210 | int32_t maxstep = (int32_t)((ntoskip > 10000000) |
211 | ?10000000 :ntoskip); |
212 | // the default implementation is to simply read the data that we want |
213 | // to skip |
214 | nread = read(begin, 1, maxstep); |
215 | if (nread < -1 ) { |
216 | // an error occurred |
217 | return nread; |
218 | } else if (nread < 1) { |
219 | // the end of the stream was encountered |
220 | ntoskip = 0; |
221 | } else { |
222 | skipped += nread; |
223 | ntoskip -= nread; |
224 | } |
225 | } |
226 | return skipped; |
227 | } |
228 | |
229 | } // end namespace Strigi |
230 | |
231 | #endif |
232 | |