summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc')
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc952
1 files changed, 952 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc b/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc
new file mode 100644
index 00000000000..2b36d106234
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc
@@ -0,0 +1,952 @@
+/* lcallbacklib.c
+
+ Copyright 2012 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+# include <stdlib.h>
+# include <stdio.h>
+# include <stdarg.h>
+# include <string.h>
+# include <assert.h>
+# include <math.h>
+
+extern "C" {
+# include <lua52/lua.h>
+# include <lua52/lauxlib.h>
+# include <lua52/lualib.h>
+}
+
+# include <poppler/poppler-config.h>
+# include <goo/GooString.h>
+# include <goo/gmem.h>
+# include <goo/gfile.h>
+# include <Object.h>
+# include <Stream.h>
+# include <Gfx.h>
+# include <Annot.h>
+# include <Array.h>
+# include <Dict.h>
+# include <XRef.h>
+# include <Catalog.h>
+# include <Link.h>
+# include <Page.h>
+# include <GfxFont.h>
+# include <PDFDoc.h>
+# include <GlobalParams.h>
+# include <Error.h>
+
+# include <lua/luatex-api.h>
+
+static const char _svn_version[] =
+ "$Id: lpdfscannerlib.cc 4524 2012-12-20 15:38:02Z taco $ $URL: http://foundry.supelec.fr/svn/luatex/trunk/source/texk/web2c/luatexdir/lua/lpdfscannerlib.cc $";
+
+#define SCANNER "pdfscanner"
+
+#define MAXOPERANDS 1000
+
+typedef enum {
+ pdf_integer = 1,
+ pdf_real,
+ pdf_boolean,
+ pdf_name,
+ pdf_operator,
+ pdf_string,
+ pdf_startarray,
+ pdf_stoparray,
+ pdf_startdict,
+ pdf_stopdict,
+} pdf_token_type ;
+
+
+typedef struct Token {
+ pdf_token_type type;
+ double value;
+ const char *string;
+} Token;
+
+typedef struct ObjectList {
+ struct ObjectList *next;
+ Object *stream;
+} ObjectList;
+
+typedef struct scannerdata {
+ int _ininlineimage;
+ int _nextoperand;
+ Token ** _operandstack;
+ Object * _stream;
+ ObjectList * _streams;
+} scannerdata;
+
+typedef enum { ALLOC_POPPLER, ALLOC_LEPDF } alloctype;
+
+#define M_Object "Object"
+#define M_Stream "Stream"
+
+typedef struct {
+ void *d;
+ alloctype atype; // was it allocated by poppler or the lepdflib.cc?
+ void *pd; // reference to PdfDocument, or NULL
+ unsigned long pc; // counter to detect PDFDoc change
+} udstruct;
+
+static void clear_operand_stack (scannerdata *self, int from);
+static Token *_parseToken (scannerdata *self, int c);
+static void push_token (lua_State *L, scannerdata *self);
+
+void *xmalloc (size_t size)
+{
+ void *new_mem = (void *)malloc(size);
+ if (new_mem == NULL) {
+ fprintf(stderr, "fatal: memory exhausted (xmalloc of %lu bytes).\n", (unsigned long)size);
+ exit(1);
+ }
+ return new_mem;
+}
+
+void *xrealloc (void *old_ptr, size_t size)
+{
+ void *new_mem = (void *)realloc(old_ptr, size);
+ if (new_mem == NULL) {
+ fprintf(stderr,"fatal: memory exhausted (realloc of %lu bytes).\n", (unsigned long)size);
+ exit(EXIT_FAILURE);
+ }
+ return new_mem;
+}
+
+#define xreallocarray(ptr,type,size) ((type*)xrealloc(ptr,(size+1)*sizeof(type)))
+
+#define INITBUFSIZE 64
+
+#define define_buffer(a) \
+ char *a = (char *)xmalloc (INITBUFSIZE); \
+ int a##_size = INITBUFSIZE; \
+ int a##index = 0; \
+ memset (a,0,INITBUFSIZE)
+
+#define check_overflow(a, wsize) do { \
+ if (wsize >= a##_size) { \
+ int nsize = a##_size + a##_size / 4; \
+ a = (char *) xreallocarray(a, char, (unsigned) nsize); \
+ memset (a+a##_size, 0, a##_size / 4); \
+ a##_size = nsize; \
+ } \
+ } while (0)
+
+
+static scannerdata * scanner_push(lua_State * L)
+{
+ scannerdata *a = (scannerdata *)lua_newuserdata(L, sizeof(scannerdata));
+ luaL_getmetatable(L, SCANNER);
+ lua_setmetatable(L, -2);
+ return a;
+}
+
+static scannerdata *scanner_check (lua_State *L, int index)
+{
+ scannerdata *bar;
+ luaL_checktype(L, index, LUA_TUSERDATA);
+ bar = (scannerdata *)luaL_checkudata(L, index, SCANNER);
+ return bar;
+}
+
+static void free_token (Token *token)
+{
+ if (token->string) {
+ free((void *)token->string);
+ }
+ free(token);
+}
+
+static void clear_operand_stack (scannerdata *self, int from)
+{
+ int i = self->_nextoperand-1;
+ while (i>=from) {
+ if (self->_operandstack[i]) {
+ free_token(self->_operandstack[i]);
+ self->_operandstack[i] = NULL;
+ }
+ i--;
+ }
+ self->_nextoperand = from;
+}
+
+static void push_operand (scannerdata *self, Token *token)
+{
+ if (self->_nextoperand+1> MAXOPERANDS) {
+ fprintf(stderr, "out of operand stack space");
+ exit(1);
+ }
+ self->_operandstack[self->_nextoperand++] = token;
+}
+
+static Token * new_operand (pdf_token_type c)
+{
+ Token *token = (Token *)xmalloc(sizeof(Token));
+ memset (token, 0, sizeof(Token));
+ token->type = c;
+ return token;
+}
+
+static void _nextStream (scannerdata *self) {
+ self->_stream->streamClose();
+ ObjectList *rover = self->_streams;
+ self->_stream = rover->stream;
+ self->_stream->streamReset();
+ self->_streams = rover->next;
+ free(rover);
+}
+
+static int streamGetChar (scannerdata *self) {
+ int i = self->_stream->streamGetChar();
+ if (i<0 && self->_streams) {
+ _nextStream(self);
+ i = streamGetChar(self);
+ }
+ return i;
+}
+
+static int streamLookChar (scannerdata *self) {
+ int i= self->_stream->streamLookChar();
+ if (i<0 && self->_streams) {
+ _nextStream(self);
+ i = streamLookChar(self);
+ }
+ return i;
+}
+
+static Token * _parseSpace (scannerdata *self)
+{
+ return _parseToken (self,streamGetChar(self));
+}
+
+static Token * _parseString (scannerdata *self, int c)
+{
+ // local token = {type = pdf_string,value = ''}
+ define_buffer(found);
+ int level = 1;
+ while (1) {
+ c = streamGetChar(self);
+ if (c == '(') {
+ level = level + 1 ;
+ }
+ if (c == ')') {
+ level = level - 1 ;
+ if (level < 1) break;
+ }
+ if (c == '\\') {
+ int next = streamGetChar(self);
+ if (next == '(' || next == ')' || next == '\\') {
+ c = next;
+ } else if (next == '\n' || next == '\r') {
+ c = '\0';
+ } else if (next == 'n') {
+ c = '\n';
+ } else if (next == 'r') {
+ c = '\r';
+ } else if (next == 't') {
+ c = '\t';
+ } else if (next == 'b') {
+ c = '\b';
+ } else if (next == 'f') {
+ c = '\f';
+ } else if (next >= '0' && next <= '7') {
+ next = next - '0';
+ int next2 = streamLookChar(self);
+ if (next2 >= '0' && next2 <= '7') {
+ next2 = streamGetChar(self);
+ next2 = next2 - '0';
+ int next3 = streamLookChar(self);
+ if (next3 >= '0' && next3 <= '7') {
+ next3 = streamGetChar(self);
+ next3 = next3 - '0';
+ c = (next*64+next2*8+next3);
+ } else {
+ c = (next*8+next2);
+ }
+ } else {
+ c = next;
+ }
+ } else {
+ c = next;
+ }
+ }
+ check_overflow(found,foundindex);
+ if (c>=0) {
+ found[foundindex++] = c;
+ }
+ }
+ Token *token = new_operand(pdf_string);
+ token->value = foundindex;
+ token->string = found;
+ return token;
+}
+
+
+static Token * _parseNumber (scannerdata *self, int c)
+{
+ double value = 0;
+ pdf_token_type type = pdf_integer;
+ int isfraction = 0;
+ int isnegative = 0;
+ int i = 0;
+ if (c == '-') {
+ isnegative = 1;
+ c = streamGetChar(self);
+ }
+ if (c == '.') {
+ type = pdf_real;
+ isfraction = 1;
+ } else {
+ value = c - '0';
+ }
+ c = streamLookChar(self);
+ if ((c>= '0'&& c<= '9') || c == '.') {
+ c = streamGetChar(self);
+ while (1) {
+ if (c == '.') {
+ type = pdf_real;
+ isfraction = 1;
+ } else {
+ i = c - '0';
+ if (isfraction>0) {
+ value = value + (i/(pow(10.0,isfraction)));
+ isfraction = isfraction + 1;
+ } else {
+ value = (value * 10) + i;
+ }
+ }
+ c = streamLookChar(self);
+ if (! ((c>= '0' && c<= '9') || c == '.')) break ;
+ c = streamGetChar(self);
+ }
+ }
+ if (isnegative) {
+ value = -value;
+ }
+ Token *token = new_operand(type);
+ token->value = value;
+ return token;
+}
+
+
+static Token *_parseName (scannerdata *self, int c)
+{
+ define_buffer(found);
+ c = streamGetChar(self);
+ while (1) {
+ check_overflow(found,foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
+ c == '/' || c == '[' || c == '(' || c == '<') break ;
+ c = streamGetChar(self);
+ }
+ Token *token = new_operand(pdf_name);
+ token->string = found;
+ token->value = strlen(found);
+ return token;
+}
+
+#define hexdigit(c) \
+ (c>= '0' && c<= '9') ? (c - '0') : ((c>= 'A' && c<= 'F') ? (c - 'A' + 10) : (c - 'a' + 10))
+
+static Token *_parseHexstring (scannerdata *self, int c)
+{
+ int isodd = 1;
+ int hexval = 0;
+ define_buffer(found);
+ while (1) {
+ if ((c>= '0' && c<= '9') ||
+ (c>= 'A' && c<= 'F') ||
+ (c>= 'a' && c<= 'f')) {
+ if (isodd==1) {
+ int v = hexdigit(c);
+ hexval = 16 * v;
+ } else {
+ hexval += hexdigit(c);
+ check_overflow(found,foundindex);
+ found[foundindex++] = hexval;
+ }
+ isodd = (isodd==1 ? 0 : 1);
+ }
+ c = streamGetChar(self);
+ if (c == '>') break;
+ }
+ Token *token = new_operand(pdf_string);
+ token->value = foundindex;
+ token->string = found;
+ return token;
+}
+
+
+// -- this is rather horrible
+static Token *_parseInlineImage (scannerdata *self, int c)
+{
+ define_buffer(found);
+ if (c == ' ') { // first space can be ignored
+ c = streamGetChar(self);
+ }
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ while (1) {
+ c = streamLookChar(self);
+ while (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ }
+ if (c == 'E') {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if (c == 'I') {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
+ found[--foundindex] = '\0';
+ found[--foundindex] = '\0';
+ /* remove optional end-of-line */
+ if (found[foundindex-1] == '\n') {
+ found[--foundindex] = '\0';
+ }
+ if (found[foundindex-1] == '\r') {
+ found[--foundindex] = '\0';
+ }
+ break;
+ }
+ } else {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ }
+ } else {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ }
+ }
+ Token *token = new_operand(pdf_string);
+ token->value = foundindex;
+ token->string = found;
+ return token;
+}
+
+static Token *_parseOperator (scannerdata *self, int c)
+{
+ define_buffer(found);
+ while (1) {
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if ((c<0) || (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
+ c == '/' || c == '[' || c == '(' || c == '<'))
+ break ;
+ c = streamGetChar(self);
+ }
+ // print (found)
+ if (strcmp(found, "ID") == 0) {
+ self->_ininlineimage = 1;
+ }
+ if (strcmp(found,"false") == 0) {
+ Token *token = new_operand(pdf_boolean);
+ token->value = 0;
+ return token;
+ } else if (strcmp(found,"true") == 0) {
+ Token *token = new_operand(pdf_boolean);
+ token->value = 1.0;
+ return token;
+ } else {
+ Token *token = new_operand(pdf_operator);
+ token->string = found;
+ return token;
+ }
+}
+
+
+static Token * _parseComment (scannerdata *self, int c)
+{
+ do {
+ c = streamGetChar(self);
+ } while (c != '\n' && c != '\r');
+ return _parseToken(self,streamGetChar(self));
+}
+
+static Token *_parseLt (scannerdata *self, int c)
+{
+ c = streamGetChar(self);
+ if (c == '<') {
+ return new_operand(pdf_startdict);
+ } else {
+ return _parseHexstring(self,c);
+ }
+}
+
+static Token * _parseGt (scannerdata *self, int c)
+{
+ c = streamGetChar(self);
+ if (c== '>') {
+ return new_operand(pdf_stopdict);
+ } else {
+ fprintf(stderr,"stray > in stream");
+ return NULL;
+ }
+}
+
+
+static Token *_parseError (int c)
+{
+ fprintf(stderr, "stray %c [%d] in stream", c, c);
+ return NULL;
+}
+
+static Token *_parseStartarray ()
+{
+ return new_operand (pdf_startarray);
+}
+
+static Token *_parseStoparray ()
+{
+ return new_operand (pdf_stoparray);
+}
+
+
+static Token *_parseToken (scannerdata *self, int c)
+{
+ if (self->_ininlineimage==1) {
+ self->_ininlineimage = 2;
+ return _parseInlineImage(self,c);
+ } else if (self->_ininlineimage==2) {
+ self->_ininlineimage = 0;
+ Token *token = new_operand(pdf_operator);
+ token->string = strdup("EI");
+ return token;
+ }
+ if (c<0) return NULL ;
+ switch (c) {
+ case '(': return _parseString(self,c); break;
+ case ')': return _parseError(c); break;
+ case '[': return _parseStartarray(); break;
+ case ']': return _parseStoparray(); break;
+ case '/': return _parseName(self,c); break;
+ case '<': return _parseLt(self,c); break;
+ case '>': return _parseGt(self,c); break;
+ case '%': return _parseComment(self,c); break;
+ case ' ':
+ case '\r':
+ case '\n':
+ case '\t':
+ return _parseSpace(self); break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ case '.':
+ return _parseNumber(self,c); break;
+ default:
+ if (c<=127) {
+ return _parseOperator(self,c);
+ } else {
+ return _parseError(c);
+ }
+ }
+}
+
+static int scanner_scan(lua_State * L)
+{
+ Token *token;
+ scannerdata *self;
+ if (lua_gettop(L) != 3) {
+ return 0;
+ }
+ luaL_checktype(L, 2, LUA_TTABLE);
+ luaL_checktype(L, 3, LUA_TTABLE);
+ self = scanner_push(L);
+ memset(self,0,sizeof(scannerdata));
+ self->_operandstack = (Token **)xmalloc (MAXOPERANDS * sizeof (Token));
+ memset (self->_operandstack,0,(MAXOPERANDS * sizeof (Token)));
+ // 4 = self
+ if (lua_type(L,1)== LUA_TTABLE) {
+ udstruct *uin;
+ int i = 1;
+ while (1) {
+ lua_rawgeti(L,1,i);
+ if (lua_type(L,-1)== LUA_TUSERDATA) {
+ uin = (udstruct *) luaL_checkudata(L, -1, M_Object);
+ if (((Object *) uin->d)->isStream()) {
+ ObjectList *rover = self->_streams;
+ ObjectList *item = (ObjectList *)xmalloc (sizeof(ObjectList));
+ item->stream = ((Object *) uin->d);
+ item->next = NULL;
+ if (!rover) {
+ rover = item;
+ self->_streams = rover;
+ } else {
+ while (rover->next)
+ rover = rover->next;
+ rover->next = item;
+ }
+ }
+ } else { // done
+ ObjectList *rover = self->_streams;
+ self->_stream = rover->stream;
+ self->_streams = rover->next;
+ free(rover);
+ lua_pop(L,1);
+ break;
+ }
+ lua_pop(L,1);
+ i++;
+ }
+
+ } else {
+ udstruct *uin;
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ uin = (udstruct *) luaL_checkudata(L, 1, M_Object);
+ if (((Object *) uin->d)->isStream()) {
+ self->_stream = ((Object *) uin->d);
+ } else if (((Object *) uin->d)->isArray()) {
+ Array *arrayref = ((Object *) uin->d)->getArray();
+ int count = arrayref->getLength();
+ int i;
+ for (i=0;i<count;i++) {
+ Object *val = new Object();
+ arrayref->get(i, val);
+ if (val->isStream()) {
+ ObjectList *rover = self->_streams;
+ ObjectList *item = (ObjectList *)xmalloc (sizeof(ObjectList));
+ item->stream = val;
+ item->next = NULL;
+ if (!rover) {
+ rover = item;
+ self->_streams = rover;
+ } else {
+ while (rover->next)
+ rover = rover->next;
+ rover->next = item;
+ }
+ }
+ }
+ ObjectList *rover = self->_streams;
+ self->_stream = rover->stream;
+ self->_streams = rover->next;
+ }
+
+ }
+ assert (lua_gettop(L) == 4);
+ self->_stream->streamReset();
+ token = _parseToken(self,streamGetChar(self));
+ while (token) {
+ if (token->type == pdf_operator) {
+ lua_pushstring(L, token->string);
+ free_token(token);
+ lua_rawget(L,2); // operator table
+ if (lua_isfunction(L,-1)) {
+ lua_pushvalue(L,4);
+ lua_pushvalue(L,3);
+ (void)lua_call(L,2,0);
+ } else {
+ lua_pop(L,1); // nil
+ }
+ clear_operand_stack(self,0);
+ } else {
+ push_operand(self, token);
+ }
+ if (!self->_stream) {
+ break;
+ }
+ token = _parseToken(self,streamGetChar(self));
+ }
+ /* wrap up */
+ if (self->_stream) {
+ self->_stream->streamClose();
+ self->_stream = NULL;
+ }
+ clear_operand_stack(self,0);
+ free(self->_operandstack);
+ return 0;
+}
+
+static int scanner_done(lua_State * L)
+{
+ int c;
+ scannerdata *self = scanner_check(L,1);
+ while ((c=streamGetChar(self))>=0)
+ ;
+ return 0;
+}
+
+// here are the stack popping functions, and their helpers
+
+static void operandstack_backup (scannerdata *self) {
+ int i = self->_nextoperand-1;
+ int balance = 0;
+ int backupstart = 0;
+ int backupstop = self->_operandstack[i]->type;
+ if (backupstop == pdf_stopdict) {
+ backupstart = pdf_startdict;
+ } else if (backupstop == pdf_stoparray) {
+ backupstart = pdf_startarray;
+ } else {
+ return;
+ }
+ for (;i>=0;i--) {
+ if (self->_operandstack[i]->type == backupstop) {
+ balance++;
+ } else if (self->_operandstack[i]->type == backupstart) {
+ balance--;
+ }
+ if (balance==0) {
+ break;
+ }
+ }
+ self->_nextoperand = i+1;
+}
+
+static void push_array (lua_State *L, scannerdata *self)
+{
+ int balance = 1; // nesting tracking
+ int index = 1; // lua array index
+ Token *token = self->_operandstack[self->_nextoperand++];
+ lua_newtable(L);
+ while (token) {
+ if (token->type == pdf_stoparray)
+ balance --;
+ if (token->type == pdf_startarray)
+ balance ++;
+ if (!balance) {
+ break;
+ } else {
+ push_token(L,self);
+ lua_rawseti(L,-2, index++);
+ }
+ token = self->_operandstack[self->_nextoperand++];
+ }
+}
+
+
+static void push_dict (lua_State *L, scannerdata *self)
+{
+ int balance = 1; // nesting tracking
+ int needskey = 1; // toggle between lua value and lua key
+ Token *token = self->_operandstack[self->_nextoperand++];
+ lua_newtable(L);
+ while (token) {
+ if (token->type == pdf_stopdict)
+ balance --;
+ if (token->type == pdf_startdict)
+ balance ++;
+ if (!balance) {
+ break;
+ } else {
+ if (needskey) {
+ lua_pushlstring(L, token->string, token->value);
+ needskey = 0;
+ } else {
+ push_token(L,self);
+ needskey = 1;
+ lua_rawset(L,-3);
+ }
+ }
+ token = self->_operandstack[self->_nextoperand++];
+ }
+}
+
+const char *typenames[pdf_stopdict+1] =
+ { "unknown", "integer", "real", "boolean", "name", "operator",
+ "string", "array", "array", "dict", "dict" };
+
+static void push_token (lua_State *L, scannerdata *self)
+{
+ Token *token = self->_operandstack[self->_nextoperand-1];
+ lua_createtable(L,2,0);
+ lua_pushstring (L, typenames[token->type]);
+ lua_rawseti(L,-2,1);
+ if (token->type == pdf_string || token->type == pdf_name) {
+ lua_pushlstring(L, token->string, token->value);
+ } else if (token->type == pdf_real || token->type == pdf_integer) {
+ lua_pushnumber(L, token->value);
+ } else if (token->type == pdf_boolean) {
+ lua_pushboolean(L, (int)token->value);
+ } else if (token->type == pdf_startarray) {
+ push_array(L, self);
+ } else if (token->type == pdf_startdict) {
+ push_dict(L, self);
+ } else {
+ lua_pushnil(L);
+ }
+ lua_rawseti(L,-2, 2);
+}
+
+static int scanner_popsingular (lua_State * L, int token_type) {
+ int clear = 0; // how much of the operand stack needs deleting
+ scannerdata *self = scanner_check(L,1);
+ if (self->_nextoperand==0) {
+ return 0;
+ }
+ clear = self->_nextoperand-1;
+ Token *token = self->_operandstack[self->_nextoperand-1];
+ if (token ==NULL || (token->type != token_type )) {
+ return 0;
+ }
+ // the simple cases can be written out directly, but dicts and
+ // arrays are better done via the recursive function
+ if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
+ operandstack_backup(self);
+ clear = self->_nextoperand-1;
+ push_token(L, self);
+ lua_rawgeti(L,-1,2);
+ } else if (token_type == pdf_real || token_type == pdf_integer) {
+ lua_pushnumber(L, token->value);
+ } else if (token_type == pdf_boolean) {
+ lua_pushboolean(L,(int)token->value);
+ } else if (token_type == pdf_name || token_type == pdf_string) {
+ lua_pushlstring(L, token->string, token->value);
+ } else {
+ return 0;
+ }
+ clear_operand_stack(self,clear);
+ return 1;
+}
+
+static int scanner_popanything (lua_State * L) {
+ int clear = 0; // how much of the operand stack needs deleting
+ scannerdata *self = scanner_check(L,1);
+ if (self->_nextoperand==0) {
+ return 0;
+ }
+ clear = self->_nextoperand-1;
+ Token *token = self->_operandstack[self->_nextoperand-1];
+ if (token ==NULL) {
+ return 0;
+ }
+ int token_type = token->type;
+ // the simple cases can be written out directly, but dicts and
+ // arrays are better done via the recursive function
+ if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
+ operandstack_backup(self);
+ clear = self->_nextoperand-1;
+ push_token(L, self);
+ } else {
+ push_token(L, self);
+ }
+ clear_operand_stack(self,clear);
+ return 1;
+}
+
+
+static int scanner_popnumber(lua_State * L)
+{
+ if(scanner_popsingular(L,pdf_real))
+ return 1;
+ if (scanner_popsingular(L,pdf_integer))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popboolean(lua_State * L)
+{
+ if(scanner_popsingular(L,pdf_boolean))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popstring(lua_State * L)
+{
+ if (scanner_popsingular(L,pdf_string))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popname(lua_State * L)
+{
+ if (scanner_popsingular(L,pdf_name))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_poparray(lua_State * L)
+{
+ if (scanner_popsingular(L,pdf_stoparray))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popdictionary(lua_State * L)
+{
+ if (scanner_popsingular(L,pdf_stopdict))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popany(lua_State * L)
+{
+ if (scanner_popanything(L))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static const luaL_Reg scannerlib_meta[] = {
+ {0, 0}
+};
+
+static const struct luaL_Reg scannerlib_m[] = {
+ {"done", scanner_done},
+ {"popNumber", scanner_popnumber},
+ {"popName", scanner_popname},
+ {"popString", scanner_popstring},
+ {"popArray", scanner_poparray},
+ {"popDict", scanner_popdictionary},
+ {"popBool", scanner_popboolean},
+ {"pop", scanner_popany},
+ {NULL, NULL} /* sentinel */
+};
+
+
+static const luaL_Reg scannerlib[] = {
+ {"scan", scanner_scan},
+ {NULL, NULL}
+};
+
+LUALIB_API int luaopen_pdfscanner(lua_State * L)
+{
+ luaL_newmetatable(L, SCANNER);
+ luaL_openlib(L, 0, scannerlib_meta, 0);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_register(L, NULL, scannerlib_m);
+ luaL_register(L, "pdfscanner", scannerlib);
+ return 1;
+}
+