this is a awk based code generator. Very primitive at the moment, but
authorAndrew Tridgell <tridge@samba.org>
Fri, 12 May 2000 14:35:13 +0000 (14:35 +0000)
committerAndrew Tridgell <tridge@samba.org>
Fri, 12 May 2000 14:35:13 +0000 (14:35 +0000)
it was sufficient to generate info level 6 of the add printer driver
for spoolss

It has two capabilities:

1) generate the header and C code for parsing a structure, given a
   *.struct file that describes the structure. Evetually I hope to
   make *.struct compatible with MIDL.

2) it provides a harness that can read a binary data file from
   prs_dump() which contains real data from a client and display the
   parse of it from the output of the awk parser. This allows you to
   "play" with the structure definition until it comes out right, it
   takes just a few mimutes of playing with the .struct file to work
   out the right layout.

all this is very primitive right now. I hope next to completely
replace the spoolss parser with a single .struct file that describes
all the structures, and auto-generates working code. That will require
quite a bit more work.

source/aparser/Makefile [new file with mode: 0644]
source/aparser/parser.awk [new file with mode: 0644]
source/aparser/parser.c [new file with mode: 0644]
source/aparser/parser.h [new file with mode: 0644]
source/aparser/test.struct [new file with mode: 0644]
source/aparser/vluke.c [new file with mode: 0644]

