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