beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / lua / lpdfscannerlib.cc
blobcc311daebeece14ef4b24731023b2b6a247ecbd1
1 /* lpdfscannerlib.c
3 Copyright 2013 Taco Hoekwater <taco@luatex.org>
5 This file is part of LuaTeX.
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.
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.
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/>. */
20 # include <stdlib.h>
21 # include <stdio.h>
22 # include <stdarg.h>
23 # include <string.h>
24 # include <assert.h>
25 # include <math.h>
27 extern "C" {
28 # include <lua.h>
29 # include <lauxlib.h>
30 # include <lualib.h>
33 # include <poppler-config.h>
34 # include <goo/GooString.h>
35 # include <goo/gmem.h>
36 # include <goo/gfile.h>
37 # include <Object.h>
38 # include <Stream.h>
39 # include <Gfx.h>
40 # include <Annot.h>
41 # include <Array.h>
42 # include <Dict.h>
43 # include <XRef.h>
44 # include <Catalog.h>
45 # include <Link.h>
46 # include <Page.h>
47 # include <GfxFont.h>
48 # include <PDFDoc.h>
49 # include <GlobalParams.h>
50 # include <Error.h>
52 # include <lua/luatex-api.h>
55 #define SCANNER "pdfscanner"
57 #define MAXOPERANDS 1000
59 typedef enum {
60 pdf_integer = 1,
61 pdf_real,
62 pdf_boolean,
63 pdf_name,
64 pdf_operator,
65 pdf_string,
66 pdf_startarray,
67 pdf_stoparray,
68 pdf_startdict,
69 pdf_stopdict,
70 } pdf_token_type ;
73 typedef struct Token {
74 pdf_token_type type;
75 double value;
76 char *string;
77 } Token;
79 typedef struct ObjectList {
80 struct ObjectList *next;
81 Object *stream;
82 } ObjectList;
84 typedef struct scannerdata {
85 int _ininlineimage;
86 int _nextoperand;
87 Token ** _operandstack;
88 Object * _stream;
89 ObjectList * _streams;
90 } scannerdata;
92 typedef enum { ALLOC_POPPLER, ALLOC_LEPDF } alloctype;
94 #define M_Object "Object"
95 #define M_Stream "Stream"
97 typedef struct {
98 void *d;
99 alloctype atype; // was it allocated by poppler or the lepdflib.cc?
100 void *pd; // reference to PdfDocument, or NULL
101 unsigned long pc; // counter to detect PDFDoc change
102 } udstruct;
104 static void clear_operand_stack (scannerdata *self, int from);
105 static Token *_parseToken (scannerdata *self, int c);
106 static void push_token (lua_State *L, scannerdata *self);
108 void *xmalloc (size_t size)
110 void *new_mem = (void *)malloc(size);
111 if (new_mem == NULL) {
112 fprintf(stderr, "fatal: memory exhausted (xmalloc of %lu bytes).\n", (unsigned long)size);
113 exit(1);
115 return new_mem;
118 void *xrealloc (void *old_ptr, size_t size)
120 void *new_mem = (void *)realloc(old_ptr, size);
121 if (new_mem == NULL) {
122 fprintf(stderr,"fatal: memory exhausted (realloc of %lu bytes).\n", (unsigned long)size);
123 exit(EXIT_FAILURE);
125 return new_mem;
128 #define xreallocarray(ptr,type,size) ((type*)xrealloc(ptr,(size+1)*sizeof(type)))
130 #define INITBUFSIZE 64
132 #define define_buffer(a) \
133 char *a = (char *)xmalloc (INITBUFSIZE); \
134 int a##_size = INITBUFSIZE; \
135 int a##index = 0; \
136 memset (a,0,INITBUFSIZE)
138 #define check_overflow(a, wsize) do { \
139 if (wsize >= a##_size) { \
140 int nsize = a##_size + a##_size / 4; \
141 a = (char *) xreallocarray(a, char, (unsigned) nsize); \
142 memset (a+a##_size, 0, a##_size / 4); \
143 a##_size = nsize; \
145 } while (0)
148 static scannerdata * scanner_push(lua_State * L)
150 scannerdata *a = (scannerdata *)lua_newuserdata(L, sizeof(scannerdata));
151 luaL_getmetatable(L, SCANNER);
152 lua_setmetatable(L, -2);
153 return a;
156 static scannerdata *scanner_check (lua_State *L, int index)
158 scannerdata *bar;
159 luaL_checktype(L, index, LUA_TUSERDATA);
160 bar = (scannerdata *)luaL_checkudata(L, index, SCANNER);
161 if (bar == NULL) luaL_argerror(L, index, SCANNER " expected");
162 return bar;
165 static void free_token (Token *token)
167 if (token->string) {
168 free(token->string);
170 free(token);
173 static void clear_operand_stack (scannerdata *self, int from)
175 int i = self->_nextoperand-1;
176 while (i>=from) {
177 if (self->_operandstack[i]) {
178 free_token(self->_operandstack[i]);
179 self->_operandstack[i] = NULL;
181 i--;
183 self->_nextoperand = from;
186 static void push_operand (scannerdata *self, Token *token)
188 if (self->_nextoperand+1> MAXOPERANDS) {
189 fprintf(stderr, "out of operand stack space");
190 exit(1);
192 self->_operandstack[self->_nextoperand++] = token;
195 static Token * new_operand (pdf_token_type c)
197 Token *token = (Token *)xmalloc(sizeof(Token));
198 memset (token, 0, sizeof(Token));
199 token->type = c;
200 return token;
203 static void _nextStream (scannerdata *self) {
204 self->_stream->streamClose();
205 ObjectList *rover = self->_streams;
206 self->_stream = rover->stream;
207 self->_stream->streamReset();
208 self->_streams = rover->next;
209 free(rover);
212 static int streamGetChar (scannerdata *self) {
213 int i = self->_stream->streamGetChar();
214 if (i<0 && self->_streams) {
215 _nextStream(self);
216 i = streamGetChar(self);
218 return i;
221 static int streamLookChar (scannerdata *self) {
222 int i= self->_stream->streamLookChar();
223 if (i<0 && self->_streams) {
224 _nextStream(self);
225 i = streamLookChar(self);
227 return i;
230 static Token * _parseSpace (scannerdata *self)
232 return _parseToken (self,streamGetChar(self));
235 static Token * _parseString (scannerdata *self, int c)
237 // local token = {type = pdf_string,value = ''}
238 define_buffer(found);
239 int level = 1;
240 while (1) {
241 c = streamGetChar(self);
242 if (c == '(') {
243 level = level + 1 ;
245 if (c == ')') {
246 level = level - 1 ;
247 if (level < 1) break;
249 if (c == '\\') {
250 int next = streamGetChar(self);
251 if (next == '(' || next == ')' || next == '\\') {
252 c = next;
253 } else if (next == '\n' || next == '\r') {
254 c = '\0';
255 } else if (next == 'n') {
256 c = '\n';
257 } else if (next == 'r') {
258 c = '\r';
259 } else if (next == 't') {
260 c = '\t';
261 } else if (next == 'b') {
262 c = '\b';
263 } else if (next == 'f') {
264 c = '\f';
265 } else if (next >= '0' && next <= '7') {
266 next = next - '0';
267 int next2 = streamLookChar(self);
268 if (next2 >= '0' && next2 <= '7') {
269 next2 = streamGetChar(self);
270 next2 = next2 - '0';
271 int next3 = streamLookChar(self);
272 if (next3 >= '0' && next3 <= '7') {
273 next3 = streamGetChar(self);
274 next3 = next3 - '0';
275 c = (next*64+next2*8+next3);
276 } else {
277 c = (next*8+next2);
279 } else {
280 c = next;
282 } else {
283 c = next;
286 check_overflow(found,foundindex);
287 if (c>=0) {
288 found[foundindex++] = c;
291 Token *token = new_operand(pdf_string);
292 token->value = foundindex;
293 token->string = found;
294 return token;
298 static Token * _parseNumber (scannerdata *self, int c)
300 double value = 0;
301 pdf_token_type type = pdf_integer;
302 int isfraction = 0;
303 int isnegative = 0;
304 int i = 0;
305 if (c == '-') {
306 isnegative = 1;
307 c = streamGetChar(self);
309 if (c == '.') {
310 type = pdf_real;
311 isfraction = 1;
312 } else {
313 value = c - '0';
315 c = streamLookChar(self);
316 if ((c>= '0'&& c<= '9') || c == '.') {
317 c = streamGetChar(self);
318 while (1) {
319 if (c == '.') {
320 type = pdf_real;
321 isfraction = 1;
322 } else {
323 i = c - '0';
324 if (isfraction>0) {
325 value = value + (i/(pow(10.0,isfraction)));
326 isfraction = isfraction + 1;
327 } else {
328 value = (value * 10) + i;
331 c = streamLookChar(self);
332 if (! ((c>= '0' && c<= '9') || c == '.')) break ;
333 c = streamGetChar(self);
336 if (isnegative) {
337 value = -value;
339 Token *token = new_operand(type);
340 token->value = value;
341 return token;
345 static Token *_parseName (scannerdata *self, int c)
347 define_buffer(found);
348 c = streamGetChar(self);
349 while (1) {
350 check_overflow(found,foundindex);
351 found[foundindex++] = c;
352 c = streamLookChar(self);
353 if (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
354 c == '/' || c == '[' || c == '(' || c == '<') break ;
355 c = streamGetChar(self);
357 Token *token = new_operand(pdf_name);
358 token->string = found;
359 token->value = strlen(found);
360 return token;
363 #define hexdigit(c) \
364 (c>= '0' && c<= '9') ? (c - '0') : ((c>= 'A' && c<= 'F') ? (c - 'A' + 10) : (c - 'a' + 10))
366 static Token *_parseHexstring (scannerdata *self, int c)
368 int isodd = 1;
369 int hexval = 0;
370 define_buffer(found);
371 while (c != '>') {
372 if ((c>= '0' && c<= '9') ||
373 (c>= 'A' && c<= 'F') ||
374 (c>= 'a' && c<= 'f')) {
375 if (isodd==1) {
376 int v = hexdigit(c);
377 hexval = 16 * v;
378 } else {
379 hexval += hexdigit(c);
380 check_overflow(found,foundindex);
381 found[foundindex++] = hexval;
383 isodd = (isodd==1 ? 0 : 1);
385 c = streamGetChar(self);
387 Token *token = new_operand(pdf_string);
388 token->value = foundindex;
389 token->string = found;
390 return token;
393 #define pdf_isspace(a) (a == '\0' || a == ' ' || a == '\n' || a == '\r' || a == '\t' || a == '\v')
395 // -- this is rather horrible
396 static Token *_parseInlineImage (scannerdata *self, int c)
398 define_buffer(found);
399 if (c == ' ') { // first space can be ignored
400 c = streamGetChar(self);
402 check_overflow(found, foundindex);
403 found[foundindex++] = c;
404 while (1) {
405 c = streamLookChar(self);
406 if (c == 'E' && (found[foundindex-1] == '\n' || found[foundindex-1] == '\r')) {
407 c = streamGetChar(self);
408 check_overflow(found, foundindex);
409 found[foundindex++] = c;
410 c = streamLookChar(self);
411 if (c == 'I') {
412 c = streamGetChar(self);
413 check_overflow(found, foundindex);
414 found[foundindex++] = c;
415 c = streamLookChar(self);
416 if (pdf_isspace(c)) {
417 found[--foundindex] = '\0'; /* I */
418 found[--foundindex] = '\0'; /* E */
419 /* remove end-of-line before EI */
420 if (found[foundindex-1] == '\n') {
421 found[--foundindex] = '\0';
423 if (found[foundindex-1] == '\r') {
424 found[--foundindex] = '\0';
426 break;
427 } else {
428 c = streamGetChar(self);
429 check_overflow(found, foundindex);
430 found[foundindex++] = c;
432 } else {
433 c = streamGetChar(self);
434 check_overflow(found, foundindex);
435 found[foundindex++] = c;
437 } else {
438 c = streamGetChar(self);
439 check_overflow(found, foundindex);
440 found[foundindex++] = c;
443 Token *token = new_operand(pdf_string);
444 token->value = foundindex;
445 token->string = found;
446 return token;
449 static Token *_parseOperator (scannerdata *self, int c)
451 define_buffer(found);
452 while (1) {
453 check_overflow(found, foundindex);
454 found[foundindex++] = c;
455 c = streamLookChar(self);
456 if ((c<0) || (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
457 c == '/' || c == '[' || c == '(' || c == '<'))
458 break ;
459 c = streamGetChar(self);
461 // print (found)
462 if (strcmp(found, "ID") == 0) {
463 self->_ininlineimage = 1;
465 if (strcmp(found,"false") == 0) {
466 Token *token = new_operand(pdf_boolean);
467 token->value = 0;
468 free(found);
469 return token;
470 } else if (strcmp(found,"true") == 0) {
471 Token *token = new_operand(pdf_boolean);
472 token->value = 1.0;
473 free(found);
474 return token;
475 } else {
476 Token *token = new_operand(pdf_operator);
477 token->string = found;
478 return token;
483 static Token * _parseComment (scannerdata *self, int c)
485 do {
486 c = streamGetChar(self);
487 } while (c != '\n' && c != '\r' && c != -1);
488 return _parseToken(self,streamGetChar(self));
491 static Token *_parseLt (scannerdata *self, int c)
493 c = streamGetChar(self);
494 if (c == '<') {
495 return new_operand(pdf_startdict);
496 } else {
497 return _parseHexstring(self,c);
501 static Token * _parseGt (scannerdata *self, int c)
503 c = streamGetChar(self);
504 if (c== '>') {
505 return new_operand(pdf_stopdict);
506 } else {
507 fprintf(stderr,"stray > in stream");
508 return NULL;
513 static Token *_parseError (int c)
515 fprintf(stderr, "stray %c [%d] in stream", c, c);
516 return NULL;
519 static Token *_parseStartarray ()
521 return new_operand (pdf_startarray);
524 static Token *_parseStoparray ()
526 return new_operand (pdf_stoparray);
530 static Token *_parseToken (scannerdata *self, int c)
532 if (self->_ininlineimage==1) {
533 self->_ininlineimage = 2;
534 return _parseInlineImage(self,c);
535 } else if (self->_ininlineimage==2) {
536 self->_ininlineimage = 0;
537 Token *token = new_operand(pdf_operator);
538 token->string = strdup("EI");
539 return token;
541 if (c<0) return NULL ;
542 switch (c) {
543 case '(': return _parseString(self,c); break;
544 case ')': return _parseError(c); break;
545 case '[': return _parseStartarray(); break;
546 case ']': return _parseStoparray(); break;
547 case '/': return _parseName(self,c); break;
548 case '<': return _parseLt(self,c); break;
549 case '>': return _parseGt(self,c); break;
550 case '%': return _parseComment(self,c); break;
551 case ' ':
552 case '\r':
553 case '\n':
554 case '\t':
555 return _parseSpace(self); break;
556 case '0':
557 case '1':
558 case '2':
559 case '3':
560 case '4':
561 case '5':
562 case '6':
563 case '7':
564 case '8':
565 case '9':
566 case '-':
567 case '.':
568 return _parseNumber(self,c); break;
569 default:
570 if (c<=127) {
571 return _parseOperator(self,c);
572 } else {
573 return _parseError(c);
578 static int scanner_scan(lua_State * L)
580 Token *token;
581 scannerdata *self;
582 if (lua_gettop(L) != 3) {
583 return 0;
585 luaL_checktype(L, 2, LUA_TTABLE);
586 luaL_checktype(L, 3, LUA_TTABLE);
587 self = scanner_push(L);
588 memset(self,0,sizeof(scannerdata));
589 self->_operandstack = (Token **)xmalloc (MAXOPERANDS * sizeof (Token));
590 memset (self->_operandstack,0,(MAXOPERANDS * sizeof (Token)));
591 // 4 = self
592 if (lua_type(L,1)== LUA_TTABLE) {
593 udstruct *uin;
594 int i = 1;
595 while (1) {
596 lua_rawgeti(L,1,i);
597 if (lua_type(L,-1)== LUA_TUSERDATA) {
598 uin = (udstruct *) luaL_checkudata(L, -1, M_Object);
599 if (((Object *) uin->d)->isStream()) {
600 ObjectList *rover = self->_streams;
601 ObjectList *item = (ObjectList *)xmalloc (sizeof(ObjectList));
602 item->stream = ((Object *) uin->d);
603 item->next = NULL;
604 if (!rover) {
605 rover = item;
606 self->_streams = rover;
607 } else {
608 while (rover->next)
609 rover = rover->next;
610 rover->next = item;
613 } else { // done
614 ObjectList *rover = self->_streams;
615 self->_stream = rover->stream;
616 self->_streams = rover->next;
617 free(rover);
618 lua_pop(L,1);
619 break;
621 lua_pop(L,1);
622 i++;
625 } else {
626 udstruct *uin;
627 luaL_checktype(L, 1, LUA_TUSERDATA);
628 uin = (udstruct *) luaL_checkudata(L, 1, M_Object);
629 if (((Object *) uin->d)->isStream()) {
630 self->_stream = ((Object *) uin->d);
631 } else if (((Object *) uin->d)->isArray()) {
632 Array *arrayref = ((Object *) uin->d)->getArray();
633 int count = arrayref->getLength();
634 int i;
635 for (i=0;i<count;i++) {
636 Object *val = new Object();
637 arrayref->get(i, val);
638 if (val->isStream()) {
639 ObjectList *rover = self->_streams;
640 ObjectList *item = (ObjectList *)xmalloc (sizeof(ObjectList));
641 item->stream = val;
642 item->next = NULL;
643 if (!rover) {
644 rover = item;
645 self->_streams = rover;
646 } else {
647 while (rover->next)
648 rover = rover->next;
649 rover->next = item;
653 ObjectList *rover = self->_streams;
654 self->_stream = rover->stream;
655 self->_streams = rover->next;
659 assert (lua_gettop(L) == 4);
660 self->_stream->streamReset();
661 token = _parseToken(self,streamGetChar(self));
662 while (token) {
663 if (token->type == pdf_operator) {
664 lua_pushstring(L, token->string);
665 free_token(token);
666 lua_rawget(L,2); // operator table
667 if (lua_isfunction(L,-1)) {
668 lua_pushvalue(L,4);
669 lua_pushvalue(L,3);
670 (void)lua_call(L,2,0);
671 } else {
672 lua_pop(L,1); // nil
674 clear_operand_stack(self,0);
675 } else {
676 push_operand(self, token);
678 if (!self->_stream) {
679 break;
681 token = _parseToken(self,streamGetChar(self));
683 /* wrap up */
684 if (self->_stream) {
685 self->_stream->streamClose();
686 self->_stream = NULL;
688 clear_operand_stack(self,0);
689 free(self->_operandstack);
690 return 0;
693 static int scanner_done(lua_State * L)
695 int c;
696 scannerdata *self = scanner_check(L,1);
697 while ((c=streamGetChar(self))>=0)
699 return 0;
702 // here are the stack popping functions, and their helpers
704 static void operandstack_backup (scannerdata *self) {
705 int i = self->_nextoperand-1;
706 int balance = 0;
707 int backupstart = 0;
708 int backupstop = self->_operandstack[i]->type;
709 if (backupstop == pdf_stopdict) {
710 backupstart = pdf_startdict;
711 } else if (backupstop == pdf_stoparray) {
712 backupstart = pdf_startarray;
713 } else {
714 return;
716 for (;i>=0;i--) {
717 if (self->_operandstack[i]->type == backupstop) {
718 balance++;
719 } else if (self->_operandstack[i]->type == backupstart) {
720 balance--;
722 if (balance==0) {
723 break;
726 self->_nextoperand = i+1;
729 static void push_array (lua_State *L, scannerdata *self)
731 int balance = 1; // nesting tracking
732 int index = 1; // lua array index
733 Token *token = self->_operandstack[self->_nextoperand++];
734 lua_newtable(L);
735 while (token) {
736 if (token->type == pdf_stoparray)
737 balance --;
738 if (token->type == pdf_startarray)
739 balance ++;
740 if (!balance) {
741 break;
742 } else {
743 push_token(L,self);
744 lua_rawseti(L,-2, index++);
746 token = self->_operandstack[self->_nextoperand++];
751 static void push_dict (lua_State *L, scannerdata *self)
753 int balance = 1; // nesting tracking
754 int needskey = 1; // toggle between lua value and lua key
755 Token *token = self->_operandstack[self->_nextoperand++];
756 lua_newtable(L);
757 while (token) {
758 if (token->type == pdf_stopdict)
759 balance --;
760 if (token->type == pdf_startdict)
761 balance ++;
762 if (!balance) {
763 break;
764 } else {
765 if (needskey) {
766 lua_pushlstring(L, token->string, token->value);
767 needskey = 0;
768 } else {
769 push_token(L,self);
770 needskey = 1;
771 lua_rawset(L,-3);
774 token = self->_operandstack[self->_nextoperand++];
778 const char *typenames[pdf_stopdict+1] =
779 { "unknown", "integer", "real", "boolean", "name", "operator",
780 "string", "array", "array", "dict", "dict" };
782 static void push_token (lua_State *L, scannerdata *self)
784 Token *token = self->_operandstack[self->_nextoperand-1];
785 lua_createtable(L,2,0);
786 lua_pushstring (L, typenames[token->type]);
787 lua_rawseti(L,-2,1);
788 if (token->type == pdf_string || token->type == pdf_name) {
789 lua_pushlstring(L, token->string, token->value);
790 } else if (token->type == pdf_real || token->type == pdf_integer) {
791 lua_pushnumber(L, token->value); /* integer or float */
792 } else if (token->type == pdf_boolean) {
793 lua_pushboolean(L, (int)token->value);
794 } else if (token->type == pdf_startarray) {
795 push_array(L, self);
796 } else if (token->type == pdf_startdict) {
797 push_dict(L, self);
798 } else {
799 lua_pushnil(L);
801 lua_rawseti(L,-2, 2);
804 static int scanner_popsingular (lua_State * L, int token_type) {
805 int clear = 0; // how much of the operand stack needs deleting
806 scannerdata *self = scanner_check(L,1);
807 if (self->_nextoperand==0) {
808 return 0;
810 clear = self->_nextoperand-1;
811 Token *token = self->_operandstack[self->_nextoperand-1];
812 if (token ==NULL || (token->type != token_type )) {
813 return 0;
815 // the simple cases can be written out directly, but dicts and
816 // arrays are better done via the recursive function
817 if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
818 operandstack_backup(self);
819 clear = self->_nextoperand-1;
820 push_token(L, self);
821 lua_rawgeti(L,-1,2);
822 } else if (token_type == pdf_real || token_type == pdf_integer) {
823 lua_pushnumber(L, token->value); /* integer or float */
824 } else if (token_type == pdf_boolean) {
825 lua_pushboolean(L,(int)token->value);
826 } else if (token_type == pdf_name || token_type == pdf_string) {
827 lua_pushlstring(L, token->string, token->value);
828 } else {
829 return 0;
831 clear_operand_stack(self,clear);
832 return 1;
835 static int scanner_popanything (lua_State * L) {
836 int clear = 0; // how much of the operand stack needs deleting
837 scannerdata *self = scanner_check(L,1);
838 if (self->_nextoperand==0) {
839 return 0;
841 clear = self->_nextoperand-1;
842 Token *token = self->_operandstack[self->_nextoperand-1];
843 if (token ==NULL) {
844 return 0;
846 int token_type = token->type;
847 // the simple cases can be written out directly, but dicts and
848 // arrays are better done via the recursive function
849 if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
850 operandstack_backup(self);
851 clear = self->_nextoperand-1;
852 push_token(L, self);
853 } else {
854 push_token(L, self);
856 clear_operand_stack(self,clear);
857 return 1;
861 static int scanner_popnumber(lua_State * L)
863 if(scanner_popsingular(L,pdf_real))
864 return 1;
865 if (scanner_popsingular(L,pdf_integer))
866 return 1;
867 lua_pushnil(L);
868 return 1;
871 static int scanner_popboolean(lua_State * L)
873 if(scanner_popsingular(L,pdf_boolean))
874 return 1;
875 lua_pushnil(L);
876 return 1;
879 static int scanner_popstring(lua_State * L)
881 if (scanner_popsingular(L,pdf_string))
882 return 1;
883 lua_pushnil(L);
884 return 1;
887 static int scanner_popname(lua_State * L)
889 if (scanner_popsingular(L,pdf_name))
890 return 1;
891 lua_pushnil(L);
892 return 1;
895 static int scanner_poparray(lua_State * L)
897 if (scanner_popsingular(L,pdf_stoparray))
898 return 1;
899 lua_pushnil(L);
900 return 1;
903 static int scanner_popdictionary(lua_State * L)
905 if (scanner_popsingular(L,pdf_stopdict))
906 return 1;
907 lua_pushnil(L);
908 return 1;
911 static int scanner_popany(lua_State * L)
913 if (scanner_popanything(L))
914 return 1;
915 lua_pushnil(L);
916 return 1;
919 static const luaL_Reg scannerlib_meta[] = {
920 {0, 0}
923 static const struct luaL_Reg scannerlib_m[] = {
924 {"done", scanner_done},
925 {"popNumber", scanner_popnumber},
926 {"popName", scanner_popname},
927 {"popString", scanner_popstring},
928 {"popArray", scanner_poparray},
929 {"popDict", scanner_popdictionary},
930 {"popBool", scanner_popboolean},
931 {"pop", scanner_popany},
932 {NULL, NULL} /* sentinel */
936 static const luaL_Reg scannerlib[] = {
937 {"scan", scanner_scan},
938 {NULL, NULL}
941 LUALIB_API int luaopen_pdfscanner(lua_State * L)
943 luaL_newmetatable(L, SCANNER);
944 luaL_openlib(L, 0, scannerlib_meta, 0);
945 lua_pushvalue(L, -1);
946 lua_setfield(L, -2, "__index");
947 luaL_register(L, NULL, scannerlib_m);
948 luaL_register(L, "pdfscanner", scannerlib);
949 return 1;