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