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