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
29namespace Strigi {
30
31/** Used to indicate the current status of a Stream */
32enum 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 */
52class STREAMS_EXPORT StreamBaseBase { //krazy:exclude=dpointer
53protected:
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;
65public:
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 */
113template <class T>
114class StreamBase : public StreamBaseBase {
115public:
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 */
196typedef StreamBase<char> InputStream;
197
198/** Abstract class for a stream of Unicode characters */
199typedef StreamBase<wchar_t> Reader;
200
201
202template <class T>
203int64_t
204StreamBase<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