Qore Programming Language 2.0.0
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 - 2024 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 nullptr;
139 }
140 eolstr.removeBom();
141
143
144 size_t eolpos = 0;
145
146 while (true) {
147 signed char c;
148 int64 rc = readData(xsink, &c, 1, false);
149 //printd(5, "StreamReader::readLineEol() eolpos: %d/%d rc: %d c: %d str: '%s' (%s)\n", eolpos,
150 // eolstr->size(), rc, c, str->c_str(), enc->getCode());
151 if (*xsink)
152 return 0;
153 if (!rc)
154 return str->empty() ? 0 : q_remove_bom_utf16(str.release(), enc);
155
156 // add the char to the string
157 str->concat(c);
158
159 if ((**eolstr)[eolpos] == c) {
160 ++eolpos;
161 if (eolpos == eolstr->size()) {
162 if (trim)
163 str->terminate(str->size() - eolpos);
164 return q_remove_bom_utf16(str.release(), enc);
165 }
166 } else if (eolpos) {
167 // check all positions to see if the string matches
168 bool found = false;
169 for (size_t i = eolpos; i; --i) {
170 // we have to use memcmp here because we could be dealing with character
171 // encodings that include nulls in the string (ex: UTF-16*)
172 if (!memcmp(eolstr->c_str(), str->c_str() + str->size() - i, i)) {
173 found = true;
174 if (eolpos != i)
175 eolpos = i;
176 break;
177 }
178 }
179 if (!found)
180 eolpos = 0;
181 }
182 }
183 }
184
185 DLLLOCAL QoreStringNode* readNullTerminatedString(ExceptionSink* xsink) {
187
188 while (true) {
189 signed char c;
190 int64 rc = readData(xsink, &c, 1, false);
191 if (*xsink) {
192 return nullptr;
193 }
194 if (!rc) { // End of stream
195 xsink->raiseException("END-OF-STREAM-ERROR", "%d byte%s read of null-terminated string; end of "
196 "stream encountered without a null", (int)str->size(), str->size() == 1 ? "" : "s");
197 return nullptr;
198 }
199
200 if (!c) {
201 break;
202 }
203 str->concat(c);
204 }
205 return str.release();
206 }
207
208 DLLLOCAL QoreStringNode* readExactString(size_t size, ExceptionSink* xsink) {
210 if (*xsink) {
211 return nullptr;
212 }
213 if (str->size() < size) {
214 xsink->raiseException("END-OF-STREAM-ERROR", QLLD " byte%s read of " QLLD "-byte string; end of stream "
215 "encountered", str->size(), str->size() == 1 ? "" : "s", size);
216 return nullptr;
217 }
218 assert(str->size() == size);
219 return str.release();
220 }
221
222 DLLLOCAL QoreStringNode* readLine(bool trim, ExceptionSink* xsink) {
224
225 while (true) {
226 signed char c;
227 int64 rc = readData(xsink, &c, 1, false);
228 if (*xsink) {
229 return nullptr;
230 }
231 if (!rc) { // End of stream.
232 return str->empty() ? nullptr : str.release();
233 }
234
235 if (c == '\n') {
236 if (!trim) {
237 str->concat(c);
238 }
239 return str.release();
240 } else if (c == '\r') {
241 if (!trim) {
242 str->concat(c);
243 }
244 int64 p = peek(xsink);
245 if (*xsink) {
246 return nullptr;
247 }
248 if (p == '\n') {
249 readData(xsink, &c, 1);
250 if (!trim) {
251 str->concat((char)p);
252 }
253 }
254 return str.release();
255 }
256 str->concat(c);
257 }
258 }
259
260 DLLLOCAL int64 readi1(ExceptionSink* xsink) {
261 signed char i = 0;
262 if (readData(xsink, &i, 1) < 0) {
263 return 0;
264 }
265 return i;
266 }
267
268 DLLLOCAL int64 readi2(ExceptionSink* xsink) {
269 signed short i = 0;
270 if (readData(xsink, &i, 2) < 0)
271 return 0;
272 i = ntohs(i);
273 return i;
274 }
275
276 DLLLOCAL int64 readi4(ExceptionSink* xsink) {
277 int32_t i = 0;
278 if (readData(xsink, &i, 4) < 0)
279 return 0;
280 i = ntohl(i);
281 return i;
282 }
283
284 DLLLOCAL int64 readi8(ExceptionSink* xsink) {
285 int64 i = 0;
286 if (readData(xsink, &i, 8) < 0)
287 return 0;
288 i = i8MSB(i);
289 return i;
290 }
291
292 DLLLOCAL int64 readi2LSB(ExceptionSink* xsink) {
293 signed short i = 0;
294 if (readData(xsink, &i, 2) < 0)
295 return 0;
296 i = i2LSB(i);
297 return i;
298 }
299
300 DLLLOCAL int64 readi4LSB(ExceptionSink* xsink) {
301 int32_t i = 0;
302 if (readData(xsink, &i, 4) < 0)
303 return 0;
304 i = i4LSB(i);
305 return i;
306 }
307
308 DLLLOCAL int64 readi8LSB(ExceptionSink* xsink) {
309 int64 i = 0;
310 if (readData(xsink, &i, 8) < 0)
311 return 0;
312 i = i8LSB(i);
313 return i;
314 }
315
316 DLLLOCAL int64 readu1(ExceptionSink* xsink) {
317 unsigned char i = 0;
318 if (readData(xsink, &i, 1) < 0) {
319 return 0;
320 }
321 return i;
322 }
323
324 DLLLOCAL int64 readu2(ExceptionSink* xsink) {
325 unsigned short i = 0;
326 if (readData(xsink, &i, 2) < 0)
327 return 0;
328 i = ntohs(i);
329 return i;
330 }
331
332 DLLLOCAL int64 readu4(ExceptionSink* xsink) {
333 uint32_t i = 0;
334 if (readData(xsink, &i, 4) < 0)
335 return 0;
336 i = ntohl(i);
337 return i;
338 }
339
340 DLLLOCAL int64 readu2LSB(ExceptionSink* xsink) {
341 unsigned short i = 0;
342 if (readData(xsink, &i, 2) < 0)
343 return 0;
344 i = i2LSB(i);
345 return i;
346 }
347
348 DLLLOCAL int64 readu4LSB(ExceptionSink* xsink) {
349 uint32_t i = 0;
350 if (readData(xsink, &i, 4) < 0)
351 return 0;
352 i = i4LSB(i);
353 return i;
354 }
355
362 int64 rc = peek(xsink);
363 if (rc < 0) {
364 if (!*xsink) {
365 if (rc == -1) {
366 xsink->raiseException("END-OF-STREAM-ERROR", "there is not enough data available in the stream; "
367 "1 byte was requested, and 0 were read");
368 } else {
369 assert(*xsink);
370 }
371 }
372 return -1;
373 }
374 return rc;
375 }
376
378
388 DLLLOCAL virtual qore_offset_t read(ExceptionSink* xsink, void* dest, size_t limit, bool require_all = true) {
389 return readData(xsink, dest, limit, require_all);
390 }
391
392 DLLLOCAL virtual const char* getName() const { return "StreamReader"; }
393
394protected:
395 // default buffer size (note that I/O is generally unbuffered in this class)
396 static const int STREAMREADER_BUFFER_SIZE = 4096;
397
400
403
404private:
406
413 DLLLOCAL virtual qore_offset_t readData(ExceptionSink* xsink, void* dest, size_t limit, bool require_all = true) {
414 assert(dest);
415 assert(limit > 0);
416 char* destPtr = static_cast<char*>(dest);
417 size_t read = 0;
418 while (true) {
419 int64 rc = in->read(destPtr + read, limit - read, xsink);
420 if (*xsink)
421 return -1;
422 //printd(5, "StreamReader::readData() dest: %p limit: " QLLD " read: " QLLD " rc: " QLLD " char: %d\n",
423 // dest, limit, read, rc, destPtr[0]);
424 if (!rc) {
425 if (require_all) {
426 xsink->raiseException("END-OF-STREAM-ERROR", "there is not enough data available in the stream; "
427 QSD " byte%s requested, but only " QSD " could be read", limit,
428 limit == 1 ? " was" : "s were", read);
429 return -1;
430 }
431 break;
432 }
433 read += rc;
434 if (read == limit)
435 break;
436 }
437 return read;
438 }
439
445 virtual int64 peek(ExceptionSink* xsink) {
446 return in->peek(xsink);
447 }
448};
449
450#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:310
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:388
const QoreEncoding * enc
Encoding of the source input stream.
Definition StreamReader.h:402
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:399
int64 peekCheck(ExceptionSink *xsink)
Peeks the next byte from the input stream.
Definition StreamReader.h:361
use this class to manage strings where the character encoding must be specified and may be different ...
Definition QoreString.h:1191
unsigned qore_classid_t
used for the unique class ID for QoreClass objects
Definition common.h:85
intptr_t qore_offset_t
used for offsets that could be negative
Definition common.h:82
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:266