59cff0df170127f1ce5744642b57fee1f2fd484e
[supertux.git] / external / squirrel / sqstdlib / sqstdblob.cpp
1 /* see copyright notice in squirrel.h */\r
2 #include <new>\r
3 #include <squirrel.h>\r
4 #include <sqstdio.h>\r
5 #include <string.h>\r
6 #include <sqstdblob.h>\r
7 #include "sqstdstream.h"\r
8 #include "sqstdblobimpl.h"\r
9 \r
10 #define SQSTD_BLOB_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000002)\r
11 \r
12 //Blob\r
13 \r
14 \r
15 #define SETUP_BLOB(v) \\r
16         SQBlob *self = NULL; \\r
17         { if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer*)&self,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) \\r
18                 return sq_throwerror(v,_SC("invalid type tag"));  } \\r
19         if(!self || !self->IsValid())  \\r
20                 return sq_throwerror(v,_SC("the blob is invalid"));\r
21 \r
22 \r
23 static SQInteger _blob_resize(HSQUIRRELVM v)\r
24 {\r
25         SETUP_BLOB(v);\r
26         SQInteger size;\r
27         sq_getinteger(v,2,&size);\r
28         if(!self->Resize(size))\r
29                 return sq_throwerror(v,_SC("resize failed"));\r
30         return 0;\r
31 }\r
32 \r
33 static void __swap_dword(unsigned int *n)\r
34 {\r
35         *n=(unsigned int)(((*n&0xFF000000)>>24)  |\r
36                         ((*n&0x00FF0000)>>8)  |\r
37                         ((*n&0x0000FF00)<<8)  |\r
38                         ((*n&0x000000FF)<<24));\r
39 }\r
40 \r
41 static void __swap_word(unsigned short *n)\r
42 {\r
43         *n=(unsigned short)((*n>>8)&0x00FF)| ((*n<<8)&0xFF00);\r
44 }\r
45 \r
46 static SQInteger _blob_swap4(HSQUIRRELVM v)\r
47 {\r
48         SETUP_BLOB(v);\r
49         SQInteger num=(self->Len()-(self->Len()%4))>>2;\r
50         unsigned int *t=(unsigned int *)self->GetBuf();\r
51         for(SQInteger i = 0; i < num; i++) {\r
52                 __swap_dword(&t[i]);\r
53         }\r
54         return 0;\r
55 }\r
56 \r
57 static SQInteger _blob_swap2(HSQUIRRELVM v)\r
58 {\r
59         SETUP_BLOB(v);\r
60         SQInteger num=(self->Len()-(self->Len()%2))>>1;\r
61         unsigned short *t = (unsigned short *)self->GetBuf();\r
62         for(SQInteger i = 0; i < num; i++) {\r
63                 __swap_word(&t[i]);\r
64         }\r
65         return 0;\r
66 }\r
67 \r
68 static SQInteger _blob__set(HSQUIRRELVM v)\r
69 {\r
70         SETUP_BLOB(v);\r
71         SQInteger idx,val;\r
72         sq_getinteger(v,2,&idx);\r
73         sq_getinteger(v,3,&val);\r
74         if(idx < 0 || idx >= self->Len())\r
75                 return sq_throwerror(v,_SC("index out of range"));\r
76         ((unsigned char *)self->GetBuf())[idx] = (unsigned char) val;\r
77         sq_push(v,3);\r
78         return 1;\r
79 }\r
80 \r
81 static SQInteger _blob__get(HSQUIRRELVM v)\r
82 {\r
83         SETUP_BLOB(v);\r
84         SQInteger idx;\r
85         sq_getinteger(v,2,&idx);\r
86         if(idx < 0 || idx >= self->Len())\r
87                 return sq_throwerror(v,_SC("index out of range"));\r
88         sq_pushinteger(v,((unsigned char *)self->GetBuf())[idx]);\r
89         return 1;\r
90 }\r
91 \r
92 static SQInteger _blob__nexti(HSQUIRRELVM v)\r
93 {\r
94         SETUP_BLOB(v);\r
95         if(sq_gettype(v,2) == OT_NULL) {\r
96                 sq_pushinteger(v, 0);\r
97                 return 1;\r
98         }\r
99         SQInteger idx;\r
100         if(SQ_SUCCEEDED(sq_getinteger(v, 2, &idx))) {\r
101                 if(idx+1 < self->Len()) {\r
102                         sq_pushinteger(v, idx+1);\r
103                         return 1;\r
104                 }\r
105                 sq_pushnull(v);\r
106                 return 1;\r
107         }\r
108         return sq_throwerror(v,_SC("internal error (_nexti) wrong argument type"));\r
109 }\r
110 \r
111 static SQInteger _blob__typeof(HSQUIRRELVM v)\r
112 {\r
113         sq_pushstring(v,_SC("blob"),-1);\r
114         return 1;\r
115 }\r
116 \r
117 static SQInteger _blob_releasehook(SQUserPointer p, SQInteger size)\r
118 {\r
119         SQBlob *self = (SQBlob*)p;\r
120         self->~SQBlob();\r
121         sq_free(self,sizeof(SQBlob));\r
122         return 1;\r
123 }\r
124 \r
125 static SQInteger _blob_constructor(HSQUIRRELVM v)\r
126 {\r
127         SQInteger nparam = sq_gettop(v);\r
128         SQInteger size = 0;\r
129         if(nparam == 2) {\r
130                 sq_getinteger(v, 2, &size);\r
131         }\r
132         if(size < 0) return sq_throwerror(v, _SC("cannot create blob with negative size"));\r
133         //SQBlob *b = new SQBlob(size);\r
134 \r
135         SQBlob *b = new (sq_malloc(sizeof(SQBlob)))SQBlob(size);\r
136         if(SQ_FAILED(sq_setinstanceup(v,1,b))) {\r
137                 b->~SQBlob();\r
138                 sq_free(b,sizeof(SQBlob));\r
139                 return sq_throwerror(v, _SC("cannot create blob"));\r
140         }\r
141         sq_setreleasehook(v,1,_blob_releasehook);\r
142         return 0;\r
143 }\r
144 \r
145 static SQInteger _blob__cloned(HSQUIRRELVM v)\r
146 {\r
147         SQBlob *other = NULL;\r
148         { \r
149                 if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&other,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))\r
150                         return SQ_ERROR; \r
151         }\r
152         //SQBlob *thisone = new SQBlob(other->Len());\r
153         SQBlob *thisone = new (sq_malloc(sizeof(SQBlob)))SQBlob(other->Len());\r
154         memcpy(thisone->GetBuf(),other->GetBuf(),thisone->Len());\r
155         if(SQ_FAILED(sq_setinstanceup(v,1,thisone))) {\r
156                 thisone->~SQBlob();\r
157                 sq_free(thisone,sizeof(SQBlob));\r
158                 return sq_throwerror(v, _SC("cannot clone blob"));\r
159         }\r
160         sq_setreleasehook(v,1,_blob_releasehook);\r
161         return 0;\r
162 }\r
163 \r
164 #define _DECL_BLOB_FUNC(name,nparams,typecheck) {_SC(#name),_blob_##name,nparams,typecheck}\r
165 static SQRegFunction _blob_methods[] = {\r
166         _DECL_BLOB_FUNC(constructor,-1,_SC("xn")),\r
167         _DECL_BLOB_FUNC(resize,2,_SC("xn")),\r
168         _DECL_BLOB_FUNC(swap2,1,_SC("x")),\r
169         _DECL_BLOB_FUNC(swap4,1,_SC("x")),\r
170         _DECL_BLOB_FUNC(_set,3,_SC("xnn")),\r
171         _DECL_BLOB_FUNC(_get,2,_SC("xn")),\r
172         _DECL_BLOB_FUNC(_typeof,1,_SC("x")),\r
173         _DECL_BLOB_FUNC(_nexti,2,_SC("x")),\r
174         _DECL_BLOB_FUNC(_cloned,2,_SC("xx")),\r
175         {0,0,0,0}\r
176 };\r
177 \r
178 \r
179 \r
180 //GLOBAL FUNCTIONS\r
181 \r
182 static SQInteger _g_blob_casti2f(HSQUIRRELVM v)\r
183 {\r
184         SQInteger i;\r
185         sq_getinteger(v,2,&i);\r
186         sq_pushfloat(v,*((SQFloat *)&i));\r
187         return 1;\r
188 }\r
189 \r
190 static SQInteger _g_blob_castf2i(HSQUIRRELVM v)\r
191 {\r
192         SQFloat f;\r
193         sq_getfloat(v,2,&f);\r
194         sq_pushinteger(v,*((SQInteger *)&f));\r
195         return 1;\r
196 }\r
197 \r
198 static SQInteger _g_blob_swap2(HSQUIRRELVM v)\r
199 {\r
200         SQInteger i;\r
201         sq_getinteger(v,2,&i);\r
202         short s=(short)i;\r
203         sq_pushinteger(v,(s<<8)|((s>>8)&0x00FF));\r
204         return 1;\r
205 }\r
206 \r
207 static SQInteger _g_blob_swap4(HSQUIRRELVM v)\r
208 {\r
209         SQInteger i;\r
210         sq_getinteger(v,2,&i);\r
211         unsigned int t4 = (unsigned int)i;\r
212         __swap_dword(&t4);\r
213         sq_pushinteger(v,(SQInteger)t4);\r
214         return 1;\r
215 }\r
216 \r
217 static SQInteger _g_blob_swapfloat(HSQUIRRELVM v)\r
218 {\r
219         SQFloat f;\r
220         sq_getfloat(v,2,&f);\r
221         __swap_dword((unsigned int *)&f);\r
222         sq_pushfloat(v,f);\r
223         return 1;\r
224 }\r
225 \r
226 #define _DECL_GLOBALBLOB_FUNC(name,nparams,typecheck) {_SC(#name),_g_blob_##name,nparams,typecheck}\r
227 static SQRegFunction bloblib_funcs[]={\r
228         _DECL_GLOBALBLOB_FUNC(casti2f,2,_SC(".n")),\r
229         _DECL_GLOBALBLOB_FUNC(castf2i,2,_SC(".n")),\r
230         _DECL_GLOBALBLOB_FUNC(swap2,2,_SC(".n")),\r
231         _DECL_GLOBALBLOB_FUNC(swap4,2,_SC(".n")),\r
232         _DECL_GLOBALBLOB_FUNC(swapfloat,2,_SC(".n")),\r
233         {0,0}\r
234 };\r
235 \r
236 SQRESULT sqstd_getblob(HSQUIRRELVM v,SQInteger idx,SQUserPointer *ptr)\r
237 {\r
238         SQBlob *blob;\r
239         if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))\r
240                 return -1;\r
241         *ptr = blob->GetBuf();\r
242         return SQ_OK;\r
243 }\r
244 \r
245 SQInteger sqstd_getblobsize(HSQUIRRELVM v,SQInteger idx)\r
246 {\r
247         SQBlob *blob;\r
248         if(SQ_FAILED(sq_getinstanceup(v,idx,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG)))\r
249                 return -1;\r
250         return blob->Len();\r
251 }\r
252 \r
253 SQUserPointer sqstd_createblob(HSQUIRRELVM v, SQInteger size)\r
254 {\r
255         SQInteger top = sq_gettop(v);\r
256         sq_pushregistrytable(v);\r
257         sq_pushstring(v,_SC("std_blob"),-1);\r
258         if(SQ_SUCCEEDED(sq_get(v,-2))) {\r
259                 sq_remove(v,-2); //removes the registry\r
260                 sq_push(v,1); // push the this\r
261                 sq_pushinteger(v,size); //size\r
262                 SQBlob *blob = NULL;\r
263                 if(SQ_SUCCEEDED(sq_call(v,2,SQTrue,SQFalse))\r
264                         && SQ_SUCCEEDED(sq_getinstanceup(v,-1,(SQUserPointer *)&blob,(SQUserPointer)SQSTD_BLOB_TYPE_TAG))) {\r
265                         sq_remove(v,-2);\r
266                         return blob->GetBuf();\r
267                 }\r
268         }\r
269         sq_settop(v,top);\r
270         return NULL;\r
271 }\r
272 \r
273 SQRESULT sqstd_register_bloblib(HSQUIRRELVM v)\r
274 {\r
275         return declare_stream(v,_SC("blob"),(SQUserPointer)SQSTD_BLOB_TYPE_TAG,_SC("std_blob"),_blob_methods,bloblib_funcs);\r
276 }\r
277 \r