1 /* lpdflib.c
2 
3    Copyright 2006-2011 Taco Hoekwater <taco@luatex.org>
4 
5    This file is part of LuaTeX.
6 
7    LuaTeX is free software; you can redistribute it and/or modify it under
8    the terms of the GNU General Public License as published by the Free
9    Software Foundation; either version 2 of the License, or (at your
10    option) any later version.
11 
12    LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15    License for more details.
16 
17    You should have received a copy of the GNU General Public License along
18    with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
19 
20 
21 #include "ptexlib.h"
22 #include "lua/luatex-api.h"
23 
luapdfprint(lua_State * L)24 static int luapdfprint(lua_State * L)
25 {
26     int n;
27     const_lstring st;
28     const char *modestr_s;
29     ctm_transform_modes literal_mode;
30     st.s = modestr_s = NULL;
31     n = lua_gettop(L);
32     if (!lua_isstring(L, -1)) {
33         luaL_error(L, "no string to print");
34     }
35     literal_mode = set_origin;
36     if (n == 2) {
37         if (!lua_isstring(L, -2)) {
38             luaL_error(L, "invalid argument for print literal mode");
39         } else {
40 	    modestr_s = lua_tostring(L, -2);
41 	    if (lua_key_eq(modestr_s,direct))
42 	      literal_mode = direct_always;
43 	    else if (lua_key_eq(modestr_s,page))
44                 literal_mode = direct_page;
45             else {
46                 luaL_error(L, "invalid argument for print literal mode");
47             }
48         }
49     } else {
50         if (n != 1) {
51             luaL_error(L, "invalid number of arguments");
52         }
53     }
54     check_o_mode(static_pdf, "pdf.print()", 1 << OMODE_PDF, true);
55     switch (literal_mode) {
56     case (set_origin):
57         pdf_goto_pagemode(static_pdf);
58         pdf_set_pos(static_pdf, static_pdf->posstruct->pos);
59         (void) calc_pdfpos(static_pdf->pstruct, static_pdf->posstruct->pos);
60         break;
61     case (direct_page):
62         pdf_goto_pagemode(static_pdf);
63         (void) calc_pdfpos(static_pdf->pstruct, static_pdf->posstruct->pos);
64         break;
65     case (direct_always):
66         pdf_end_string_nl(static_pdf);
67         break;
68     default:
69         assert(0);
70     }
71     st.s = lua_tolstring(L, n, &st.l);
72     pdf_out_block(static_pdf, st.s, st.l);
73     return 0;
74 }
75 
fread_to_buf(lua_State * L,const char * filename,size_t * len)76 static unsigned char *fread_to_buf(lua_State * L, const char *filename,
77                                    size_t * len)
78 {
79     int ilen = 0;
80     FILE *f;
81     unsigned char *buf = NULL;
82     if ((f = fopen(filename, "rb")) == NULL)
83         luaL_error(L, "pdf.immediateobj() cannot open input file");
84     if (readbinfile(f, &buf, &ilen) == 0)
85         luaL_error(L, "pdf.immediateobj() cannot read input file");
86     fclose(f);
87     *len = (size_t) ilen;
88     return buf;
89 }
90 
l_immediateobj(lua_State * L)91 static int l_immediateobj(lua_State * L)
92 {
93     int n, first_arg = 1;
94     int k;
95     lstring buf;
96     const_lstring st1,st2, st3;
97     const char *st1_s = NULL;
98     st1.s = st2.s = st3.s = NULL;
99     check_o_mode(static_pdf, "immediateobj()", 1 << OMODE_PDF, true);
100     if (global_shipping_mode != NOT_SHIPPING)
101         luaL_error(L, "pdf.immediateobj() can not be used with \\latelua");
102     n = lua_gettop(L);
103     if (n > 0 && lua_type(L, 1) == LUA_TNUMBER) {
104         first_arg++;
105         k=(int)lua_tonumber(L, 1);
106         check_obj_type(static_pdf, obj_type_obj, k);
107         if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0)
108             luaL_error(L, "pdf.immediateobj() object in use");
109     } else {
110         static_pdf->obj_count++;
111         k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1);
112     }
113     pdf_last_obj = k;
114     switch (n - first_arg + 1) {
115     case 0:
116         luaL_error(L, "pdf.immediateobj() needs at least one argument");
117         break;
118     case 1:
119         if (!lua_isstring(L, first_arg))
120             luaL_error(L, "pdf.immediateobj() 1st argument must be string");
121         pdf_begin_obj(static_pdf, k, OBJSTM_ALWAYS);
122         st1.s = lua_tolstring(L, first_arg, &st1.l);
123         pdf_out_block(static_pdf, st1.s, st1.l);
124         /* already in pdf_end_obj:
125             if (st1.s[st1.l - 1] != '\n')
126                 pdf_out(static_pdf, '\n');
127         */
128         pdf_end_obj(static_pdf);
129         break;
130     case 2:
131     case 3:
132         if (!lua_isstring(L, first_arg))
133             luaL_error(L, "pdf.immediateobj() 1st argument must be string");
134         if (!lua_isstring(L, first_arg + 1))
135             luaL_error(L, "pdf.immediateobj() 2nd argument must be string");
136         st1_s = lua_tostring(L, first_arg);
137         st2.s = lua_tolstring(L, first_arg + 1, &st2.l);
138         if (lua_key_eq(st1_s, file)) {
139             if (n == first_arg + 2)
140                 luaL_error(L, "pdf.immediateobj() 3rd argument forbidden in file mode");
141             pdf_begin_obj(static_pdf, k, OBJSTM_ALWAYS);
142             buf.s = fread_to_buf(L, st2.s, &buf.l);
143             pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
144             /* already in pdf_end_obj:
145                 if (buf.s[buf.l - 1] != '\n')
146                     pdf_out(static_pdf, '\n');
147             */
148             xfree(buf.s);
149             pdf_end_obj(static_pdf);
150         } else {
151             pdf_begin_obj(static_pdf, k, OBJSTM_NEVER); /* not an object stream candidate! */
152             pdf_begin_dict(static_pdf);
153             if (n == first_arg + 2) {   /* write attr text */
154                 if (!lua_isstring(L, first_arg + 2))
155                     luaL_error(L, "pdf.immediateobj() 3rd argument must be string");
156                 st3.s = lua_tolstring(L, first_arg + 2, &st3.l);
157                 pdf_out_block(static_pdf, st3.s, st3.l);
158                 if (st3.s[st3.l - 1] != '\n')
159                     pdf_out(static_pdf, '\n');
160             }
161             pdf_dict_add_streaminfo(static_pdf);
162             pdf_end_dict(static_pdf);
163             pdf_begin_stream(static_pdf);
164             if (lua_key_eq(st1_s, stream)) {
165                 pdf_out_block(static_pdf, st2.s, st2.l);
166             }  else if (lua_key_eq(st1_s, streamfile)) {
167                 buf.s = fread_to_buf(L, st2.s, &buf.l);
168                 pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
169                 xfree(buf.s);
170             } else
171                 luaL_error(L, "pdf.immediateobj() invalid argument");
172             pdf_end_stream(static_pdf);
173             pdf_end_obj(static_pdf);
174         }
175         break;
176     default:
177         luaL_error(L, "pdf.immediateobj() allows max. 3 arguments");
178     }
179     lua_pushinteger(L, k);
180     return 1;
181 }
182 
table_obj(lua_State * L)183 static int table_obj(lua_State * L)
184 {
185     const char *type;
186     int k, obj_compression;
187     int compress_level = -1;    /* unset */
188     int os_threshold = OBJSTM_ALWAYS;   /* default: put non-stream objects into object streams */
189     int saved_compress_level = static_pdf->compress_level;
190     const_lstring attr, st;
191     lstring buf;
192     int immediate = 0;          /* default: not immediate */
193     attr.s = st.s = NULL;
194     attr.l = 0;
195     assert(lua_istable(L, 1));  /* t */
196 
197     /* get object "type" */
198 
199     lua_key_rawgeti(type);
200     if (lua_isnil(L, -1))       /* !vs t */
201         luaL_error(L, "pdf.obj(): object \"type\" missing");
202     if (!lua_isstring(L, -1))   /* !vs t */
203         luaL_error(L, "pdf.obj(): object \"type\" must be string");
204     type = lua_tostring(L, -1);
205 
206     if (! (lua_key_eq(type, raw) || lua_key_eq(type, stream))) {
207         luaL_error(L, "pdf.obj(): \"%s\" is not a valid object type", type);     /* i vs t */
208     }
209     lua_pop(L, 1);              /* t */
210 
211     /* get optional "immediate" */
212 
213     lua_key_rawgeti(immediate);
214     if (!lua_isnil(L, -1)) {    /* b? t */
215         if (!lua_isboolean(L, -1))      /* !b t */
216             luaL_error(L, "pdf.obj(): \"immediate\" must be boolean");
217         immediate = lua_toboolean(L, -1);       /* 0 or 1 */
218     }
219     lua_pop(L, 1);              /* t */
220 
221     /* is a reserved object referenced by "objnum"? */
222 
223     lua_key_rawgeti(objnum);
224     if (!lua_isnil(L, -1)) {    /* vi? t */
225         if (!lua_isnumber(L, -1))       /* !vi t */
226             luaL_error(L, "pdf.obj(): \"objnum\" must be integer");
227         k = (int) lua_tointeger(L, -1); /* vi t */
228         check_obj_type(static_pdf, obj_type_obj, k);
229         if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0)
230             luaL_error(L, "pdf.obj() object in use");
231     } else {
232         static_pdf->obj_count++;
233         k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1);
234     }
235     pdf_last_obj = k;
236     if (immediate == 0) {
237         obj_data_ptr(static_pdf, k) = pdf_get_mem(static_pdf, pdfmem_obj_size);
238         init_obj_obj(static_pdf, k);
239     }
240     lua_pop(L, 1);              /* t */
241 
242     /* get optional "attr" (allowed only for stream case) */
243 
244     lua_key_rawgeti(attr);
245     if (!lua_isnil(L, -1)) {    /* attr-s? t */
246         if (! lua_key_eq(type, stream))
247             luaL_error(L, "pdf.obj(): \"attr\" key not allowed for non-stream object");
248         if (!lua_isstring(L, -1))       /* !attr-s t */
249             luaL_error(L, "pdf.obj(): object \"attr\" must be string");
250         if (immediate == 1) {
251             attr.s = lua_tolstring(L, -1, &attr.l);     /* attr-s t */
252             lua_pop(L, 1);      /* t */
253         } else
254             obj_obj_stream_attr(static_pdf, k) = luaL_ref(Luas, LUA_REGISTRYINDEX);     /* t */
255     } else {
256         lua_pop(L, 1);          /* t */
257     }
258 
259     /* get optional "compresslevel" (allowed only for stream case) */
260 
261     lua_key_rawgeti(compresslevel);
262     if (!lua_isnil(L, -1)) {    /* vi? t */
263         if (lua_key_eq(type, raw))
264             luaL_error(L, "pdf.obj(): \"compresslevel\" key not allowed for raw object");
265         if (!lua_isnumber(L, -1))       /* !vi t */
266             luaL_error(L, "pdf.obj(): \"compresslevel\" must be integer");
267         compress_level = (int) lua_tointeger(L, -1);    /* vi t */
268         if (compress_level > 9)
269             luaL_error(L, "pdf.obj(): \"compresslevel\" must be <= 9");
270         else if (compress_level < 0)
271             luaL_error(L, "pdf.obj(): \"compresslevel\" must be >= 0");
272         if (immediate == 0)
273             obj_obj_pdfcompresslevel(static_pdf, k) = compress_level;
274     }
275     lua_pop(L, 1);              /* t */
276 
277     /* get optional "objcompression" (allowed only for non-stream case) */
278 
279     lua_key_rawgeti(objcompression);
280     if (!lua_isnil(L, -1)) {    /* b? t */
281         if (lua_key_eq(type, stream))
282             luaL_error(L, "pdf.obj(): \"objcompression\" key not allowed for stream object");
283         if (!lua_isboolean(L, -1))      /* !b t */
284             luaL_error(L, "pdf.obj(): \"objcompression\" must be boolean");
285         obj_compression = lua_toboolean(L, -1); /* 0 or 1 */
286         /* OBJSTM_NEVER: never into object stream; OBJSTM_ALWAYS: depends then on \pdfobjcompresslevel */
287         if (obj_compression > 0)
288             os_threshold = OBJSTM_ALWAYS;
289         else
290             os_threshold = OBJSTM_NEVER;
291         if (immediate == 0)
292             obj_obj_objstm_threshold(static_pdf, k) = os_threshold;
293     }
294     lua_pop(L, 1);              /* t */
295 
296     /* now the object contents for all cases are handled */
297 
298     lua_key_rawgeti(string);
299     lua_key_rawgeti_n(file,-2);
300 
301     if (!lua_isnil(L, -1) && !lua_isnil(L, -2)) /* file-s? string-s? t */
302         luaL_error(L, "pdf.obj(): \"string\" and \"file\" must not be given together");
303     if (lua_isnil(L, -1) && lua_isnil(L, -2))   /* nil nil t */
304         luaL_error(L, "pdf.obj(): no \"string\" or \"file\" given");
305 
306     if (lua_key_eq(type, raw)) {
307         if (immediate == 1)
308             pdf_begin_obj(static_pdf, k, os_threshold);
309         if (!lua_isnil(L, -2)) {        /* file-s? string-s? t */
310             /* from string */
311             lua_pop(L, 1);      /* string-s? t */
312             if (!lua_isstring(L, -1))   /* !string-s t */
313                 luaL_error(L, "pdf.obj(): \"string\" must be string for raw object");
314             if (immediate == 1) {
315                 st.s = lua_tolstring(L, -1, &st.l);
316                 pdf_out_block(static_pdf, st.s, st.l);
317                 /* already in pdf_end_obj:
318                     if (st.s[st.l - 1] != '\n')
319                         pdf_out(static_pdf, '\n');
320                 */
321             } else
322                 obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX);   /* t */
323         } else {
324             /* from file */
325             if (!lua_isstring(L, -1))   /* !file-s nil t */
326                 luaL_error(L, "pdf.obj(): \"file\" name must be string for raw object");
327             if (immediate == 1) {
328                 st.s = lua_tolstring(L, -1, &st.l);     /* file-s nil t */
329                 buf.s = fread_to_buf(L, st.s, &buf.l);
330                 pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
331                 /* already in pdf_end_obj:
332                     if (buf.s[buf.l - 1] != '\n')
333                         pdf_out(static_pdf, '\n');
334                 */
335                 xfree(buf.s);
336             } else {
337                 set_obj_obj_is_file(static_pdf, k);
338                 obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX);   /* nil t */
339             }
340         }
341         if (immediate == 1)
342             pdf_end_obj(static_pdf);
343     } else {
344         if (immediate == 1) {
345             pdf_begin_obj(static_pdf, k, OBJSTM_NEVER); /* 0 = not an object stream candidate! */
346             pdf_begin_dict(static_pdf);
347             if (attr.s != NULL) {
348                 pdf_out_block(static_pdf, attr.s, attr.l);
349                 if (attr.s[attr.l - 1] != '\n')
350                     pdf_out(static_pdf, '\n');
351             }
352             if (compress_level > -1)
353                 static_pdf->compress_level = compress_level;
354             pdf_dict_add_streaminfo(static_pdf);
355             pdf_end_dict(static_pdf);
356             pdf_begin_stream(static_pdf);
357         } else {
358             set_obj_obj_is_stream(static_pdf, k);
359             if (compress_level > -1)
360                 obj_obj_pdfcompresslevel(static_pdf, k) = compress_level;
361         }
362         if (!lua_isnil(L, -2)) {        /* file-s? string-s? t */
363             /* from string */
364             lua_pop(L, 1);      /* string-s? t */
365             if (!lua_isstring(L, -1))   /* !string-s t */
366                 luaL_error(L, "pdf.obj(): \"string\" must be string for stream object");
367             if (immediate == 1) {
368                 st.s = lua_tolstring(L, -1, &st.l);     /* string-s t */
369                 pdf_out_block(static_pdf, st.s, st.l);
370             } else
371                 obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX);   /* t */
372         } else {
373             /* from file */
374             if (!lua_isstring(L, -1))   /* !file-s nil t */
375                 luaL_error(L, "pdf.obj(): \"file\" name must be string for stream object");
376             if (immediate == 1) {
377                 st.s = lua_tolstring(L, -1, &st.l);     /* file-s nil t */
378                 buf.s = fread_to_buf(L, st.s, &buf.l);
379                 pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
380                 xfree(buf.s);
381             } else {
382                 set_obj_obj_is_file(static_pdf, k);
383                 obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX);   /* nil t */
384             }
385         }
386         if (immediate == 1) {
387             pdf_end_stream(static_pdf);
388             pdf_end_obj(static_pdf);
389         }
390     }
391     static_pdf->compress_level = saved_compress_level;
392     return k;
393 }
394 
orig_obj(lua_State * L)395 static int orig_obj(lua_State * L)
396 {
397     int n, first_arg = 1;
398     int k;
399     const char *st_s = NULL ;
400     n = lua_gettop(L);
401     if (n > 0 && lua_type(L, 1) == LUA_TNUMBER) {
402         first_arg++;
403         k=(int)lua_tonumber(L, 1);
404         check_obj_type(static_pdf, obj_type_obj, k);
405         if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0)
406             luaL_error(L, "pdf.obj() object in use");
407     } else {
408         static_pdf->obj_count++;
409         k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1);
410     }
411     pdf_last_obj = k;
412     obj_data_ptr(static_pdf, k) = pdf_get_mem(static_pdf, pdfmem_obj_size);
413     init_obj_obj(static_pdf, k);
414     switch (n - first_arg + 1) {
415     case 0:
416         luaL_error(L, "pdf.obj() needs at least one argument");
417         break;
418     case 1:
419         if (!lua_isstring(L, first_arg))
420             luaL_error(L, "pdf.obj() 1st argument must be string");
421         break;
422     case 2:
423     case 3:
424         if (!lua_isstring(L, first_arg))
425             luaL_error(L, "pdf.obj() 1st argument must be string");
426         if (!lua_isstring(L, first_arg + 1))
427             luaL_error(L, "pdf.obj() 2nd argument must be string");
428         st_s = lua_tostring(L, first_arg);
429         if (lua_key_eq(st_s, file)) {
430             if (n == first_arg + 2)
431                 luaL_error(L, "pdf.obj() 3rd argument forbidden in file mode");
432             set_obj_obj_is_file(static_pdf, k);
433         } else {
434             if (n == first_arg + 2) {   /* write attr text */
435                 if (!lua_isstring(L, -1))
436                     luaL_error(L, "pdf.obj() 3rd argument must be string");
437                 obj_obj_stream_attr(static_pdf, k) =
438                     luaL_ref(Luas, LUA_REGISTRYINDEX);
439             }
440             if (lua_key_eq(st_s, stream)) {
441                 set_obj_obj_is_stream(static_pdf, k);
442             } else if (lua_key_eq(st_s, streamfile)) {
443                 set_obj_obj_is_stream(static_pdf, k);
444                 set_obj_obj_is_file(static_pdf, k);
445             } else
446                 luaL_error(L, "pdf.obj() invalid argument");
447         }
448         break;
449     default:
450         luaL_error(L, "pdf.obj() allows max. 3 arguments");
451     }
452     obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX);
453     return k;
454 }
455 
l_obj(lua_State * L)456 static int l_obj(lua_State * L)
457 {
458     int k, n;
459     ensure_output_state(static_pdf, ST_HEADER_WRITTEN);
460     n = lua_gettop(L);
461     if (n == 1 && lua_istable(L, 1))
462         k = table_obj(L);       /* new */
463     else
464         k = orig_obj(L);
465     lua_pushinteger(L, k);
466     return 1;
467 }
468 
l_refobj(lua_State * L)469 static int l_refobj(lua_State * L)
470 {
471     int k, n;
472     n = lua_gettop(L);
473     if (n != 1)
474         luaL_error(L, "pdf.refobj() needs exactly 1 argument");
475     k = (int) luaL_checkinteger(L, 1);
476     if (global_shipping_mode == NOT_SHIPPING)
477         scan_refobj_lua(static_pdf, k);
478     else
479         pdf_ref_obj_lua(static_pdf, k);
480     return 0;
481 }
482 
l_reserveobj(lua_State * L)483 static int l_reserveobj(lua_State * L)
484 {
485     int n;
486     const char *st_s = NULL;
487     n = lua_gettop(L);
488     switch (n) {
489     case 0:
490         static_pdf->obj_count++;
491         pdf_last_obj =
492             pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1);
493         break;
494     case 1:
495         if (!lua_isstring(L, -1))
496             luaL_error(L, "pdf.reserveobj() optional argument must be string");
497         if (lua_key_eq(st_s, annot)) {
498             pdf_last_annot = pdf_create_obj(static_pdf, obj_type_annot, 0);
499         } else {
500             luaL_error(L, "pdf.reserveobj() optional string must be \"annot\"");
501         }
502         lua_pop(L, 1);
503         break;
504     default:
505         luaL_error(L, "pdf.reserveobj() allows max. 1 argument");
506     }
507     lua_pushinteger(L, static_pdf->obj_ptr);
508     return 1;
509 }
510 
l_registerannot(lua_State * L)511 static int l_registerannot(lua_State * L)
512 {
513     int n, i;
514     n = lua_gettop(L);
515     switch (n) {
516     case 1:
517         if (global_shipping_mode == NOT_SHIPPING)
518             luaL_error(L, "pdf.registerannot() can only be used in late lua");
519         i = (int) luaL_checkinteger(L, 1);
520         if (i <= 0)
521             luaL_error(L, "pdf.registerannot() can only register positive object numbers");
522         addto_page_resources(static_pdf, obj_type_annot, i);
523         break;
524     default:
525         luaL_error(L, "pdf.registerannot() needs exactly 1 argument");
526     }
527     return 0;
528 }
529 
l_get_pdf_value(lua_State * L,int key)530 static int l_get_pdf_value(lua_State * L, int key)
531 {
532     lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(pdf_data));
533     lua_gettable(L, LUA_REGISTRYINDEX);
534     /* [table] */
535     lua_rawgeti(L, LUA_REGISTRYINDEX, key);
536     /* [table] [key] */
537     lua_rawget(L,-2);
538     return 1;
539 }
l_get_pageresources(lua_State * L)540 static int l_get_pageresources(lua_State * L) {
541     return l_get_pdf_value(L,lua_key_index(pageresources));
542 }
l_get_pageattributes(lua_State * L)543 static int l_get_pageattributes(lua_State * L) {
544     return l_get_pdf_value(L,lua_key_index(pageattributes));
545 }
l_get_pagesattributes(lua_State * L)546 static int l_get_pagesattributes(lua_State * L) {
547     return l_get_pdf_value(L,lua_key_index(pagesattributes));
548 }
l_get_catalog(lua_State * L)549 static int l_get_catalog(lua_State * L) {
550     return l_get_pdf_value(L,lua_key_index(catalog));
551 }
l_get_info(lua_State * L)552 static int l_get_info(lua_State * L) {
553     return l_get_pdf_value(L,lua_key_index(info));
554 }
l_get_names(lua_State * L)555 static int l_get_names(lua_State * L) {
556     return l_get_pdf_value(L,lua_key_index(names));
557 }
558 
559 
l_get_trailer(lua_State * L)560 static int l_get_trailer(lua_State * L) {
561     return l_get_pdf_value(L,lua_key_index(trailer));
562 }
563 
564 
getpdf(lua_State * L)565 static int getpdf(lua_State * L)
566 {
567     /* [pdf table] [key] */
568     const char *s ;
569     if (lua_gettop(L) != 2) {
570         return 0;
571     }
572     if (lua_isstring(L, -1)) {
573         s =  lua_tostring(L, -1);
574         if (lua_key_eq(s,h)) {
575             lua_pushnumber(L, static_pdf->posstruct->pos.h);
576 	    return 1;
577         } else if (lua_key_eq(s,v)) {
578             lua_pushnumber(L, static_pdf->posstruct->pos.v);
579 	    return 1;
580         } else if (
581                 lua_key_eq(s,catalog) || lua_key_eq(s,info) || lua_key_eq(s,trailer) || lua_key_eq(s,names) ||
582                 lua_key_eq(s,pageattributes) || lua_key_eq(s,pagesattributes) || lua_key_eq(s,pageresources)
583             ) {
584             lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(pdf_data));
585             lua_gettable(L, LUA_REGISTRYINDEX);
586             /* [pdf table] [key] [pdf.data table] */
587             lua_replace(L, -3);
588             /* [pdf.data table] [key] */
589 	    lua_rawget(L, -2);
590 	    return 1;
591         }
592     }
593     return 0;
594 }
595 
596 
597 
598 
l_set_pdf_value(lua_State * L,int key)599 static int l_set_pdf_value(lua_State * L, int key)
600 {
601     if (lua_isstring(L, -1)) {
602         /* [value] */
603         lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(pdf_data));
604         lua_gettable(L, LUA_REGISTRYINDEX);
605         /* [value] [table]  */
606         lua_rawgeti(L, LUA_REGISTRYINDEX, key);
607         /* [value] [table] [key] */
608         lua_pushvalue(L, -3);
609         /* [table] [key] [value] */
610         lua_rawset(L,-3);
611     }
612     return 0;
613 }
l_set_pageresources(lua_State * L)614 static int l_set_pageresources(lua_State * L) {
615     return l_set_pdf_value(L,lua_key_index(pageresources));
616 }
l_set_pageattributes(lua_State * L)617 static int l_set_pageattributes(lua_State * L) {
618     return l_set_pdf_value(L,lua_key_index(pageattributes));
619 }
l_set_pagesattributes(lua_State * L)620 static int l_set_pagesattributes(lua_State * L) {
621     return l_set_pdf_value(L,lua_key_index(pagesattributes));
622 }
l_set_catalog(lua_State * L)623 static int l_set_catalog(lua_State * L) {
624     return l_set_pdf_value(L,lua_key_index(catalog));
625 }
l_set_info(lua_State * L)626 static int l_set_info(lua_State * L) {
627     return l_set_pdf_value(L,lua_key_index(info));
628 }
l_set_names(lua_State * L)629 static int l_set_names(lua_State * L) {
630     return l_set_pdf_value(L,lua_key_index(names));
631 }
l_set_trailer(lua_State * L)632 static int l_set_trailer(lua_State * L) {
633     return l_set_pdf_value(L,lua_key_index(trailer));
634 }
635 
636 
setpdf(lua_State * L)637 static int setpdf(lua_State * L)
638 {
639     /* [pdf table] [key] [value] */
640     const char *s ;
641     if (lua_gettop(L) != 3) {
642         return 0;
643     }
644     if (lua_isstring(L, -2)) {
645         s =  lua_tostring(L, -1);
646         if (
647                 lua_key_eq(s,catalog) || lua_key_eq(s,info) || lua_key_eq(s,trailer) || lua_key_eq(s,names) ||
648                 lua_key_eq(s,pageattributes) || lua_key_eq(s,pagesattributes) || lua_key_eq(s,pageresources)
649             ) {
650             lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(pdf_data));
651             lua_gettable(L, LUA_REGISTRYINDEX);
652             /* [pdf table] [key] [value] [pdf.data table] */
653             lua_replace(L, -4);
654             /* [pdf.data table] [key] [value] */
655         }
656     }
657     lua_rawset(L, -3);
658     return 0;
659 }
660 
661 
l_objtype(lua_State * L)662 static int l_objtype(lua_State * L)
663 {
664     int n = lua_gettop(L);
665     if (n != 1)
666         luaL_error(L, "pdf.objtype() needs exactly 1 argument");
667     n = (int) luaL_checkinteger(L, 1);
668     if (n < 0 || n > static_pdf->obj_ptr)
669         lua_pushnil(L);
670     else
671         lua_pushstring(L, pdf_obj_typenames[obj_type(static_pdf, n)]);
672     return 1;
673 }
674 
l_maxobjnum(lua_State * L)675 static int l_maxobjnum(lua_State * L)
676 {
677     int n = lua_gettop(L);
678     if (n != 0)
679         luaL_error(L, "pdf.maxobjnum() needs 0 arguments");
680     lua_pushinteger(L, static_pdf->obj_ptr);
681     return 1;
682 }
683 
l_mapfile(lua_State * L)684 static int l_mapfile(lua_State * L)
685 {
686     char *s;
687     const char *st;
688     if (lua_isstring(L, -1) && (st = lua_tostring(L, -1)) != NULL) {
689         s = xstrdup(st);
690         process_map_item(s, MAPFILE);
691         free(s);
692     }
693     return 0;
694 }
695 
l_mapline(lua_State * L)696 static int l_mapline(lua_State * L)
697 {
698     char *s;
699     const char *st;
700     if (lua_isstring(L, -1) && (st = lua_tostring(L, -1)) != NULL) {
701         s = xstrdup(st);
702         process_map_item(s, MAPLINE);
703         free(s);
704     }
705     return 0;
706 }
707 
l_pageref(lua_State * L)708 static int l_pageref(lua_State * L)
709 {
710     int n = lua_gettop(L);
711     if (n != 1)
712         luaL_error(L, "pdf.pageref() needs exactly 1 argument");
713     n = (int) luaL_checkinteger(L, 1);
714     if (n <= 0)
715         luaL_error(L, "pdf.pageref() needs page number > 0");
716     n = pdf_get_obj(static_pdf, obj_type_page, n, false);
717     lua_pushnumber(L, n);
718     return 1;
719 }
720 
l_getpos(lua_State * L)721 static int l_getpos(lua_State * L)
722 {
723     lua_pushnumber(L, static_pdf->posstruct->pos.h);
724     lua_pushnumber(L, static_pdf->posstruct->pos.v);
725     return 2;
726 }
727 
l_gethpos(lua_State * L)728 static int l_gethpos(lua_State * L)
729 {
730     lua_pushnumber(L, static_pdf->posstruct->pos.h);
731     return 1;
732 }
733 
l_getvpos(lua_State * L)734 static int l_getvpos(lua_State * L)
735 {
736     lua_pushnumber(L, static_pdf->posstruct->pos.v);
737     return 1;
738 }
739 
l_getmatrix(lua_State * L)740 static int l_getmatrix(lua_State * L)
741 {
742     if (matrix_stack_used > 0) {
743         matrix_entry *m = &matrix_stack[matrix_stack_used - 1];
744         lua_pushnumber(L, m->a);
745         lua_pushnumber(L, m->b);
746         lua_pushnumber(L, m->c);
747         lua_pushnumber(L, m->d);
748         lua_pushnumber(L, m->e);
749         lua_pushnumber(L, m->f);
750     } else {
751         lua_pushnumber(L, 1);
752         lua_pushnumber(L, 0);
753         lua_pushnumber(L, 0);
754         lua_pushnumber(L, 1);
755         lua_pushnumber(L, 0);
756         lua_pushnumber(L, 0);
757     }
758     return 6 ;
759 }
760 
l_hasmatrix(lua_State * L)761 static int l_hasmatrix(lua_State * L)
762 {
763     lua_pushboolean(L, (matrix_stack_used > 0));
764     return 1 ;
765 }
766 
767 
768 static const struct luaL_Reg pdflib[] = {
769     {"immediateobj", l_immediateobj},
770     {"mapfile", l_mapfile},
771     {"mapline", l_mapline},
772     {"maxobjnum", l_maxobjnum},
773     {"obj", l_obj},
774     {"objtype", l_objtype},
775     {"pageref", l_pageref},
776     {"print", luapdfprint},
777     {"refobj", l_refobj},
778     {"registerannot", l_registerannot},
779     {"reserveobj", l_reserveobj},
780     {"getpos", l_getpos},
781     {"gethpos", l_gethpos},
782     {"getvpos", l_getvpos},
783     {"getmatrix", l_getmatrix},
784     {"hasmatrix", l_hasmatrix},
785     {"setcatalog", l_set_catalog},
786     {"setinfo", l_set_info},
787     {"setnames", l_set_names},
788     {"settrailer", l_set_trailer},
789     {"setpageresources", l_set_pageresources},
790     {"setpageattributes", l_set_pageattributes},
791     {"setpagesattributes", l_set_pagesattributes},
792     {"getcatalog", l_get_catalog},
793     {"getinfo", l_get_info},
794     {"getnames", l_get_names},
795     {"gettrailer", l_get_trailer},
796     {"getpageresources", l_get_pageresources},
797     {"getpageattributes", l_get_pageattributes},
798     {"getpagesattributes", l_get_pagesattributes},
799     {NULL, NULL}                /* sentinel */
800 };
801 
802 /**********************************************************************/
803 
luaopen_pdf(lua_State * L)804 int luaopen_pdf(lua_State * L)
805 {
806     lua_pushstring(L,"pdf.data");
807     lua_newtable(L);
808     lua_settable(L,LUA_REGISTRYINDEX);
809     /* */
810     luaL_register(L, "pdf", pdflib);
811     /* build meta table */
812     luaL_newmetatable(L, "pdf.meta");
813     lua_pushstring(L, "__index");
814     lua_pushcfunction(L, getpdf);
815     /* do these later, NYI */
816     lua_settable(L, -3);
817     lua_pushstring(L, "__newindex");
818     lua_pushcfunction(L, setpdf);
819     lua_settable(L, -3);
820     lua_setmetatable(L, -2);    /* meta to itself */
821     return 1;
822 }
823