1 /** @file stream.c
2
3 @authors Copyright (c) 2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4
5 @par License
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15
16 <small>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</small>
26 */
27
28 #include "the_Foundation/stream.h"
29 #include "the_Foundation/block.h"
30 #include "the_Foundation/mutex.h"
31 #include "the_Foundation/stringlist.h"
32 #include "the_Foundation/buffer.h"
33
34 iDefineClass(Stream)
35
36 #define class_Stream(d) ((const iStreamClass *) (d)->object.classObj)
37
38 iDeclareType(ByteOrder)
39
40 struct Impl_ByteOrder {
41 uint16_t (*order16)(uint16_t);
42 uint32_t (*order32)(uint32_t);
43 uint64_t (*order64)(uint64_t);
44 };
45
nop16_(uint16_t v)46 iLocalDef uint16_t nop16_(uint16_t v) { return v; }
nop32_(uint32_t v)47 iLocalDef uint32_t nop32_(uint32_t v) { return v; }
nop64_(uint64_t v)48 iLocalDef uint64_t nop64_(uint64_t v) { return v; }
49
swap16_(uint16_t v)50 iLocalDef uint16_t swap16_(uint16_t v) { return (uint16_t) ((v >> 8) | ((v & 0xff) << 8)); }
swap32_(uint32_t v)51 iLocalDef uint32_t swap32_(uint32_t v) { return (v >> 24) | ((v & 0xff0000) >> 8) | ((v & 0xff00) << 8) | ((v & 0xff) << 24); }
swap64_(uint64_t v)52 iLocalDef uint64_t swap64_(uint64_t v) { return swap32_(v >> 32) | ((uint64_t) (swap32_(v & 0xffffffff)) << 32); }
53
54 #if defined (iBigEndian)
order16le_(uint16_t v)55 static uint16_t order16le_(uint16_t v) { return swap16_(v); }
order32le_(uint32_t v)56 static uint32_t order32le_(uint32_t v) { return swap32_(v); }
order64le_(uint64_t v)57 static uint64_t order64le_(uint64_t v) { return swap64_(v); }
58
order16be_(uint16_t v)59 static uint16_t order16be_(uint16_t v) { return nop16_(v); }
order32be_(uint32_t v)60 static uint32_t order32be_(uint32_t v) { return nop32_(v); }
order64be_(uint64_t v)61 static uint64_t order64be_(uint64_t v) { return nop64_(v); }
62 #else
order16le_(uint16_t v)63 static uint16_t order16le_(uint16_t v) { return nop16_(v); }
order32le_(uint32_t v)64 static uint32_t order32le_(uint32_t v) { return nop32_(v); }
order64le_(uint64_t v)65 static uint64_t order64le_(uint64_t v) { return nop64_(v); }
66
order16be_(uint16_t v)67 static uint16_t order16be_(uint16_t v) { return swap16_(v); }
order32be_(uint32_t v)68 static uint32_t order32be_(uint32_t v) { return swap32_(v); }
order64be_(uint64_t v)69 static uint64_t order64be_(uint64_t v) { return swap64_(v); }
70 #endif
71
72 static const iByteOrder byteOrder_[2] = {
73 /* Little-endian */ { .order16 = order16le_, .order32 = order32le_, .order64 = order64le_ },
74 /* Big-endian */ { .order16 = order16be_, .order32 = order32be_, .order64 = order64be_ }
75 };
76
77 #define ord_Stream(d) (byteOrder_[(d)->flags & bigEndianByteOrder_StreamFlag])
78
79 enum iStreamFlags {
80 bigEndianByteOrder_StreamFlag = 1,
81 versionMask_StreamFlag = 0xfff00,
82 versionShift_StreamFlag = 8,
83 };
84
init_Stream(iStream * d)85 void init_Stream(iStream *d) {
86 d->size = 0;
87 d->pos = 0;
88 d->flags = 0; // little-endian
89 d->mtx = new_Mutex();
90 }
91
deinit_Stream(iStream * d)92 void deinit_Stream(iStream *d) {
93 delete_Mutex(d->mtx);
94 }
95
setByteOrder_Stream(iStream * d,enum iStreamByteOrder byteOrder)96 void setByteOrder_Stream(iStream *d, enum iStreamByteOrder byteOrder) {
97 iChangeFlags(d->flags, bigEndianByteOrder_StreamFlag, byteOrder == bigEndian_StreamByteOrder);
98 }
99
setVersion_Stream(iStream * d,int version)100 void setVersion_Stream(iStream *d, int version) {
101 d->flags &= ~versionMask_StreamFlag;
102 d->flags |= (version << versionShift_StreamFlag) & versionMask_StreamFlag;
103 }
104
setSize_Stream(iStream * d,size_t size)105 void setSize_Stream(iStream *d, size_t size) {
106 iGuardMutex(d->mtx, {
107 d->size = size;
108 d->pos = iMin(d->pos, size);
109 });
110 }
111
byteOrder_Stream(const iStream * d)112 enum iStreamByteOrder byteOrder_Stream(const iStream *d) {
113 return d->flags & bigEndianByteOrder_StreamFlag ? bigEndian_StreamByteOrder
114 : littleEndian_StreamByteOrder;
115 }
116
version_Stream(const iStream * d)117 int version_Stream(const iStream *d) {
118 return (d->flags & versionMask_StreamFlag) >> versionShift_StreamFlag;
119 }
120
seek_Stream(iStream * d,size_t offset)121 void seek_Stream(iStream *d, size_t offset) {
122 iGuardMutex(d->mtx, d->pos = class_Stream(d)->seek(d, offset));
123 }
124
read_Stream(iStream * d,size_t size)125 iBlock *read_Stream(iStream *d, size_t size) {
126 iBlock *data = new_Block(0);
127 readBlock_Stream(d, size, data);
128 return data;
129 }
130
readData_Stream(iStream * d,size_t size,void * data_out)131 size_t readData_Stream(iStream *d, size_t size, void *data_out) {
132 size_t readSize = 0;
133 iGuardMutex(d->mtx, {
134 readSize = class_Stream(d)->read(d, size, data_out);
135 d->pos += readSize;
136 d->size = iMax(d->size, d->pos); // update successfully read size
137 });
138 return readSize;
139 }
140
readBlock_Stream(iStream * d,size_t size,iBlock * data_out)141 size_t readBlock_Stream(iStream *d, size_t size, iBlock *data_out) {
142 resize_Block(data_out, size);
143 const size_t readSize = readData_Stream(d, size, data_Block(data_out));
144 truncate_Block(data_out, readSize);
145 return readSize;
146 }
147
readAll_Stream(iStream * d)148 iBlock *readAll_Stream(iStream *d) {
149 iBlock *data = new_Block(0);
150 iBlock *chunk = new_Block(0);
151 for (;;) {
152 size_t readSize = readBlock_Stream(d, 128 * 1024, chunk);
153 if (!readSize) break;
154 append_Block(data, chunk);
155 }
156 delete_Block(chunk);
157 return data;
158 }
159
write_Stream(iStream * d,const iBlock * data)160 size_t write_Stream(iStream *d, const iBlock *data) {
161 return writeData_Stream(d, constData_Block(data), size_Block(data));
162 }
163
writeData_Stream(iStream * d,const void * data,size_t size)164 size_t writeData_Stream(iStream *d, const void *data, size_t size) {
165 size_t n = 0;
166 iGuardMutex(d->mtx, {
167 n = class_Stream(d)->write(d, data, size);
168 d->pos += n;
169 d->size = iMax(d->pos, d->size);
170 });
171 return n;
172 }
173
writeBuffer_Stream(iStream * d,const iBuffer * buf)174 size_t writeBuffer_Stream(iStream *d, const iBuffer *buf) {
175 return write_Stream(d, data_Buffer(buf));
176 }
177
readLines_Stream(iStream * d)178 iStringList *readLines_Stream(iStream *d) {
179 iBlock *data = readAll_Stream(d);
180 iStringList *lines = split_String((iString *) data, "\n");
181 delete_Block(data);
182 return lines;
183 }
184
printf_Stream(iStream * d,const char * format,...)185 size_t printf_Stream(iStream *d, const char *format, ...) {
186 va_list args;
187 va_start(args, format);
188 iBlock str;
189 init_Block(&str, 0);
190 vprintf_Block(&str, format, args);
191 const size_t len = write_Stream(d, &str);
192 deinit_Block(&str);
193 va_end(args);
194 return len;
195 }
196
flush_Stream(iStream * d)197 void flush_Stream(iStream *d) {
198 class_Stream(d)->flush(d);
199 }
200
readString_Stream(iStream * d)201 iString *readString_Stream(iStream *d) {
202 iBlock *chars = readAll_Stream(d);
203 iString *str = newBlock_String(chars);
204 delete_Block(chars);
205 return str;
206 }
207
writeObject_Stream(iStream * d,const iAnyObject * object)208 size_t writeObject_Stream(iStream *d, const iAnyObject *object) {
209 iAssert(class_Object(object)->serialize != NULL);
210 const size_t start = d->pos;
211 class_Object(object)->serialize(object, d);
212 iAssert(d->pos >= start);
213 return d->pos - start;
214 }
215
readObject_Stream(iStream * d,const iAnyClass * class)216 iAnyObject *readObject_Stream(iStream *d, const iAnyClass *class) {
217 const iClass *cls = (const iClass *) class;
218 iAssert(cls->newObject);
219 iAssert(cls->deserialize);
220 iAnyObject *obj = cls->newObject();
221 cls->deserialize(obj, d);
222 return obj;
223 }
224
write16_Stream(iStream * d,int16_t value)225 void write16_Stream(iStream *d, int16_t value) {
226 const uint16_t data = ord_Stream(d).order16(value);
227 writeData_Stream(d, &data, 2);
228 }
229
write32_Stream(iStream * d,int32_t value)230 void write32_Stream(iStream *d, int32_t value) {
231 const uint32_t data = ord_Stream(d).order32(value);
232 writeData_Stream(d, &data, 4);
233 }
234
write64_Stream(iStream * d,int64_t value)235 void write64_Stream(iStream *d, int64_t value) {
236 const uint64_t data = ord_Stream(d).order64(value);
237 writeData_Stream(d, &data, 8);
238 }
239
read8_Stream(iStream * d)240 int8_t read8_Stream(iStream *d) {
241 int8_t value = 0;
242 readData_Stream(d, 1, &value);
243 return value;
244 }
245
read16_Stream(iStream * d)246 int16_t read16_Stream(iStream *d) {
247 uint16_t data = 0;
248 readData_Stream(d, 2, &data);
249 return ord_Stream(d).order16(data);
250 }
251
read32_Stream(iStream * d)252 int32_t read32_Stream(iStream *d) {
253 uint32_t data = 0;
254 readData_Stream(d, 4, &data);
255 return ord_Stream(d).order32(data);
256 }
257
read64_Stream(iStream * d)258 int64_t read64_Stream(iStream *d) {
259 uint64_t data = 0;
260 readData_Stream(d, 8, &data);
261 return ord_Stream(d).order64(data);
262 }
263