1/* see copyright notice in squirrel.h */
2#include <new>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <squirrel.h>
7#include <sqstdio.h>
8#include <sqstdblob.h>
9#include "sqstdstream.h"
10#include "sqstdblobimpl.h"
11
12#define SETUP_STREAM(v) \
13 SQStream *self = NULL; \
14 if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG)))) \
15 return sq_throwerror(v,_SC("invalid type tag")); \
16 if(!self || !self->IsValid()) \
17 return sq_throwerror(v,_SC("the stream is invalid"));
18
19SQInteger _stream_readblob(HSQUIRRELVM v)
20{
21 SETUP_STREAM(v);
22 SQUserPointer data,blobp;
23 SQInteger size,res;
24 sq_getinteger(v,2,&size);
25 if(size > self->Len()) {
26 size = self->Len();
27 }
28 data = sq_getscratchpad(v,size);
29 res = self->Read(data,size);
30 if(res <= 0)
31 return sq_throwerror(v,_SC("no data left to read"));
32 blobp = sqstd_createblob(v,res);
33 memcpy(blobp,data,res);
34 return 1;
35}
36
37#define SAFE_READN(ptr,len) { \
38 if(self->Read(ptr,len) != len) return sq_throwerror(v,_SC("io error")); \
39 }
40SQInteger _stream_readn(HSQUIRRELVM v)
41{
42 SETUP_STREAM(v);
43 SQInteger format;
44 sq_getinteger(v, 2, &format);
45 switch(format) {
46 case 'l': {
47 SQInteger i;
48 SAFE_READN(&i, sizeof(i));
49 sq_pushinteger(v, i);
50 }
51 break;
52 case 'i': {
53 SQInt32 i;
54 SAFE_READN(&i, sizeof(i));
55 sq_pushinteger(v, i);
56 }
57 break;
58 case 's': {
59 short s;
60 SAFE_READN(&s, sizeof(short));
61 sq_pushinteger(v, s);
62 }
63 break;
64 case 'w': {
65 unsigned short w;
66 SAFE_READN(&w, sizeof(unsigned short));
67 sq_pushinteger(v, w);
68 }
69 break;
70 case 'c': {
71 char c;
72 SAFE_READN(&c, sizeof(char));
73 sq_pushinteger(v, c);
74 }
75 break;
76 case 'b': {
77 unsigned char c;
78 SAFE_READN(&c, sizeof(unsigned char));
79 sq_pushinteger(v, c);
80 }
81 break;
82 case 'f': {
83 float f;
84 SAFE_READN(&f, sizeof(float));
85 sq_pushfloat(v, f);
86 }
87 break;
88 case 'd': {
89 double d;
90 SAFE_READN(&d, sizeof(double));
91 sq_pushfloat(v, (SQFloat)d);
92 }
93 break;
94 default:
95 return sq_throwerror(v, _SC("invalid format"));
96 }
97 return 1;
98}
99
100SQInteger _stream_writeblob(HSQUIRRELVM v)
101{
102 SQUserPointer data;
103 SQInteger size;
104 SETUP_STREAM(v);
105 if(SQ_FAILED(sqstd_getblob(v,2,&data)))
106 return sq_throwerror(v,_SC("invalid parameter"));
107 size = sqstd_getblobsize(v,2);
108 if(self->Write(data,size) != size)
109 return sq_throwerror(v,_SC("io error"));
110 sq_pushinteger(v,size);
111 return 1;
112}
113
114SQInteger _stream_writen(HSQUIRRELVM v)
115{
116 SETUP_STREAM(v);
117 SQInteger format, ti;
118 SQFloat tf;
119 sq_getinteger(v, 3, &format);
120 switch(format) {
121 case 'l': {
122 SQInteger i;
123 sq_getinteger(v, 2, &ti);
124 i = ti;
125 self->Write(&i, sizeof(SQInteger));
126 }
127 break;
128 case 'i': {
129 SQInt32 i;
130 sq_getinteger(v, 2, &ti);
131 i = (SQInt32)ti;
132 self->Write(&i, sizeof(SQInt32));
133 }
134 break;
135 case 's': {
136 short s;
137 sq_getinteger(v, 2, &ti);
138 s = (short)ti;
139 self->Write(&s, sizeof(short));
140 }
141 break;
142 case 'w': {
143 unsigned short w;
144 sq_getinteger(v, 2, &ti);
145 w = (unsigned short)ti;
146 self->Write(&w, sizeof(unsigned short));
147 }
148 break;
149 case 'c': {
150 char c;
151 sq_getinteger(v, 2, &ti);
152 c = (char)ti;
153 self->Write(&c, sizeof(char));
154 }
155 break;
156 case 'b': {
157 unsigned char b;
158 sq_getinteger(v, 2, &ti);
159 b = (unsigned char)ti;
160 self->Write(&b, sizeof(unsigned char));
161 }
162 break;
163 case 'f': {
164 float f;
165 sq_getfloat(v, 2, &tf);
166 f = (float)tf;
167 self->Write(&f, sizeof(float));
168 }
169 break;
170 case 'd': {
171 double d;
172 sq_getfloat(v, 2, &tf);
173 d = tf;
174 self->Write(&d, sizeof(double));
175 }
176 break;
177 default:
178 return sq_throwerror(v, _SC("invalid format"));
179 }
180 return 0;
181}
182
183SQInteger _stream_seek(HSQUIRRELVM v)
184{
185 SETUP_STREAM(v);
186 SQInteger offset, origin = SQ_SEEK_SET;
187 sq_getinteger(v, 2, &offset);
188 if(sq_gettop(v) > 2) {
189 SQInteger t;
190 sq_getinteger(v, 3, &t);
191 switch(t) {
192 case 'b': origin = SQ_SEEK_SET; break;
193 case 'c': origin = SQ_SEEK_CUR; break;
194 case 'e': origin = SQ_SEEK_END; break;
195 default: return sq_throwerror(v,_SC("invalid origin"));
196 }
197 }
198 sq_pushinteger(v, self->Seek(offset, origin));
199 return 1;
200}
201
202SQInteger _stream_tell(HSQUIRRELVM v)
203{
204 SETUP_STREAM(v);
205 sq_pushinteger(v, self->Tell());
206 return 1;
207}
208
209SQInteger _stream_len(HSQUIRRELVM v)
210{
211 SETUP_STREAM(v);
212 sq_pushinteger(v, self->Len());
213 return 1;
214}
215
216SQInteger _stream_flush(HSQUIRRELVM v)
217{
218 SETUP_STREAM(v);
219 if(!self->Flush())
220 sq_pushinteger(v, 1);
221 else
222 sq_pushnull(v);
223 return 1;
224}
225
226SQInteger _stream_eos(HSQUIRRELVM v)
227{
228 SETUP_STREAM(v);
229 if(self->EOS())
230 sq_pushinteger(v, 1);
231 else
232 sq_pushnull(v);
233 return 1;
234}
235
236 SQInteger _stream__cloned(HSQUIRRELVM v)
237 {
238 return sq_throwerror(v,_SC("this object cannot be cloned"));
239 }
240
241static const SQRegFunction _stream_methods[] = {
242 _DECL_STREAM_FUNC(readblob,2,_SC("xn")),
243 _DECL_STREAM_FUNC(readn,2,_SC("xn")),
244 _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")),
245 _DECL_STREAM_FUNC(writen,3,_SC("xnn")),
246 _DECL_STREAM_FUNC(seek,-2,_SC("xnn")),
247 _DECL_STREAM_FUNC(tell,1,_SC("x")),
248 _DECL_STREAM_FUNC(len,1,_SC("x")),
249 _DECL_STREAM_FUNC(eos,1,_SC("x")),
250 _DECL_STREAM_FUNC(flush,1,_SC("x")),
251 _DECL_STREAM_FUNC(_cloned,0,NULL),
252 {NULL,(SQFUNCTION)0,0,NULL}
253};
254
255void init_streamclass(HSQUIRRELVM v)
256{
257 sq_pushregistrytable(v);
258 sq_pushstring(v,_SC("std_stream"),-1);
259 if(SQ_FAILED(sq_get(v,-2))) {
260 sq_pushstring(v,_SC("std_stream"),-1);
261 sq_newclass(v,SQFalse);
262 sq_settypetag(v,-1,(SQUserPointer)((SQUnsignedInteger)SQSTD_STREAM_TYPE_TAG));
263 SQInteger i = 0;
264 while(_stream_methods[i].name != 0) {
265 const SQRegFunction &f = _stream_methods[i];
266 sq_pushstring(v,f.name,-1);
267 sq_newclosure(v,f.f,0);
268 sq_setparamscheck(v,f.nparamscheck,f.typemask);
269 sq_newslot(v,-3,SQFalse);
270 i++;
271 }
272 sq_newslot(v,-3,SQFalse);
273 sq_pushroottable(v);
274 sq_pushstring(v,_SC("stream"),-1);
275 sq_pushstring(v,_SC("std_stream"),-1);
276 sq_get(v,-4);
277 sq_newslot(v,-3,SQFalse);
278 sq_pop(v,1);
279 }
280 else {
281 sq_pop(v,1); //result
282 }
283 sq_pop(v,1);
284}
285
286SQRESULT declare_stream(HSQUIRRELVM v,const SQChar* name,SQUserPointer typetag,const SQChar* reg_name,const SQRegFunction *methods,const SQRegFunction *globals)
287{
288 if(sq_gettype(v,-1) != OT_TABLE)
289 return sq_throwerror(v,_SC("table expected"));
290 SQInteger top = sq_gettop(v);
291 //create delegate
292 init_streamclass(v);
293 sq_pushregistrytable(v);
294 sq_pushstring(v,reg_name,-1);
295 sq_pushstring(v,_SC("std_stream"),-1);
296 if(SQ_SUCCEEDED(sq_get(v,-3))) {
297 sq_newclass(v,SQTrue);
298 sq_settypetag(v,-1,typetag);
299 SQInteger i = 0;
300 while(methods[i].name != 0) {
301 const SQRegFunction &f = methods[i];
302 sq_pushstring(v,f.name,-1);
303 sq_newclosure(v,f.f,0);
304 sq_setparamscheck(v,f.nparamscheck,f.typemask);
305 sq_setnativeclosurename(v,-1,f.name);
306 sq_newslot(v,-3,SQFalse);
307 i++;
308 }
309 sq_newslot(v,-3,SQFalse);
310 sq_pop(v,1);
311
312 i = 0;
313 while(globals[i].name!=0)
314 {
315 const SQRegFunction &f = globals[i];
316 sq_pushstring(v,f.name,-1);
317 sq_newclosure(v,f.f,0);
318 sq_setparamscheck(v,f.nparamscheck,f.typemask);
319 sq_setnativeclosurename(v,-1,f.name);
320 sq_newslot(v,-3,SQFalse);
321 i++;
322 }
323 //register the class in the target table
324 sq_pushstring(v,name,-1);
325 sq_pushregistrytable(v);
326 sq_pushstring(v,reg_name,-1);
327 sq_get(v,-2);
328 sq_remove(v,-2);
329 sq_newslot(v,-3,SQFalse);
330
331 sq_settop(v,top);
332 return SQ_OK;
333 }
334 sq_settop(v,top);
335 return SQ_ERROR;
336}
337