fixed warnings in squirrel
[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,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 int _stream_readstr(HSQUIRRELVM v)
20 {
21     SETUP_STREAM(v);
22         SQInteger type = _SC('a'), size = 0;
23         sq_getinteger(v, 2, &size);
24         if(size <= 0) return sq_throwerror(v,_SC("invalid size"));
25         if(sq_gettop(v) > 2)
26                 sq_getinteger(v, 3, &type);
27         SQChar *dest = NULL;
28         switch(type) {
29         case _SC('a'): {
30                 char *temp;
31                 if(self->Read(sq_getscratchpad(v, size+1), size) != size)
32                         return sq_throwerror(v, _SC("io failure"));
33 #ifdef _UNICODE
34                 temp = (char*) sq_getscratchpad(v, size + (size * sizeof(SQChar)));
35                 dest = (SQChar*) &temp[size];
36                 size = (SQInteger)mbstowcs(dest, (const char*)temp, size);
37 #else
38                 temp = (char *) sq_getscratchpad(v, -1);
39                 dest = temp;
40 #endif
41                                    }
42                 break;
43         case _SC('u'): {
44                 wchar_t *temp;
45                 if(self->Read(sq_getscratchpad(v, (size + 1) * sizeof(wchar_t)), size * sizeof(wchar_t)) != (int) (size * sizeof(wchar_t)))
46                         return sq_throwerror(v, _SC("io failure"));
47                 
48 #ifdef _UNICODE
49                 temp = (wchar_t*) sq_getscratchpad(v, -1);
50                 dest = (SQChar*) temp;
51 #else
52                 temp = (wchar_t*) sq_getscratchpad(v,(size * 3) + (size * sizeof(wchar_t)));
53                 dest = (char*) &temp[size];
54                 size = (SQInteger)wcstombs(dest, (const wchar_t*)temp, size);
55 #endif
56                                    }
57                 break;
58         default:
59                 return sq_throwerror(v, _SC("invalid coding"));
60         }
61
62         sq_pushstring(v, dest, size);
63         return 1;
64 }
65
66 int _stream_readblob(HSQUIRRELVM v)
67 {
68         SETUP_STREAM(v);
69         SQUserPointer data,blobp;
70         SQInteger size,res;
71         sq_getinteger(v,2,&size);
72         if(size > self->Len()) {
73                 size = self->Len();
74         }
75         data = sq_getscratchpad(v,size);
76         res = self->Read(data,size);
77         if(res <= 0)
78                 return sq_throwerror(v,_SC("no data left to read"));
79         blobp = sqstd_createblob(v,res);
80         memcpy(blobp,data,res);
81         return 1;
82 }
83
84 #define SAFE_READN(ptr,len) { \
85         if(self->Read(ptr,len) != len) return sq_throwerror(v,_SC("io error")); \
86         }
87 int _stream_readn(HSQUIRRELVM v)
88 {
89         SETUP_STREAM(v);
90         SQInteger format;
91         sq_getinteger(v, 2, &format);
92         switch(format) {
93         case 'i': {
94                 int i;
95                 SAFE_READN(&i, sizeof(i));
96                 sq_pushinteger(v, i);
97                           }
98                 break;
99         case 's': {
100                 short s;
101                 SAFE_READN(&s, sizeof(short));
102                 sq_pushinteger(v, s);
103                           }
104                 break;
105         case 'w': {
106                 unsigned short w;
107                 SAFE_READN(&w, sizeof(unsigned short));
108                 sq_pushinteger(v, w);
109                           }
110                 break;
111         case 'c': {
112                 char c;
113                 SAFE_READN(&c, sizeof(char));
114                 sq_pushinteger(v, c);
115                           }
116                 break;
117         case 'b': {
118                 unsigned char c;
119                 SAFE_READN(&c, sizeof(unsigned char));
120                 sq_pushinteger(v, c);
121                           }
122                 break;
123         case 'f': {
124                 float f;
125                 SAFE_READN(&f, sizeof(float));
126                 sq_pushfloat(v, f);
127                           }
128                 break;
129         case 'd': {
130                 double d;
131                 SAFE_READN(&d, sizeof(double));
132                 sq_pushfloat(v, (SQFloat)d);
133                           }
134                 break;
135         default:
136                 return sq_throwerror(v, _SC("invalid format"));
137         }
138         return 1;
139 }
140
141 int _stream_writestr(HSQUIRRELVM v)
142 {
143         SETUP_STREAM(v);
144         const SQChar *str,*res;
145         SQInteger trgformat = 'a',len = 0;
146         sq_getstring(v,2,&str);
147         len = sq_getsize(v,2);
148         if(sq_gettop(v)>2)
149                 sq_getinteger(v,3,&trgformat);
150         switch(trgformat)
151         {
152         case 'a':
153 #ifdef _UNICODE
154                 res = sq_getscratchpad(v,len*3);
155                 len = (SQInteger) wcstombs((char *)res, (const wchar_t*)str, len);
156 #else
157                 res = str;
158 #endif
159                 self->Write((void *)res,len);
160                 break;
161         case 'u':
162 #ifdef _UNICODE
163                 res = str;
164 #else
165                 res = sq_getscratchpad(v,len*sizeof(wchar_t));
166                 len = (SQInteger) mbstowcs((wchar_t*)res, str, len);
167 #endif
168                 self->Write((void *)res,len*sizeof(wchar_t));
169                 break;
170         default:
171                 return sq_throwerror(v,_SC("wrong encoding"));
172         }
173         
174         return 0;
175 }
176
177 int _stream_writeblob(HSQUIRRELVM v)
178 {
179         SQUserPointer data;
180         int size;
181         SETUP_STREAM(v);
182         if(SQ_FAILED(sqstd_getblob(v,2,&data)))
183                 return sq_throwerror(v,_SC("invalid parameter"));
184         size = sqstd_getblobsize(v,2);
185         if(self->Write(data,size) != size)
186                 return sq_throwerror(v,_SC("io error"));
187         sq_pushinteger(v,size);
188         return 1;
189 }
190
191 int _stream_writen(HSQUIRRELVM v)
192 {
193         SETUP_STREAM(v);
194         SQInteger format, ti;
195         SQFloat tf;
196         sq_getinteger(v, 3, &format);
197         switch(format) {
198         case 'i': {
199                 int i;
200                 sq_getinteger(v, 2, &ti);
201                 i = ti;
202                 self->Write(&i, sizeof(int));
203                           }
204                 break;
205         case 's': {
206                 short s;
207                 sq_getinteger(v, 2, &ti);
208                 s = ti;
209                 self->Write(&s, sizeof(short));
210                           }
211                 break;
212         case 'w': {
213                 unsigned short w;
214                 sq_getinteger(v, 2, &ti);
215                 w = ti;
216                 self->Write(&w, sizeof(unsigned short));
217                           }
218                 break;
219         case 'c': {
220                 char c;
221                 sq_getinteger(v, 2, &ti);
222                 c = ti;
223                 self->Write(&c, sizeof(char));
224                                   }
225                 break;
226         case 'b': {
227                 unsigned char b;
228                 sq_getinteger(v, 2, &ti);
229                 b = ti;
230                 self->Write(&b, sizeof(unsigned char));
231                           }
232                 break;
233         case 'f': {
234                 float f;
235                 sq_getfloat(v, 2, &tf);
236                 f = tf;
237                 self->Write(&f, sizeof(float));
238                           }
239                 break;
240         case 'd': {
241                 double d;
242                 sq_getfloat(v, 2, &tf);
243                 d = tf;
244                 self->Write(&d, sizeof(double));
245                           }
246                 break;
247         default:
248                 return sq_throwerror(v, _SC("invalid format"));
249         }
250         return 0;
251 }
252
253 int _stream_seek(HSQUIRRELVM v)
254 {
255         SETUP_STREAM(v);
256         SQInteger offset, origin = SQ_SEEK_SET;
257         sq_getinteger(v, 2, &offset);
258         if(sq_gettop(v) > 2) {
259                 SQInteger t;
260                 sq_getinteger(v, 3, &t);
261                 switch(t) {
262                         case 'b': origin = SQ_SEEK_SET; break;
263                         case 'c': origin = SQ_SEEK_CUR; break;
264                         case 'e': origin = SQ_SEEK_END; break;
265                         default: return sq_throwerror(v,_SC("invalid origin"));
266                 }
267         }
268         sq_pushinteger(v, self->Seek(offset, origin));
269         return 1;
270 }
271
272 int _stream_tell(HSQUIRRELVM v)
273 {
274         SETUP_STREAM(v);
275         sq_pushinteger(v, self->Tell());
276         return 1;
277 }
278
279 int _stream_len(HSQUIRRELVM v)
280 {
281         SETUP_STREAM(v);
282         sq_pushinteger(v, self->Len());
283         return 1;
284 }
285
286 int _stream_flush(HSQUIRRELVM v)
287 {
288         SETUP_STREAM(v);
289         if(!self->Flush())
290                 sq_pushinteger(v, 1);
291         else
292                 sq_pushnull(v);
293         return 1;
294 }
295
296 int _stream_eos(HSQUIRRELVM v)
297 {
298         SETUP_STREAM(v);
299         if(self->EOS())
300                 sq_pushinteger(v, 1);
301         else
302                 sq_pushnull(v);
303         return 1;
304 }
305
306 static SQRegFunction _stream_methods[] = {
307         _DECL_STREAM_FUNC(readstr,-2,_SC("xnn")),
308         _DECL_STREAM_FUNC(readblob,2,_SC("xn")),
309         _DECL_STREAM_FUNC(readn,2,_SC("xn")),
310         _DECL_STREAM_FUNC(writestr,-2,_SC("xsn")),
311         _DECL_STREAM_FUNC(writeblob,-2,_SC("xx")),
312         _DECL_STREAM_FUNC(writen,3,_SC("xnn")),
313         _DECL_STREAM_FUNC(seek,-2,_SC("xnn")),
314         _DECL_STREAM_FUNC(tell,1,_SC("x")),
315         _DECL_STREAM_FUNC(len,1,_SC("x")),
316         _DECL_STREAM_FUNC(eos,1,_SC("x")),
317         _DECL_STREAM_FUNC(flush,1,_SC("x")),
318         {0,0,0,0}
319 };
320
321 void init_streamclass(HSQUIRRELVM v)
322 {
323         sq_pushregistrytable(v);
324         sq_pushstring(v,_SC("std_stream"),-1);
325         if(SQ_FAILED(sq_get(v,-2))) {
326                 sq_pushstring(v,_SC("std_stream"),-1);
327                 sq_newclass(v,SQFalse);
328                 sq_settypetag(v,-1,SQSTD_STREAM_TYPE_TAG);
329                 int i = 0;
330                 while(_stream_methods[i].name != 0) {
331                         SQRegFunction &f = _stream_methods[i];
332                         sq_pushstring(v,f.name,-1);
333                         sq_newclosure(v,f.f,0);
334                         sq_setparamscheck(v,f.nparamscheck,f.typemask);
335                         sq_createslot(v,-3);
336                         i++;
337                 }
338                 sq_createslot(v,-3);
339         }
340         else {
341                 sq_pop(v,1); //result
342         }
343         sq_pop(v,1);
344 }
345
346 SQRESULT declare_stream(HSQUIRRELVM v,SQChar* name,int typetag,SQChar* reg_name,SQRegFunction *methods,SQRegFunction *globals)
347 {
348         if(sq_gettype(v,-1) != OT_TABLE)
349                 return sq_throwerror(v,_SC("table expected"));
350         int top = sq_gettop(v);
351         //create delegate
352     init_streamclass(v);
353         sq_pushregistrytable(v);
354         sq_pushstring(v,reg_name,-1);
355         sq_pushstring(v,_SC("std_stream"),-1);
356         if(SQ_SUCCEEDED(sq_get(v,-3))) {
357                 sq_newclass(v,SQTrue);
358                 sq_settypetag(v,-1,typetag);
359                 int i = 0;
360                 while(methods[i].name != 0) {
361                         SQRegFunction &f = methods[i];
362                         sq_pushstring(v,f.name,-1);
363                         sq_newclosure(v,f.f,0);
364                         sq_setparamscheck(v,f.nparamscheck,f.typemask);
365                         sq_setnativeclosurename(v,-1,f.name);
366                         sq_createslot(v,-3);
367                         i++;
368                 }
369                 sq_createslot(v,-3);
370                 sq_pop(v,1);
371                 
372                 i = 0;
373                 while(globals[i].name!=0)
374                 {
375                         SQRegFunction &f = globals[i];
376                         sq_pushstring(v,f.name,-1);
377                         sq_newclosure(v,f.f,0);
378                         sq_setparamscheck(v,f.nparamscheck,f.typemask);
379                         sq_setnativeclosurename(v,-1,f.name);
380                         sq_createslot(v,-3);
381                         i++;
382                 }
383                 //register the class in the target table
384                 sq_pushstring(v,name,-1);
385                 sq_pushregistrytable(v);
386                 sq_pushstring(v,reg_name,-1);
387                 sq_get(v,-2);
388                 sq_remove(v,-2);
389                 sq_createslot(v,-3);
390
391                 sq_settop(v,top);
392                 return SQ_OK;
393         }
394         sq_settop(v,top);
395         return SQ_ERROR;
396 }