Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

410 lines
9.9 KiB

  1. /* see copyright notice in squirrel.h */
  2. #include <new>
  3. #include <stdio.h>
  4. #include <squirrel.h>
  5. #include <sqstdio.h>
  6. #include "sqstdstream.h"
  7. #define SQSTD_FILE_TYPE_TAG (SQSTD_STREAM_TYPE_TAG | 0x00000001)
  8. //basic API
  9. SQFILE sqstd_fopen(const SQChar *filename ,const SQChar *mode)
  10. {
  11. #ifndef SQUNICODE
  12. return (SQFILE)fopen(filename,mode);
  13. #else
  14. return (SQFILE)_wfopen(filename,mode);
  15. #endif
  16. }
  17. SQInteger sqstd_fread(void* buffer, SQInteger size, SQInteger count, SQFILE file)
  18. {
  19. return (SQInteger)fread(buffer,size,count,(FILE *)file);
  20. }
  21. SQInteger sqstd_fwrite(const SQUserPointer buffer, SQInteger size, SQInteger count, SQFILE file)
  22. {
  23. return (SQInteger)fwrite(buffer,size,count,(FILE *)file);
  24. }
  25. SQInteger sqstd_fseek(SQFILE file, SQInteger offset, SQInteger origin)
  26. {
  27. SQInteger realorigin;
  28. switch(origin) {
  29. case SQ_SEEK_CUR: realorigin = SEEK_CUR; break;
  30. case SQ_SEEK_END: realorigin = SEEK_END; break;
  31. case SQ_SEEK_SET: realorigin = SEEK_SET; break;
  32. default: return -1; //failed
  33. }
  34. return fseek((FILE *)file,(long)offset,(int)realorigin);
  35. }
  36. SQInteger sqstd_ftell(SQFILE file)
  37. {
  38. return ftell((FILE *)file);
  39. }
  40. SQInteger sqstd_fflush(SQFILE file)
  41. {
  42. return fflush((FILE *)file);
  43. }
  44. SQInteger sqstd_fclose(SQFILE file)
  45. {
  46. return fclose((FILE *)file);
  47. }
  48. SQInteger sqstd_feof(SQFILE file)
  49. {
  50. return feof((FILE *)file);
  51. }
  52. //File
  53. struct SQFile : public SQStream {
  54. SQFile() { _handle = NULL; _owns = false;}
  55. SQFile(SQFILE file, bool owns) { _handle = file; _owns = owns;}
  56. virtual ~SQFile() { Close(); }
  57. bool Open(const SQChar *filename ,const SQChar *mode) {
  58. Close();
  59. if( (_handle = sqstd_fopen(filename,mode)) ) {
  60. _owns = true;
  61. return true;
  62. }
  63. return false;
  64. }
  65. void Close() {
  66. if(_handle && _owns) {
  67. sqstd_fclose(_handle);
  68. _handle = NULL;
  69. _owns = false;
  70. }
  71. }
  72. SQInteger Read(void *buffer,SQInteger size) {
  73. return sqstd_fread(buffer,1,size,_handle);
  74. }
  75. SQInteger Write(void *buffer,SQInteger size) {
  76. return sqstd_fwrite(buffer,1,size,_handle);
  77. }
  78. SQInteger Flush() {
  79. return sqstd_fflush(_handle);
  80. }
  81. SQInteger Tell() {
  82. return sqstd_ftell(_handle);
  83. }
  84. SQInteger Len() {
  85. SQInteger prevpos=Tell();
  86. Seek(0,SQ_SEEK_END);
  87. SQInteger size=Tell();
  88. Seek(prevpos,SQ_SEEK_SET);
  89. return size;
  90. }
  91. SQInteger Seek(SQInteger offset, SQInteger origin) {
  92. return sqstd_fseek(_handle,offset,origin);
  93. }
  94. bool IsValid() { return _handle?true:false; }
  95. bool EOS() { return Tell()==Len()?true:false;}
  96. SQFILE GetHandle() {return _handle;}
  97. private:
  98. SQFILE _handle;
  99. bool _owns;
  100. };
  101. static SQInteger _file__typeof(HSQUIRRELVM v)
  102. {
  103. sq_pushstring(v,_SC("file"),-1);
  104. return 1;
  105. }
  106. static SQInteger _file_releasehook(SQUserPointer p, SQInteger size)
  107. {
  108. SQFile *self = (SQFile*)p;
  109. delete self;
  110. return 1;
  111. }
  112. static SQInteger _file_constructor(HSQUIRRELVM v)
  113. {
  114. const SQChar *filename,*mode;
  115. bool owns = true;
  116. SQFile *f;
  117. SQFILE newf;
  118. if(sq_gettype(v,2) == OT_STRING && sq_gettype(v,3) == OT_STRING) {
  119. sq_getstring(v, 2, &filename);
  120. sq_getstring(v, 3, &mode);
  121. newf = sqstd_fopen(filename, mode);
  122. if(!newf) return sq_throwerror(v, _SC("cannot open file"));
  123. } else if(sq_gettype(v,2) == OT_USERPOINTER) {
  124. owns = !(sq_gettype(v,3) == OT_NULL);
  125. sq_getuserpointer(v,2,&newf);
  126. } else {
  127. return sq_throwerror(v,_SC("wrong parameter"));
  128. }
  129. f = new SQFile(newf,owns);
  130. if(SQ_FAILED(sq_setinstanceup(v,1,f))) {
  131. delete f;
  132. return sq_throwerror(v, _SC("cannot create blob with negative size"));
  133. }
  134. sq_setreleasehook(v,1,_file_releasehook);
  135. return 0;
  136. }
  137. //bindings
  138. #define _DECL_FILE_FUNC(name,nparams,typecheck) {_SC(#name),_file_##name,nparams,typecheck}
  139. static SQRegFunction _file_methods[] = {
  140. _DECL_FILE_FUNC(constructor,3,_SC("x")),
  141. _DECL_FILE_FUNC(_typeof,1,_SC("x")),
  142. {0,0,0,0},
  143. };
  144. SQRESULT sqstd_createfile(HSQUIRRELVM v, SQFILE file,SQBool own)
  145. {
  146. SQInteger top = sq_gettop(v);
  147. sq_pushregistrytable(v);
  148. sq_pushstring(v,_SC("std_file"),-1);
  149. if(SQ_SUCCEEDED(sq_get(v,-2))) {
  150. sq_remove(v,-2); //removes the registry
  151. sq_pushroottable(v); // push the this
  152. sq_pushuserpointer(v,file); //file
  153. if(own){
  154. sq_pushinteger(v,1); //true
  155. }
  156. else{
  157. sq_pushnull(v); //false
  158. }
  159. if(SQ_SUCCEEDED( sq_call(v,3,SQTrue,SQFalse) )) {
  160. sq_remove(v,-2);
  161. return SQ_OK;
  162. }
  163. }
  164. sq_settop(v,top);
  165. return SQ_OK;
  166. }
  167. SQRESULT sqstd_getfile(HSQUIRRELVM v, SQInteger idx, SQFILE *file)
  168. {
  169. SQFile *fileobj = NULL;
  170. if(SQ_SUCCEEDED(sq_getinstanceup(v,idx,(SQUserPointer*)&fileobj,(SQUserPointer)SQSTD_FILE_TYPE_TAG))) {
  171. *file = fileobj->GetHandle();
  172. return SQ_OK;
  173. }
  174. return sq_throwerror(v,_SC("not a file"));
  175. }
  176. static SQInteger _io_file_lexfeed_ASCII(SQUserPointer file)
  177. {
  178. SQInteger ret;
  179. char c;
  180. if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
  181. return c;
  182. return 0;
  183. }
  184. static SQInteger _io_file_lexfeed_UTF8(SQUserPointer file)
  185. {
  186. #define READ() \
  187. if(sqstd_fread(&inchar,sizeof(inchar),1,(FILE *)file) != 1) \
  188. return 0;
  189. static const SQInteger utf8_lengths[16] =
  190. {
  191. 1,1,1,1,1,1,1,1, /* 0000 to 0111 : 1 byte (plain ASCII) */
  192. 0,0,0,0, /* 1000 to 1011 : not valid */
  193. 2,2, /* 1100, 1101 : 2 bytes */
  194. 3, /* 1110 : 3 bytes */
  195. 4 /* 1111 :4 bytes */
  196. };
  197. static unsigned char byte_masks[5] = {0,0,0x1f,0x0f,0x07};
  198. unsigned char inchar;
  199. SQInteger c = 0;
  200. READ();
  201. c = inchar;
  202. //
  203. if(c >= 0x80) {
  204. SQInteger tmp;
  205. SQInteger codelen = utf8_lengths[c>>4];
  206. if(codelen == 0)
  207. return 0;
  208. //"invalid UTF-8 stream";
  209. tmp = c&byte_masks[codelen];
  210. for(SQInteger n = 0; n < codelen-1; n++) {
  211. tmp<<=6;
  212. READ();
  213. tmp |= inchar & 0x3F;
  214. }
  215. c = tmp;
  216. }
  217. return c;
  218. }
  219. static SQInteger _io_file_lexfeed_UCS2_LE(SQUserPointer file)
  220. {
  221. SQInteger ret;
  222. wchar_t c;
  223. if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) )
  224. return (SQChar)c;
  225. return 0;
  226. }
  227. static SQInteger _io_file_lexfeed_UCS2_BE(SQUserPointer file)
  228. {
  229. SQInteger ret;
  230. unsigned short c;
  231. if( ( ret=sqstd_fread(&c,sizeof(c),1,(FILE *)file )>0) ) {
  232. c = ((c>>8)&0x00FF)| ((c<<8)&0xFF00);
  233. return (SQChar)c;
  234. }
  235. return 0;
  236. }
  237. SQInteger file_read(SQUserPointer file,SQUserPointer buf,SQInteger size)
  238. {
  239. SQInteger ret;
  240. if( ( ret = sqstd_fread(buf,1,size,(SQFILE)file ))!=0 )return ret;
  241. return -1;
  242. }
  243. SQInteger file_write(SQUserPointer file,SQUserPointer p,SQInteger size)
  244. {
  245. return sqstd_fwrite(p,1,size,(SQFILE)file);
  246. }
  247. SQRESULT sqstd_loadfile(HSQUIRRELVM v,const SQChar *filename,SQBool printerror)
  248. {
  249. SQFILE file = sqstd_fopen(filename,_SC("rb"));
  250. SQInteger ret;
  251. unsigned short us;
  252. unsigned char uc;
  253. SQLEXREADFUNC func = _io_file_lexfeed_ASCII;
  254. if(file){
  255. ret = sqstd_fread(&us,1,2,file);
  256. if(ret != 2) {
  257. //probably an empty file
  258. us = 0;
  259. }
  260. if(us == SQ_BYTECODE_STREAM_TAG) { //BYTECODE
  261. sqstd_fseek(file,0,SQ_SEEK_SET);
  262. if(SQ_SUCCEEDED(sq_readclosure(v,file_read,file))) {
  263. sqstd_fclose(file);
  264. return SQ_OK;
  265. }
  266. }
  267. else { //SCRIPT
  268. switch(us)
  269. {
  270. //gotta swap the next 2 lines on BIG endian machines
  271. case 0xFFFE: func = _io_file_lexfeed_UCS2_BE; break;//UTF-16 little endian;
  272. case 0xFEFF: func = _io_file_lexfeed_UCS2_LE; break;//UTF-16 big endian;
  273. case 0xBBEF:
  274. if(sqstd_fread(&uc,1,sizeof(uc),file) == 0) {
  275. sqstd_fclose(file);
  276. return sq_throwerror(v,_SC("io error"));
  277. }
  278. if(uc != 0xBF) {
  279. sqstd_fclose(file);
  280. return sq_throwerror(v,_SC("Unrecognozed ecoding"));
  281. }
  282. func = _io_file_lexfeed_UTF8;
  283. break;//UTF-8 ;
  284. default: sqstd_fseek(file,0,SQ_SEEK_SET); break; // ascii
  285. }
  286. if(SQ_SUCCEEDED(sq_compile(v,func,file,filename,printerror))){
  287. sqstd_fclose(file);
  288. return SQ_OK;
  289. }
  290. }
  291. sqstd_fclose(file);
  292. return SQ_ERROR;
  293. }
  294. return sq_throwerror(v,_SC("cannot open the file"));
  295. }
  296. SQRESULT sqstd_dofile(HSQUIRRELVM v,const SQChar *filename,SQBool retval,SQBool printerror)
  297. {
  298. if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror))) {
  299. sq_push(v,-2);
  300. if(SQ_SUCCEEDED(sq_call(v,1,retval,SQTrue))) {
  301. sq_remove(v,retval?-2:-1); //removes the closure
  302. return 1;
  303. }
  304. sq_pop(v,1); //removes the closure
  305. }
  306. return SQ_ERROR;
  307. }
  308. SQRESULT sqstd_writeclosuretofile(HSQUIRRELVM v,const SQChar *filename)
  309. {
  310. SQFILE file = sqstd_fopen(filename,_SC("wb+"));
  311. if(!file) return sq_throwerror(v,_SC("cannot open the file"));
  312. if(SQ_SUCCEEDED(sq_writeclosure(v,file_write,file))) {
  313. sqstd_fclose(file);
  314. return SQ_OK;
  315. }
  316. sqstd_fclose(file);
  317. return SQ_ERROR; //forward the error
  318. }
  319. SQInteger _g_io_loadfile(HSQUIRRELVM v)
  320. {
  321. const SQChar *filename;
  322. SQBool printerror = SQFalse;
  323. sq_getstring(v,2,&filename);
  324. if(sq_gettop(v) >= 3) {
  325. sq_getbool(v,3,&printerror);
  326. }
  327. if(SQ_SUCCEEDED(sqstd_loadfile(v,filename,printerror)))
  328. return 1;
  329. return SQ_ERROR; //propagates the error
  330. }
  331. SQInteger _g_io_writeclosuretofile(HSQUIRRELVM v)
  332. {
  333. const SQChar *filename;
  334. sq_getstring(v,2,&filename);
  335. if(SQ_SUCCEEDED(sqstd_writeclosuretofile(v,filename)))
  336. return 1;
  337. return SQ_ERROR; //propagates the error
  338. }
  339. SQInteger _g_io_dofile(HSQUIRRELVM v)
  340. {
  341. const SQChar *filename;
  342. SQBool printerror = SQFalse;
  343. sq_getstring(v,2,&filename);
  344. if(sq_gettop(v) >= 3) {
  345. sq_getbool(v,3,&printerror);
  346. }
  347. sq_push(v,1); //repush the this
  348. if(SQ_SUCCEEDED(sqstd_dofile(v,filename,SQTrue,printerror)))
  349. return 1;
  350. return SQ_ERROR; //propagates the error
  351. }
  352. #define _DECL_GLOBALIO_FUNC(name,nparams,typecheck) {_SC(#name),_g_io_##name,nparams,typecheck}
  353. static SQRegFunction iolib_funcs[]={
  354. _DECL_GLOBALIO_FUNC(loadfile,-2,_SC(".sb")),
  355. _DECL_GLOBALIO_FUNC(dofile,-2,_SC(".sb")),
  356. _DECL_GLOBALIO_FUNC(writeclosuretofile,3,_SC(".sc")),
  357. {0,0}
  358. };
  359. SQRESULT sqstd_register_iolib(HSQUIRRELVM v)
  360. {
  361. SQInteger top = sq_gettop(v);
  362. //create delegate
  363. declare_stream(v,_SC("file"),(SQUserPointer)SQSTD_FILE_TYPE_TAG,_SC("std_file"),_file_methods,iolib_funcs);
  364. sq_pushstring(v,_SC("stdout"),-1);
  365. sqstd_createfile(v,stdout,SQFalse);
  366. sq_createslot(v,-3);
  367. sq_pushstring(v,_SC("stdin"),-1);
  368. sqstd_createfile(v,stdin,SQFalse);
  369. sq_createslot(v,-3);
  370. sq_pushstring(v,_SC("stderr"),-1);
  371. sqstd_createfile(v,stderr,SQFalse);
  372. sq_createslot(v,-3);
  373. sq_settop(v,top);
  374. return SQ_OK;
  375. }