diff --git a/source/aparser/Makefile b/source/aparser/Makefile
new file mode 100644 (file)
index 0000000..e9ff8ad
--- /dev/null
@@ -0,0 +1,20 @@
+CFLAGS=-Wall -g
+CC=gcc
+
+%.h : %.struct
+       awk -f parser.awk < $*.struct > $*.h
+
+OBJ = harness.o parser.o
+
+all: test.h harness
+
+test.h : test.struct
+
+harness: test.h $(OBJ) 
+       $(CC) $(CFLAGS) -o harness $(OBJ)
+
+clean:
+       rm -f *.o test.h
+
+test: harness
+       ./harness test.dat > test.out
diff --git a/source/aparser/parser.awk b/source/aparser/parser.awk
new file mode 100644 (file)
index 0000000..a32d4b7
--- /dev/null
@@ -0,0 +1,200 @@
+function add_elem(type, elem)
+{
+   types[num_elems] = type;
+   elems[num_elems] = elem;
+   num_elems++;
+}
+
+function produce_preamble() {
+       printf("#define TEST_STRUCT %s\n", struct_name);
+       printf("#define TEST_FUNC %s\n", func_name);
+       printf("#define TEST_NAME \"%s\"\n", func_name);
+       printf("\n\n");
+}
+
+function produce_header() {
+        printf("\n/* %s structure */\n", struct_name);
+       printf("typedef struct {\n");
+       for (i=0;i<num_elems;i++) {
+               if (types[i] == "UNISTR2") {
+                       printf("\tuint32 %s_ptr;\n", elems[i]);
+               } else if (types[i] == "BUFFER5") {
+                       printf("\tuint32 %s_len;\n", elems[i]);
+                       printf("\tuint32 %s_ptr;\n", elems[i]);
+               } else {
+                       printf("\t%s\t%s;\n", types[i], elems[i]);
+               }
+       }
+       for (i=0;i<num_elems;i++) {
+               if (types[i] == "UNISTR2" || 
+                   types[i] == "BUFFER5") {
+                       printf("\t%s\t%s;\n", types[i], elems[i]);
+               }
+       }
+       printf("} %s;\n\n", struct_name);
+}
+
+
+function parse_structs() {
+        printf("\n\t/* parse the structures in the packet */\n\n");
+       for (i=0;i<num_elems;i++) {
+               if (types[i] == "UNISTR2") {
+                       io_unistr2(elems[i]);
+               }
+               if (types[i] == "BUFFER5") {
+                       io_buffer5(elems[i]);
+               }
+       }
+}
+
+function io_unistr2(elem) {
+       printf("\
+       if(!smb_io_unistr2(\"%s\", &il->%s, il->%s_ptr, ps, depth))\n\
+               return False;\n\
+       if(!prs_align(ps))\n\
+               return False;\n\
+", elem, elem, elem);
+}
+
+function io_buffer5(elem) {
+       printf("\
+        if (il->%s_ptr) {\n\
+       if(!smb_io_buffer5(\"%s\", &il->%s, ps, depth))\n\
+               return False;\n\
+       if(!prs_align(ps))\n\
+               return False;\n\
+        }\n\
+", elem, elem, elem);
+}
+
+function start_struct(name) {
+       num_elems=0;
+       struct_name=toupper(module"_"name);
+       func_name=tolower(module"_io_"name);
+}
+
+function parse_elems() {
+        printf("\n\t/* parse the main elements the packet */\n\n");
+       for (i=0;i<num_elems;i++) {
+               if (types[i] == "uint32") {
+                       uint32_parser(elems[i]);
+               } 
+               if (types[i] == "UINT64_S") {
+                       uint64_parser(elems[i]);
+               } 
+               if (types[i] == "UNISTR2") {
+                       unistr2_parser(elems[i]);
+               } 
+               if (types[i] == "BUFFER5") {
+                       buffer5_parser(elems[i]);
+               } 
+               if (types[i] == "NTTIME") {
+                       nttime_parser(elems[i]);
+               } 
+       }
+}
+
+function end_struct() {
+       produce_preamble();
+       produce_header();
+       func_header(func_name, struct_name);
+       parse_elems();
+       parse_structs();
+       func_footer();
+}
+
+
+
+function func_footer() {
+       printf("\n\
+\n\
+       return True;\n\
+}\n");
+}
+
+function func_header(func_name, struct_name)
+{
+       printf("\
+/*******************************************************************\n\
+parse a %s structure\n\
+********************************************************************/  \n\
+BOOL %s(char *desc, %s **q_u, \n\
+                                          prs_struct *ps, int depth)\n\
+{      \n\
+       %s *il;\n\
+       \n\
+       prs_debug(ps, depth, desc, \"%s\");\n\
+       depth++;\n\
+               \n\
+       /* reading */\n\
+       if (UNMARSHALLING(ps)) {\n\
+               il=(%s *)malloc(sizeof(%s));\n\
+               if(il == NULL)\n\
+                       return False;\n\
+               ZERO_STRUCTP(il);\n\
+               *q_u=il;\n\
+       }\n\
+       else {\n\
+               il=*q_u;\n\
+       }\n\
+       \n\
+       if(!prs_align(ps))\n\
+               return False;\n\
+\n\
+", struct_name, func_name, struct_name, struct_name, func_name, struct_name, struct_name);
+}
+
+function uint32_parser(elem) {
+       printf("\
+       if(!prs_uint32(\"%s\", ps, depth, &il->%s))\n\
+               return False;\n\
+", elem, elem);
+}
+
+function unistr2_parser(elem) {
+       printf("\
+       if(!prs_uint32(\"%s_ptr\", ps, depth, &il->%s_ptr))\n\
+               return False;\n\
+", elem, elem);
+}
+
+function buffer5_parser(elem) {
+       printf("\
+       if(!prs_uint32(\"%s_len\", ps, depth, &il->%s_len))\n\
+               return False;\n\
+       if(!prs_uint32(\"%s_ptr\", ps, depth, &il->%s_ptr))\n\
+               return False;\n\
+", elem, elem, elem, elem);
+}
+
+function nttime_parser(elem) {
+       printf("\
+       if(!smb_io_time(\"%s\", &il->%s, ps, depth))\n\
+               return False;\n\
+", elem, elem);
+}
+
+function uint64_parser(elem) {
+       printf("\
+       if(!prs_uint64(\"%s\", ps, depth, &il->%s))\n\
+               return False;\n\
+", elem, elem);
+}
+
+/^module/ {
+       module=$2;
+}
+
+/^struct/ {
+       start_struct($2);
+}
+
+
+/^\}/ {
+       end_struct();
+}
+
+/uint32|UINT64_S|UNISTR2|BUFFER5|NTTIME/ {
+       split($0,a,"[ ;]*");
+       add_elem(a[2], a[3]);
+}
diff --git a/source/aparser/parser.c b/source/aparser/parser.c
new file mode 100644 (file)
index 0000000..f938c58
--- /dev/null
@@ -0,0 +1,411 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h> 
+#include <unistd.h>
+#include "parser.h"
+
+char *tab_depth(int depth)
+{
+       static pstring spaces;
+       memset(spaces, ' ', depth * 4);
+       spaces[depth * 4] = 0;
+       return spaces;
+}
+
+/****************************************************************************
+expand a pointer to be a particular size
+****************************************************************************/
+void *Realloc(void *p,size_t size)
+{
+  void *ret=NULL;
+
+  if (size == 0) {
+    if (p) free(p);
+    DEBUG(5,("Realloc asked for 0 bytes\n"));
+    return NULL;
+  }
+
+  if (!p)
+    ret = (void *)malloc(size);
+  else
+    ret = (void *)realloc(p,size);
+
+  if (!ret)
+    DEBUG(0,("Memory allocation error: failed to expand to %d bytes\n",(int)size));
+
+  return(ret);
+}
+
+/*******************************************************************
+ Attempt, if needed, to grow a data buffer.
+ Also depends on the data stream mode (io).
+ ********************************************************************/
+
+BOOL prs_grow(prs_struct *ps, uint32 extra_space)
+{
+       uint32 new_size;
+       char *new_data;
+
+       if(ps->data_offset + extra_space <= ps->buffer_size)
+               return True;
+
+       /*
+        * We cannot grow the buffer if we're not reading
+        * into the prs_struct, or if we don't own the memory.
+        */
+
+       if(UNMARSHALLING(ps) || !ps->is_dynamic) {
+               DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
+                               (unsigned int)extra_space));
+               return False;
+       }
+       
+       /*
+        * Decide how much extra space we really need.
+        */
+
+       extra_space -= (ps->buffer_size - ps->data_offset);
+       if(ps->buffer_size == 0) {
+               /*
+                * Ensure we have at least a PDU's length, or extra_space, whichever
+                * is greater.
+                */
+
+               new_size = MAX(MAX_PDU_FRAG_LEN,extra_space);
+
+               if((new_data = malloc(new_size)) == NULL) {
+                       DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
+                       return False;
+               }
+               memset(new_data, '\0', new_size );
+       } else {
+               /*
+                * If the current buffer size is bigger than the space needed, just 
+                * double it, else add extra_space.
+                */
+               new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);               
+
+               if ((new_data = Realloc(ps->data_p, new_size)) == NULL) {
+                       DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
+                               (unsigned int)new_size));
+                       return False;
+               }
+       }
+       ps->buffer_size = new_size;
+       ps->data_p = new_data;
+
+       return True;
+}
+
+
+/*******************************************************************
+ Ensure we can read/write to a given offset.
+ ********************************************************************/
+
+char *prs_mem_get(prs_struct *ps, uint32 extra_size)
+{
+       if(UNMARSHALLING(ps)) {
+               /*
+                * If reading, ensure that we can read the requested size item.
+                */
+               if (ps->data_offset + extra_size > ps->buffer_size) {
+                       DEBUG(0,("prs_mem_get: reading data of size %u would overrun buffer.\n",
+                                       (unsigned int)extra_size ));
+                       return NULL;
+               }
+       } else {
+               /*
+                * Writing - grow the buffer if needed.
+                */
+               if(!prs_grow(ps, extra_size))
+                       return False;
+       }
+       return &ps->data_p[ps->data_offset];
+}
+
+
+/*******************************************************************
+ Stream a uint32.
+ ********************************************************************/
+
+BOOL prs_uint32(char *name, prs_struct *ps, int depth, uint32 *data32)
+{
+       char *q = prs_mem_get(ps, sizeof(uint32));
+       if (q == NULL)
+               return False;
+
+       DBG_RW_IVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data32)
+       ps->data_offset += sizeof(uint32);
+
+       return True;
+}
+
+/*******************************************************************
+ Initialise a parse structure - malloc the data if requested.
+ ********************************************************************/
+
+BOOL prs_init(prs_struct *ps, uint32 size, uint8 align, BOOL io)
+{
+       ZERO_STRUCTP(ps);
+       ps->io = io;
+       ps->bigendian_data = False;
+       ps->align = align;
+       ps->is_dynamic = False;
+       ps->data_offset = 0;
+       ps->buffer_size = 0;
+       ps->data_p = NULL;
+
+       if (size != 0) {
+               ps->buffer_size = size;
+               if((ps->data_p = (char *)malloc((size_t)size)) == NULL) {
+                       DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
+                       return False;
+               }
+               ps->is_dynamic = True; /* We own this memory. */
+       }
+
+       return True;
+}
+
+/*******************************************************************
+ debug output for parsing info.
+
+ XXXX side-effect of this function is to increase the debug depth XXXX
+
+ ********************************************************************/
+void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name)
+{
+       DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc));
+}
+
+/*******************************************************************
+ Align a the data_len to a multiple of align bytes - filling with
+ zeros.
+ ********************************************************************/
+
+BOOL prs_align(prs_struct *ps)
+{
+       uint32 mod = ps->data_offset & (ps->align-1);
+
+       if (ps->align != 0 && mod != 0) {
+               uint32 extra_space = (ps->align - mod);
+               if(!prs_grow(ps, extra_space))
+                       return False;
+               memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
+               ps->data_offset += extra_space;
+       }
+
+       return True;
+}
+
+/*******************************************************************
+ Reads or writes an NTTIME structure.
+********************************************************************/
+
+BOOL smb_io_time(char *desc, NTTIME *nttime, prs_struct *ps, int depth)
+{
+       if (nttime == NULL)
+               return False;
+
+       prs_debug(ps, depth, desc, "smb_io_time");
+       depth++;
+
+       if(!prs_align(ps))
+               return False;
+       
+       if(!prs_uint32("low ", ps, depth, &nttime->low)) /* low part */
+               return False;
+       if(!prs_uint32("high", ps, depth, &nttime->high)) /* high part */
+               return False;
+
+       return True;
+}
+
+
+/*******************************************************************
+ Reads or writes a UNISTR2 structure.
+ XXXX NOTE: UNISTR2 structures need NOT be null-terminated.
+   the uni_str_len member tells you how long the string is;
+   the uni_max_len member tells you how large the buffer is.
+********************************************************************/
+
+BOOL smb_io_unistr2(char *desc, UNISTR2 *uni2, uint32 buffer, prs_struct *ps, int depth)
+{
+       if (uni2 == NULL)
+               return False;
+
+       if (buffer) {
+
+               prs_debug(ps, depth, desc, "smb_io_unistr2");
+               depth++;
+
+               if(!prs_align(ps))
+                       return False;
+               
+               if(!prs_uint32("uni_max_len", ps, depth, &uni2->uni_max_len))
+                       return False;
+               if(!prs_uint32("undoc      ", ps, depth, &uni2->undoc))
+                       return False;
+               if(!prs_uint32("uni_str_len", ps, depth, &uni2->uni_str_len))
+                       return False;
+
+               /* oops! XXXX maybe issue a warning that this is happening... */
+               if (uni2->uni_max_len > MAX_UNISTRLEN)
+                       uni2->uni_max_len = MAX_UNISTRLEN;
+               if (uni2->uni_str_len > MAX_UNISTRLEN)
+                       uni2->uni_str_len = MAX_UNISTRLEN;
+
+               /* buffer advanced by indicated length of string
+                  NOT by searching for null-termination */
+               if(!prs_unistr2(True, "buffer     ", ps, depth, uni2))
+                       return False;
+
+       } else {
+
+               prs_debug(ps, depth, desc, "smb_io_unistr2 - NULL");
+               depth++;
+               memset((char *)uni2, '\0', sizeof(*uni2));
+
+       }
+
+       return True;
+}
+
+/******************************************************************
+ Stream a unicode string, length/buffer specified separately,
+ in uint16 chars. We use DBG_RW_PCVAL, not DBG_RW_PSVAL here
+ as the unicode string is already in little-endian format.
+ ********************************************************************/
+
+BOOL prs_unistr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNISTR2 *str)
+{
+       char *p = (char *)str->buffer;
+       char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
+       if (q == NULL)
+               return False;
+
+       /* If we're using big-endian, reverse to get little-endian. */
+       if(ps->bigendian_data)
+               DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->uni_str_len)
+       else
+               DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->uni_str_len * 2)
+       ps->data_offset += (str->uni_str_len * sizeof(uint16));
+
+       return True;
+}
+
+void print_asc(int level, unsigned char *buf,int len)
+{
+       int i;
+       for (i=0;i<len;i++)
+               DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.'));
+}
+
+/*******************************************************************
+ read from a socket into memory.
+ ********************************************************************/
+BOOL prs_read(prs_struct *ps, int fd, size_t len, int timeout)
+{
+       BOOL ok;
+       size_t prev_size = ps->buffer_size;
+       if (!prs_grow(ps, len))
+       {
+               return False;
+       }
+
+       if (timeout > 0)
+       {
+               ok = (read(fd, &ps->data_p[prev_size], len) == len);
+       }
+       else 
+       {
+               ok = (read(fd, &ps->data_p[prev_size], len) == len);
+       }
+       return ok;
+}
+
+void dump_data(int level,char *buf1,int len)
+{
+  unsigned char *buf = (unsigned char *)buf1;
+  int i=0;
+  if (len<=0) return;
+
+  DEBUG(level,("[%03X] ",i));
+  for (i=0;i<len;) {
+    DEBUG(level,("%02X ",(int)buf[i]));
+    i++;
+    if (i%8 == 0) DEBUG(level,(" "));
+    if (i%16 == 0) {      
+      print_asc(level,&buf[i-16],8); DEBUG(level,(" "));
+      print_asc(level,&buf[i-8],8); DEBUG(level,("\n"));
+      if (i<len) DEBUG(level,("[%03X] ",i));
+    }
+  }
+  if (i%16) {
+    int n;
+
+    n = 16 - (i%16);
+    DEBUG(level,(" "));
+    if (n>8) DEBUG(level,(" "));
+    while (n--) DEBUG(level,("   "));
+
+    n = MIN(8,i%16);
+    print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" "));
+    n = (i%16) - n;
+    if (n>0) print_asc(level,&buf[i-n],n); 
+    DEBUG(level,("\n"));    
+  }
+}
+
+/*******************************************************************
+ Stream a uint64_struct
+ ********************************************************************/
+BOOL prs_uint64(char *desc, prs_struct *ps, int depth, UINT64_S *data64)
+{
+       prs_debug(ps, depth, desc, "prs_uint64");
+       return prs_uint32("low", ps, depth+1, &data64->low) &&
+               prs_uint32("high", ps, depth+1, &data64->high);
+}
+
+
+
+/*******************************************************************
+reads or writes a BUFFER5 structure.
+the buf_len member tells you how large the buffer is.
+********************************************************************/
+BOOL smb_io_buffer5(char *desc, BUFFER5 *buf5, prs_struct *ps, int depth)
+{
+       prs_debug(ps, depth, desc, "smb_io_buffer5");
+       depth++;
+
+       if (buf5 == NULL) return False;
+
+       prs_align(ps);
+       prs_uint32("buf_len", ps, depth, &(buf5->buf_len));
+
+       /* reading: alloc the buffer first */
+       if ( ps->io )
+       {
+               buf5->buffer=(uint16 *)malloc( sizeof(uint16)*buf5->buf_len );
+       }
+       
+       prs_uint16s(True, "buffer", ps, depth, buf5->buffer, buf5->buf_len);
+
+       return True;
+}
+
+/******************************************************************
+ Stream an array of uint16s. Length is number of uint16s.
+ ********************************************************************/
+
+BOOL prs_uint16s(BOOL charmode, char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
+{
+       char *q = prs_mem_get(ps, len * sizeof(uint16));
+       if (q == NULL)
+               return False;
+
+       DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, data16s, len)
+       ps->data_offset += (len * sizeof(uint16));
+
+       return True;
+}
diff --git a/source/aparser/parser.h b/source/aparser/parser.h
new file mode 100644 (file)
index 0000000..196aa6b
--- /dev/null
@@ -0,0 +1,98 @@
+#include <ctype.h>
+#include "../include/byteorder.h"
+
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+/* Maximum PDU fragment size. */
+#define MAX_PDU_FRAG_LEN 0x1630
+
+#define DEBUG(lvl, str) printf str;
+
+#define MARSHALL 0
+#define UNMARSHALL 1
+
+#define MARSHALLING(ps) (!(ps)->io)
+#define UNMARSHALLING(ps) ((ps)->io)
+
+typedef int BOOL;
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned uint32;
+
+#define False 0
+#define True 1
+
+typedef char pstring[1024];
+
+/* zero a structure given a pointer to the structure */
+#define ZERO_STRUCTP(x) { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); }
+
+typedef struct {
+       uint32 low;
+       uint32 high;
+} UINT64_S;
+
+typedef struct 
+{
+  uint32 low;
+  uint32 high;
+} NTTIME;
+
+#define MAX_UNISTRLEN 256
+#define MAX_STRINGLEN 256
+#define MAX_BUFFERLEN 512
+
+/* UNISTR2 - unicode string size (in uint16 unicode chars) and buffer */
+typedef struct unistr2_info
+{
+  uint32 uni_max_len;
+  uint32 undoc;
+  uint32 uni_str_len;
+  /* unicode characters. ***MUST*** be little-endian. **NOT** necessarily null-terminated */
+  uint16 buffer[MAX_UNISTRLEN];
+
+} UNISTR2;
+
+/* BUFFER5 */
+typedef struct buffer5_info
+{
+  uint32 buf_len;
+  uint16 *buffer; /* data */
+} BUFFER5;
+
+typedef struct _prs_struct 
+{
+       BOOL io; /* parsing in or out of data stream */
+       /* 
+        * If the (incoming) data is big-endian. On output we are
+        * always little-endian.
+        */ 
+       BOOL bigendian_data;
+       uint8 align; /* data alignment */
+       BOOL is_dynamic; /* Do we own this memory or not ? */
+       uint32 data_offset; /* Current working offset into data. */
+       uint32 buffer_size; /* Current size of the buffer. */
+       char *data_p; /* The buffer itself. */
+} prs_struct;
+
+
+char *prs_mem_get(prs_struct *ps, uint32 extra_size);
+BOOL prs_uint32(char *name, prs_struct *ps, int depth, uint32 *data32);
+BOOL prs_init(prs_struct *ps, uint32 size, uint8 align, BOOL io);
+void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name);
+BOOL prs_align(prs_struct *ps);
+BOOL smb_io_time(char *desc, NTTIME *nttime, prs_struct *ps, int depth);
+BOOL smb_io_unistr2(char *desc, UNISTR2 *uni2, uint32 buffer, prs_struct *ps, int depth);
+BOOL prs_unistr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNISTR2 *str);
+void print_asc(int level, unsigned char *buf,int len);
+BOOL prs_read(prs_struct *ps, int fd, size_t len, int timeout);
+void dump_data(int level,char *buf1,int len);
+BOOL prs_uint64(char *name, prs_struct *ps, int depth, UINT64_S *data64);
+BOOL smb_io_buffer5(char *desc, BUFFER5 *buf5, prs_struct *ps, int depth);
+BOOL prs_uint16s(BOOL charmode, char *name, prs_struct *ps, int depth, uint16 *data16s, int len);
+
diff --git a/source/aparser/test.struct b/source/aparser/test.struct
new file mode 100644 (file)
index 0000000..517197b
--- /dev/null
@@ -0,0 +1,23 @@
+module spool
+struct PRINTER_DRIVER_INFO_LEVEL_6 {
+  uint32   dummy1; 
+  uint32   version; 
+  UNISTR2  name;       
+  UNISTR2  environment;
+  UNISTR2  driverpath;
+  UNISTR2  datafile;
+  UNISTR2  configfile;
+  UNISTR2  helpfile;
+  UNISTR2  monitorname;
+  UNISTR2  defaultdatatype;
+  BUFFER5  dependentfiles;
+  BUFFER5  previousnames;
+  NTTIME   driverdate; 
+  UINT64_S driverversion; 
+  uint32   dummy4;
+  UNISTR2  mfgname; 
+  UNISTR2  oemurl; 
+  UNISTR2  hardwareid; 
+  UNISTR2  provider; 
+};
+
diff --git a/source/aparser/vluke.c b/source/aparser/vluke.c
new file mode 100644 (file)
index 0000000..5e14301
--- /dev/null
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include "parser.h"
+#include "test.h"
+
+int main(int argc, char *argv[])
+{
+       BOOL ret;
+       TEST_STRUCT *q_u;
+       char *desc = TEST_NAME;
+       char *fname = argv[1];
+       int fd; 
+       struct stat st;
+       prs_struct ps;
+
+       if (argc < 2) {
+               printf("usage: harness <file>\n");
+               exit(1);
+       }
+
+       fd = open(fname,O_RDONLY);
+       fstat(fd, &st);
+
+       prs_init(&ps, 0, 4, MARSHALL);
+       ps.is_dynamic=True;
+       prs_read(&ps, fd, st.st_size, 0);
+       dump_data(0, ps.data_p, ps.buffer_size);
+       ps.data_offset = 0;
+       ps.io = UNMARSHALL;
+       ret = TEST_FUNC(desc, &q_u, &ps, 1);
+       printf("ret=%d\n", ret);
+       return !ret;
+}