1 /*
2 ** Buffer library.
3 ** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h
4 */
5 
6 #define lib_buffer_c
7 #define LUA_LIB
8 
9 #include "lua.h"
10 #include "lauxlib.h"
11 #include "lualib.h"
12 
13 #include "lj_obj.h"
14 
15 #if LJ_HASBUFFER
16 #include "lj_gc.h"
17 #include "lj_err.h"
18 #include "lj_buf.h"
19 #include "lj_str.h"
20 #include "lj_tab.h"
21 #include "lj_udata.h"
22 #include "lj_meta.h"
23 #if LJ_HASFFI
24 #include "lj_ctype.h"
25 #include "lj_cdata.h"
26 #include "lj_cconv.h"
27 #endif
28 #include "lj_strfmt.h"
29 #include "lj_serialize.h"
30 #include "lj_lib.h"
31 
32 /* -- Helper functions ---------------------------------------------------- */
33 
34 /* Check that the first argument is a string buffer. */
buffer_tobuf(lua_State * L)35 static SBufExt *buffer_tobuf(lua_State *L)
36 {
37   if (!(L->base < L->top && tvisbuf(L->base)))
38     lj_err_argtype(L, 1, "buffer");
39   return bufV(L->base);
40 }
41 
42 /* Ditto, but for writers. */
buffer_tobufw(lua_State * L)43 static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L)
44 {
45   SBufExt *sbx = buffer_tobuf(L);
46   setsbufXL_(sbx, L);
47   return sbx;
48 }
49 
50 #define buffer_toudata(sbx)	((GCudata *)(sbx)-1)
51 
52 /* -- Buffer methods ------------------------------------------------------ */
53 
54 #define LJLIB_MODULE_buffer_method
55 
LJLIB_CF(buffer_method_free)56 LJLIB_CF(buffer_method_free)
57 {
58   SBufExt *sbx = buffer_tobuf(L);
59   lj_bufx_free(L, sbx);
60   L->top = L->base+1;  /* Chain buffer object. */
61   return 1;
62 }
63 
64 LJLIB_CF(buffer_method_reset)		LJLIB_REC(.)
65 {
66   SBufExt *sbx = buffer_tobuf(L);
67   lj_bufx_reset(sbx);
68   L->top = L->base+1;  /* Chain buffer object. */
69   return 1;
70 }
71 
72 LJLIB_CF(buffer_method_skip)		LJLIB_REC(.)
73 {
74   SBufExt *sbx = buffer_tobuf(L);
75   MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
76   MSize len = sbufxlen(sbx);
77   if (n < len) {
78     sbx->r += n;
79   } else {
80     sbx->r = sbx->w = sbx->b;
81   }
82   L->top = L->base+1;  /* Chain buffer object. */
83   return 1;
84 }
85 
86 LJLIB_CF(buffer_method_set)		LJLIB_REC(.)
87 {
88   SBufExt *sbx = buffer_tobuf(L);
89   GCobj *ref;
90   const char *p;
91   MSize len;
92 #if LJ_HASFFI
93   if (tviscdata(L->base+1)) {
94     CTState *cts = ctype_cts(L);
95     lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
96 		   L->base+1, CCF_ARG(2));
97     len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
98   } else
99 #endif
100   {
101     GCstr *str = lj_lib_checkstrx(L, 2);
102     p = strdata(str);
103     len = str->len;
104   }
105   lj_bufx_free(L, sbx);
106   lj_bufx_set_cow(L, sbx, p, len);
107   ref = gcV(L->base+1);
108   setgcref(sbx->cowref, ref);
109   lj_gc_objbarrier(L, buffer_toudata(sbx), ref);
110   L->top = L->base+1;  /* Chain buffer object. */
111   return 1;
112 }
113 
114 LJLIB_CF(buffer_method_put)		LJLIB_REC(.)
115 {
116   SBufExt *sbx = buffer_tobufw(L);
117   ptrdiff_t arg, narg = L->top - L->base;
118   for (arg = 1; arg < narg; arg++) {
119     cTValue *o = &L->base[arg], *mo = NULL;
120   retry:
121     if (tvisstr(o)) {
122       lj_buf_putstr((SBuf *)sbx, strV(o));
123     } else if (tvisint(o)) {
124       lj_strfmt_putint((SBuf *)sbx, intV(o));
125     } else if (tvisnum(o)) {
126       lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o));
127     } else if (tvisbuf(o)) {
128       SBufExt *sbx2 = bufV(o);
129       if (sbx2 == sbx) lj_err_arg(L, arg+1, LJ_ERR_BUFFER_SELF);
130       lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2));
131     } else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
132       /* Call __tostring metamethod inline. */
133       copyTV(L, L->top++, mo);
134       copyTV(L, L->top++, o);
135       lua_call(L, 1, 1);
136       o = &L->base[arg];  /* The stack may have been reallocated. */
137       copyTV(L, &L->base[arg], L->top-1);
138       L->top = L->base + narg;
139       goto retry;  /* Retry with the result. */
140     } else {
141       lj_err_argtype(L, arg+1, "string/number/__tostring");
142     }
143     /* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
144   }
145   L->top = L->base+1;  /* Chain buffer object. */
146   lj_gc_check(L);
147   return 1;
148 }
149 
150 LJLIB_CF(buffer_method_putf)		LJLIB_REC(.)
151 {
152   SBufExt *sbx = buffer_tobufw(L);
153   lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
154   L->top = L->base+1;  /* Chain buffer object. */
155   lj_gc_check(L);
156   return 1;
157 }
158 
159 LJLIB_CF(buffer_method_get)		LJLIB_REC(.)
160 {
161   SBufExt *sbx = buffer_tobuf(L);
162   ptrdiff_t arg, narg = L->top - L->base;
163   if (narg == 1) {
164     narg++;
165     setnilV(L->top++);  /* get() is the same as get(nil). */
166   }
167   for (arg = 1; arg < narg; arg++) {
168     TValue *o = &L->base[arg];
169     MSize n = tvisnil(o) ? LJ_MAX_BUF :
170 	      (MSize) lj_lib_checkintrange(L, arg+1, 0, LJ_MAX_BUF);
171     MSize len = sbufxlen(sbx);
172     if (n > len) n = len;
173     setstrV(L, o, lj_str_new(L, sbx->r, n));
174     sbx->r += n;
175   }
176   if (sbx->r == sbx->w) sbx->r = sbx->w = sbx->b;
177   lj_gc_check(L);
178   return narg-1;
179 }
180 
181 #if LJ_HASFFI
182 LJLIB_CF(buffer_method_putcdata)	LJLIB_REC(.)
183 {
184   SBufExt *sbx = buffer_tobufw(L);
185   const char *p;
186   MSize len;
187   if (tviscdata(L->base+1)) {
188     CTState *cts = ctype_cts(L);
189     lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
190 		   L->base+1, CCF_ARG(2));
191   } else {
192     lj_err_argtype(L, 2, "cdata");
193   }
194   len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
195   lj_buf_putmem((SBuf *)sbx, p, len);
196   L->top = L->base+1;  /* Chain buffer object. */
197   return 1;
198 }
199 
200 LJLIB_CF(buffer_method_reserve)		LJLIB_REC(.)
201 {
202   SBufExt *sbx = buffer_tobufw(L);
203   MSize sz = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
204   GCcdata *cd;
205   lj_buf_more((SBuf *)sbx, sz);
206   ctype_loadffi(L);
207   cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
208   *(void **)cdataptr(cd) = sbx->w;
209   setcdataV(L, L->top++, cd);
210   setintV(L->top++, sbufleft(sbx));
211   return 2;
212 }
213 
214 LJLIB_CF(buffer_method_commit)		LJLIB_REC(.)
215 {
216   SBufExt *sbx = buffer_tobuf(L);
217   MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
218   if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG);
219   sbx->w += len;
220   L->top = L->base+1;  /* Chain buffer object. */
221   return 1;
222 }
223 
224 LJLIB_CF(buffer_method_ref)		LJLIB_REC(.)
225 {
226   SBufExt *sbx = buffer_tobuf(L);
227   GCcdata *cd;
228   ctype_loadffi(L);
229   cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
230   *(void **)cdataptr(cd) = sbx->r;
231   setcdataV(L, L->top++, cd);
232   setintV(L->top++, sbufxlen(sbx));
233   return 2;
234 }
235 #endif
236 
237 LJLIB_CF(buffer_method_encode)		LJLIB_REC(.)
238 {
239   SBufExt *sbx = buffer_tobufw(L);
240   cTValue *o = lj_lib_checkany(L, 2);
241   lj_serialize_put(sbx, o);
242   lj_gc_check(L);
243   L->top = L->base+1;  /* Chain buffer object. */
244   return 1;
245 }
246 
247 LJLIB_CF(buffer_method_decode)		LJLIB_REC(.)
248 {
249   SBufExt *sbx = buffer_tobufw(L);
250   setnilV(L->top++);
251   sbx->r = lj_serialize_get(sbx, L->top-1);
252   lj_gc_check(L);
253   return 1;
254 }
255 
LJLIB_CF(buffer_method___gc)256 LJLIB_CF(buffer_method___gc)
257 {
258   SBufExt *sbx = buffer_tobuf(L);
259   lj_bufx_free(L, sbx);
260   return 0;
261 }
262 
263 LJLIB_CF(buffer_method___tostring)	LJLIB_REC(.)
264 {
265   SBufExt *sbx = buffer_tobuf(L);
266   setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
267   lj_gc_check(L);
268   return 1;
269 }
270 
271 LJLIB_CF(buffer_method___len)		LJLIB_REC(.)
272 {
273   SBufExt *sbx = buffer_tobuf(L);
274   setintV(L->top-1, (int32_t)sbufxlen(sbx));
275   return 1;
276 }
277 
LJLIB_SET(__metatable)278 LJLIB_PUSH("buffer") LJLIB_SET(__metatable)
279 LJLIB_PUSH(top-1) LJLIB_SET(__index)
280 
281 /* -- Buffer library functions -------------------------------------------- */
282 
283 #define LJLIB_MODULE_buffer
284 
285 LJLIB_PUSH(top-2) LJLIB_SET(!)  /* Set environment. */
286 
287 LJLIB_CF(buffer_new)
288 {
289   MSize sz = 0;
290   int targ = 1;
291   GCtab *env, *dict_str = NULL, *dict_mt = NULL;
292   GCudata *ud;
293   SBufExt *sbx;
294   if (L->base < L->top && !tvistab(L->base)) {
295     targ = 2;
296     if (!tvisnil(L->base))
297       sz = (MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF);
298   }
299   if (L->base+targ-1 < L->top) {
300     GCtab *options = lj_lib_checktab(L, targ);
301     cTValue *opt_dict, *opt_mt;
302     opt_dict = lj_tab_getstr(options, lj_str_newlit(L, "dict"));
303     if (opt_dict && tvistab(opt_dict)) {
304       dict_str = tabV(opt_dict);
305       lj_serialize_dict_prep_str(L, dict_str);
306     }
307     opt_mt = lj_tab_getstr(options, lj_str_newlit(L, "metatable"));
308     if (opt_mt && tvistab(opt_mt)) {
309       dict_mt = tabV(opt_mt);
310       lj_serialize_dict_prep_mt(L, dict_mt);
311     }
312   }
313   env = tabref(curr_func(L)->c.env);
314   ud = lj_udata_new(L, sizeof(SBufExt), env);
315   ud->udtype = UDTYPE_BUFFER;
316   /* NOBARRIER: The GCudata is new (marked white). */
317   setgcref(ud->metatable, obj2gco(env));
318   setudataV(L, L->top++, ud);
319   sbx = (SBufExt *)uddata(ud);
320   lj_bufx_init(L, sbx);
321   setgcref(sbx->dict_str, obj2gco(dict_str));
322   setgcref(sbx->dict_mt, obj2gco(dict_mt));
323   if (sz > 0) lj_buf_need2((SBuf *)sbx, sz);
324   return 1;
325 }
326 
327 LJLIB_CF(buffer_encode)			LJLIB_REC(.)
328 {
329   cTValue *o = lj_lib_checkany(L, 1);
330   setstrV(L, L->top++, lj_serialize_encode(L, o));
331   lj_gc_check(L);
332   return 1;
333 }
334 
335 LJLIB_CF(buffer_decode)			LJLIB_REC(.)
336 {
337   GCstr *str = lj_lib_checkstrx(L, 1);
338   setnilV(L->top++);
339   lj_serialize_decode(L, L->top-1, str);
340   return 1;
341 }
342 
343 /* ------------------------------------------------------------------------ */
344 
345 #include "lj_libdef.h"
346 
luaopen_string_buffer(lua_State * L)347 int luaopen_string_buffer(lua_State *L)
348 {
349   LJ_LIB_REG(L, NULL, buffer_method);
350   lua_getfield(L, -1, "__tostring");
351   lua_setfield(L, -2, "tostring");
352   LJ_LIB_REG(L, NULL, buffer);
353   return 1;
354 }
355 
356 #endif
357