Qore Programming Language 1.19.1
Loading...
Searching...
No Matches
StreamReader.h
1/* -*- mode: c++; indent-tabs-mode: nil -*- */
2/*
3 StreamReader.h
4
5 Qore Programming Language
6
7 Copyright (C) 2016 - 2023 Qore Technologies, s.r.o.
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the "Software"),
11 to deal in the Software without restriction, including without limitation
12 the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 and/or sell copies of the Software, and to permit persons to whom the
14 Software is furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26
27 Note that the Qore library is released under a choice of three open-source
28 licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
29 information.
30*/
31
32#ifndef _QORE_STREAMREADER_H
33#define _QORE_STREAMREADER_H
34
35#include <cstdint>
36
37#include "qore/qore_bitopts.h"
38#include "qore/InputStream.h"
39#include "qore/intern/StringReaderHelper.h"
40
41DLLLOCAL extern qore_classid_t CID_STREAMREADER;
42DLLLOCAL extern QoreClass* QC_STREAMREADER;
43
46public:
47 DLLLOCAL StreamReader(ExceptionSink* xsink, InputStream* is, const QoreEncoding* encoding = QCS_DEFAULT) :
48 in(is, xsink), enc(encoding) {
49 }
50
51 virtual DLLLOCAL ~StreamReader() {
52 }
53
54 DLLLOCAL const QoreEncoding* getEncoding() const {
55 return enc;
56 }
57
58 DLLLOCAL InputStream* getInputStream() {
59 return *in;
60 }
61
62 DLLLOCAL const InputStream* getInputStream() const {
63 return *in;
64 }
65
66 DLLLOCAL void setEncoding(const QoreEncoding* n_enc) {
67 enc = n_enc;
68 }
69
71
77 DLLLOCAL BinaryNode* readBinary(int64 limit, ExceptionSink* xsink) {
78 if (limit == 0)
79 return 0;
81 char buffer[STREAMREADER_BUFFER_SIZE];
82 if (limit == -1) {
83 while (true) {
84 int rc = readData(xsink, buffer, STREAMREADER_BUFFER_SIZE, false);
85 if (*xsink)
86 return 0;
87 if (rc == 0)
88 break;
89 b->append(buffer, rc);
90 }
91 } else {
92 while (limit > 0) {
93 int rc = readData(xsink, buffer, QORE_MIN(limit, STREAMREADER_BUFFER_SIZE), false);
94 if (*xsink)
95 return 0;
96 if (rc == 0)
97 break;
98 b->append(buffer, rc);
99 limit -= rc;
100 }
101 }
102
103 return b->empty() ? 0 : b.release();
104 }
105
107
114 return q_read_string(xsink, size, enc, std::bind(&StreamReader::readData, this, _3, _1, _2, false));
115 }
116
118
126 DLLLOCAL QoreStringNode* readLine(const QoreStringNode* eol, bool trim, ExceptionSink* xsink) {
127 if (!eol && !enc->isAsciiCompat()) {
128 QoreString nl("\n");
129 return readLineEol(&nl, trim, xsink);
130 }
131
132 return eol ? readLineEol(eol, trim, xsink) : readLine(trim, xsink);
133 }
134
135 DLLLOCAL QoreStringNode* readLineEol(const QoreString* eol, bool trim, ExceptionSink* xsink) {
136 TempEncodingHelper eolstr(eol, enc, xsink);
137 if (*xsink)
138 return 0;
139 eolstr.removeBom();
140
142
143 size_t eolpos = 0;
144
145 while (true) {
146 signed char c;
147 int64 rc = readData(xsink, &c, 1, false);
148 //printd(5, "StreamReader::readLineEol() eolpos: %d/%d rc: %d c: %d str: '%s' (%s)\n", eolpos,
149 // eolstr->size(), rc, c, str->c_str(), enc->getCode());
150 if (*xsink)
151 return 0;
152 if (!rc)
153 return str->empty() ? 0 : q_remove_bom_utf16(str.release(), enc);
154
155 // add the char to the string
156 str->concat(c);
157
158 if ((**eolstr)[eolpos] == c) {
159 ++eolpos;
160 if (eolpos == eolstr->size()) {
161 if (trim)
162 str->terminate(str->size() - eolpos);
163 return q_remove_bom_utf16(str.release(), enc);
164 }
165 } else if (eolpos) {
166 // check all positions to see if the string matches
167 bool found = false;
168 for (size_t i = eolpos; i; --i) {
169 // we have to use memcmp here because we could be dealing with character
170 // encodings that include nulls in the string (ex: UTF-16*)
171 if (!memcmp(eolstr->c_str(), str->c_str() + str->size() - i, i)) {
172 found = true;
173 if (eolpos != i)
174 eolpos = i;
175 break;
176 }
177 }
178 if (!found)
179 eolpos = 0;
180 }
181 }
182 }
183
184 DLLLOCAL QoreStringNode* readNullTerminatedString(ExceptionSink* xsink) {
186
187 while (true) {
188 signed char c;
189 int64 rc = readData(xsink, &c, 1, false);
190 if (*xsink) {
191 return nullptr;
192 }
193 if (!rc) { // End of stream
194 xsink->raiseException("END-OF-STREAM-ERROR", "%d byte%s read of null-terminated string; end of "
195 "stream encountered without a null", (int)str->size(), str->size() == 1 ? "" : "s");
196 return nullptr;
197 }
198
199 if (!c) {
200 break;
201 }
202 str->concat(c);
203 }
204 return str.release();
205 }
206
207 DLLLOCAL QoreStringNode* readExactString(size_t size, ExceptionSink* xsink) {
209 if (*xsink) {
210 return nullptr;
211 }
212 if (str->size() < size) {
213 xsink->raiseException("END-OF-STREAM-ERROR", QLLD " byte%s read of " QLLD "-byte string; end of stream "
214 "encountered", str->size(), str->size() == 1 ? "" : "s", size);
215 return nullptr;
216 }
217 assert(str->size() == size);
218 return str.release();
219 }
220
221 DLLLOCAL QoreStringNode* readLine(bool trim, ExceptionSink* xsink) {
223
224 while (true) {
225 signed char c;
226 int64 rc = readData(xsink, &c, 1, false);
227 if (*xsink)
228 return 0;
229 if (!rc) { // End of stream.
230 return str->empty() ? 0 : str.release();
231 }
232
233 if (c == '\n') {
234 if (!trim)
235 str->concat(c);
236 return str.release();
237 } else if (c == '\r') {
238 if (!trim)
239 str->concat(c);
240 int64 p = peek(xsink);
241 if (*xsink)
242 return 0;
243 if (p == '\n') {
244 readData(xsink, &c, 1);
245 if (!trim)
246 str->concat((char)p);
247 }
248 return str.release();
249 }
250 str->concat(c);
251 }
252 }
253
254 DLLLOCAL int64 readi1(ExceptionSink* xsink) {
255 signed char i = 0;
256 if (readData(xsink, &i, 1) < 0) {
257 return 0;
258 }
259 return i;
260 }
261
262 DLLLOCAL int64 readi2(ExceptionSink* xsink) {
263 signed short i = 0;
264 if (readData(xsink, &i, 2) < 0)
265 return 0;
266 i = ntohs(i);
267 return i;
268 }
269
270 DLLLOCAL int64 readi4(ExceptionSink* xsink) {
271 int32_t i = 0;
272 if (readData(xsink, &i, 4) < 0)
273 return 0;
274 i = ntohl(i);
275 return i;
276 }
277
278 DLLLOCAL int64 readi8(ExceptionSink* xsink) {
279 int64 i = 0;
280 if (readData(xsink, &i, 8) < 0)
281 return 0;
282 i = i8MSB(i);
283 return i;
284 }
285
286 DLLLOCAL int64 readi2LSB(ExceptionSink* xsink) {
287 signed short i = 0;
288 if (readData(xsink, &i, 2) < 0)
289 return 0;
290 i = i2LSB(i);
291 return i;
292 }
293
294 DLLLOCAL int64 readi4LSB(ExceptionSink* xsink) {
295 int32_t i = 0;
296 if (readData(xsink, &i, 4) < 0)
297 return 0;
298 i = i4LSB(i);
299 return i;
300 }
301
302 DLLLOCAL int64 readi8LSB(ExceptionSink* xsink) {
303 int64 i = 0;
304 if (readData(xsink, &i, 8) < 0)
305 return 0;
306 i = i8LSB(i);
307 return i;
308 }
309
310 DLLLOCAL int64 readu1(ExceptionSink* xsink) {
311 unsigned char i = 0;
312 if (readData(xsink, &i, 1) < 0) {
313 return 0;
314 }
315 return i;
316 }
317
318 DLLLOCAL int64 readu2(ExceptionSink* xsink) {
319 unsigned short i = 0;
320 if (readData(xsink, &i, 2) < 0)
321 return 0;
322 i = ntohs(i);
323 return i;
324 }
325
326 DLLLOCAL int64 readu4(ExceptionSink* xsink) {
327 uint32_t i = 0;
328 if (readData(xsink, &i, 4) < 0)
329 return 0;
330 i = ntohl(i);
331 return i;
332 }
333
334 DLLLOCAL int64 readu2LSB(ExceptionSink* xsink) {
335 unsigned short i = 0;
336 if (readData(xsink, &i, 2) < 0)
337 return 0;
338 i = i2LSB(i);
339 return i;
340 }
341
342 DLLLOCAL int64 readu4LSB(ExceptionSink* xsink) {
343 uint32_t i = 0;
344 if (readData(xsink, &i, 4) < 0)
345 return 0;
346 i = i4LSB(i);
347 return i;
348 }
349
356 int64 rc = peek(xsink);
357 if (rc < 0) {
358 if (!*xsink) {
359 if (rc == -1) {
360 xsink->raiseException("END-OF-STREAM-ERROR", "there is not enough data available in the stream; "
361 "1 byte was requested, and 0 were read");
362 } else {
363 assert(*xsink);
364 }
365 }
366 return -1;
367 }
368 return rc;
369 }
370
372
382 DLLLOCAL virtual qore_offset_t read(ExceptionSink* xsink, void* dest, size_t limit, bool require_all = true) {
383 return readData(xsink, dest, limit, require_all);
384 }
385
386 DLLLOCAL virtual const char* getName() const { return "StreamReader"; }
387
388protected:
389 // default buffer size (note that I/O is generally unbuffered in this class)
390 static const int STREAMREADER_BUFFER_SIZE = 4096;
391
394
397
398private:
400
407 DLLLOCAL virtual qore_offset_t readData(ExceptionSink* xsink, void* dest, size_t limit, bool require_all = true) {
408 assert(dest);
409 assert(limit > 0);
410 char* destPtr = static_cast<char*>(dest);
411 size_t read = 0;
412 while (true) {
413 int64 rc = in->read(destPtr + read, limit - read, xsink);
414 if (*xsink)
415 return -1;
416 //printd(5, "StreamReader::readData() dest: %p limit: " QLLD " read: " QLLD " rc: " QLLD " char: %d\n",
417 // dest, limit, read, rc, destPtr[0]);
418 if (!rc) {
419 if (require_all) {
420 xsink->raiseException("END-OF-STREAM-ERROR", "there is not enough data available in the stream; "
421 QSD " byte%s requested, but only " QSD " could be read", limit,
422 limit == 1 ? " was" : "s were", read);
423 return -1;
424 }
425 break;
426 }
427 read += rc;
428 if (read == limit)
429 break;
430 }
431 return read;
432 }
433
439 virtual int64 peek(ExceptionSink* xsink) {
440 return in->peek(xsink);
441 }
442};
443
444#endif // _QORE_STREAMREADER_H
DLLEXPORT const QoreEncoding * QCS_DEFAULT
the default encoding for the Qore library
#define QORE_MIN(a, b)
macro to return the minimum of 2 numbers
Definition: QoreLib.h:616
the base class for all data to be used as private data of Qore objects
Definition: AbstractPrivateData.h:44
holds arbitrary binary data
Definition: BinaryNode.h:41
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:50
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
Interface for private data of input streams.
Definition: InputStream.h:44
virtual int64 peek(ExceptionSink *xsink)=0
Peeks the next byte from the input stream.
virtual int64 read(void *ptr, int64 limit, ExceptionSink *xsink)=0
Reads up to `limit` bytes from the input stream.
defines a Qore-language class
Definition: QoreClass.h:253
defines string encoding functions in Qore
Definition: QoreEncoding.h:83
DLLEXPORT bool isAsciiCompat() const
returns true if the character encoding is backwards-compatible with ASCII
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:93
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
a templated class to manage a reference count of an object that can throw a Qore-language exception w...
Definition: ReferenceHolder.h:52
manages a reference count of a pointer to a class that takes a simple "deref()" call with no argument...
Definition: ReferenceHolder.h:127
Private data for the Qore::StreamReader class.
Definition: StreamReader.h:45
virtual DLLLOCAL qore_offset_t read(ExceptionSink *xsink, void *dest, size_t limit, bool require_all=true)
Read data until a limit.
Definition: StreamReader.h:382
const QoreEncoding * enc
Encoding of the source input stream.
Definition: StreamReader.h:396
DLLLOCAL BinaryNode * readBinary(int64 limit, ExceptionSink *xsink)
Read binary data from the stream.
Definition: StreamReader.h:77
DLLLOCAL QoreStringNode * readString(int64 size, ExceptionSink *xsink)
Read string data from the stream.
Definition: StreamReader.h:113
DLLLOCAL QoreStringNode * readLine(const QoreStringNode *eol, bool trim, ExceptionSink *xsink)
Read one line.
Definition: StreamReader.h:126
ReferenceHolder< InputStream > in
Source input stream.
Definition: StreamReader.h:393
int64 peekCheck(ExceptionSink *xsink)
Peeks the next byte from the input stream.
Definition: StreamReader.h:355
use this class to manage strings where the character encoding must be specified and may be different ...
Definition: QoreString.h:1125
unsigned qore_classid_t
used for the unique class ID for QoreClass objects
Definition: common.h:79
intptr_t qore_offset_t
used for offsets that could be negative
Definition: common.h:76
long long int64
64bit integer type, cannot use int64_t here since it breaks the API on some 64-bit systems due to equ...
Definition: common.h:260