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