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