f373f5bed9d82a5594fa6ce3b0ec4defbaab00bc
[supertux.git] / src / squirrel / sqstdlib / sqstdstream.cpp
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)SQSTD_STREAM_TYPE_TAG))) \
15                 return sq_throwerror(v,_SC("invalid type tag")); \
16         if(!self->IsValid())  \
17                 return sq_throwerror(v,_SC("the stream is invalid"));
18
19 SQInteger _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         }
40 SQInteger _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
100 SQInteger _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
114 SQInteger _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
183 SQInteger _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
202 SQInteger _stream_tell(HSQUIRRELVM v)
203 {
204         SETUP_STREAM(v);
205         sq_pushinteger(v, self->Tell());
206         return 1;
207 }
208
209 SQInteger _stream_len(HSQUIRRELVM v)
210 {
211         SETUP_STREAM(v);
212         sq_pushinteger(v, self->Len());
213         return 1;
214 }
215
216 SQInteger _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
226 SQInteger _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 static SQRegFunction _stream_methods[] = {
237         _DECL_STREAM_FUNC(readblob,2,_SC("xn")),
238         _DECL_STREAM_FUNC(readn,2,_SC("xn")),
239         _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")),
240         _DECL_STREAM_FUNC(writen,3,_SC("xnn")),
241         _DECL_STREAM_FUNC(seek,-2,_SC("xnn")),
242         _DECL_STREAM_FUNC(tell,1,_SC("x")),
243         _DECL_STREAM_FUNC(len,1,_SC("x")),
244         _DECL_STREAM_FUNC(eos,1,_SC("x")),
245         _DECL_STREAM_FUNC(flush,1,_SC("x")),
246         {0,0}
247 };
248
249 void init_streamclass(HSQUIRRELVM v)
250 {
251         sq_pushregistrytable(v);
252         sq_pushstring(v,_SC("std_stream"),-1);
253         if(SQ_FAILED(sq_get(v,-2))) {
254                 sq_pushstring(v,_SC("std_stream"),-1);
255                 sq_newclass(v,SQFalse);
256                 sq_settypetag(v,-1,(SQUserPointer)SQSTD_STREAM_TYPE_TAG);
257                 SQInteger i = 0;
258                 while(_stream_methods[i].name != 0) {
259                         SQRegFunction &f = _stream_methods[i];
260                         sq_pushstring(v,f.name,-1);
261                         sq_newclosure(v,f.f,0);
262                         sq_setparamscheck(v,f.nparamscheck,f.typemask);
263                         sq_createslot(v,-3);
264                         i++;
265                 }
266                 sq_createslot(v,-3);
267                 sq_pushroottable(v);
268                 sq_pushstring(v,_SC("stream"),-1);
269                 sq_pushstring(v,_SC("std_stream"),-1);
270                 sq_get(v,-4);
271                 sq_createslot(v,-3);
272                 sq_pop(v,1);
273         }
274         else {
275                 sq_pop(v,1); //result
276         }
277         sq_pop(v,1);
278 }
279
280 SQRESULT declare_stream(HSQUIRRELVM v,const SQChar* name,SQUserPointer typetag,const SQChar* reg_name,SQRegFunction *methods,SQRegFunction *globals)
281 {
282         if(sq_gettype(v,-1) != OT_TABLE)
283                 return sq_throwerror(v,_SC("table expected"));
284         SQInteger top = sq_gettop(v);
285         //create delegate
286     init_streamclass(v);
287         sq_pushregistrytable(v);
288         sq_pushstring(v,reg_name,-1);
289         sq_pushstring(v,_SC("std_stream"),-1);
290         if(SQ_SUCCEEDED(sq_get(v,-3))) {
291                 sq_newclass(v,SQTrue);
292                 sq_settypetag(v,-1,typetag);
293                 SQInteger i = 0;
294                 while(methods[i].name != 0) {
295                         SQRegFunction &f = methods[i];
296                         sq_pushstring(v,f.name,-1);
297                         sq_newclosure(v,f.f,0);
298                         sq_setparamscheck(v,f.nparamscheck,f.typemask);
299                         sq_setnativeclosurename(v,-1,f.name);
300                         sq_createslot(v,-3);
301                         i++;
302                 }
303                 sq_createslot(v,-3);
304                 sq_pop(v,1);
305                 
306                 i = 0;
307                 while(globals[i].name!=0)
308                 {
309                         SQRegFunction &f = globals[i];
310                         sq_pushstring(v,f.name,-1);
311                         sq_newclosure(v,f.f,0);
312                         sq_setparamscheck(v,f.nparamscheck,f.typemask);
313                         sq_setnativeclosurename(v,-1,f.name);
314                         sq_createslot(v,-3);
315                         i++;
316                 }
317                 //register the class in the target table
318                 sq_pushstring(v,name,-1);
319                 sq_pushregistrytable(v);
320                 sq_pushstring(v,reg_name,-1);
321                 sq_get(v,-2);
322                 sq_remove(v,-2);
323                 sq_createslot(v,-3);
324
325                 sq_settop(v,top);
326                 return SQ_OK;
327         }
328         sq_settop(v,top);
329         return SQ_ERROR;
330 }