summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/aparser/Makefile20
-rw-r--r--source3/aparser/parser.awk200
-rw-r--r--source3/aparser/parser.c411
-rw-r--r--source3/aparser/parser.h98
-rw-r--r--source3/aparser/test.struct23
-rw-r--r--source3/aparser/vluke.c38
6 files changed, 790 insertions, 0 deletions
diff --git a/source3/aparser/Makefile b/source3/aparser/Makefile
new file mode 100644
index 0000000000..e9ff8ad010
--- /dev/null
+++ b/source3/aparser/Makefile
@@ -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/source3/aparser/parser.awk b/source3/aparser/parser.awk
new file mode 100644
index 0000000000..a32d4b727b
--- /dev/null
+++ b/source3/aparser/parser.awk
@@ -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/source3/aparser/parser.c b/source3/aparser/parser.c
new file mode 100644
index 0000000000..f938c58e8b
--- /dev/null
+++ b/source3/aparser/parser.c
@@ -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/source3/aparser/parser.h b/source3/aparser/parser.h
new file mode 100644
index 0000000000..196aa6b855
--- /dev/null
+++ b/source3/aparser/parser.h
@@ -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/source3/aparser/test.struct b/source3/aparser/test.struct
new file mode 100644
index 0000000000..517197bac3
--- /dev/null
+++ b/source3/aparser/test.struct
@@ -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/source3/aparser/vluke.c b/source3/aparser/vluke.c
new file mode 100644
index 0000000000..5e143016be
--- /dev/null
+++ b/source3/aparser/vluke.c
@@ -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;
+}