This provides a recursive-descent parser for the grammar of sections, as given at: http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html
The actual manifest parsing has still to be done. Signed-off-by: Vegard Nossum <vegard.nos...@gmail.com> --- Makefile | 1 + include/vm/jar.h | 6 + vm/jar.c | 359 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vm/jato.c | 9 ++ 4 files changed, 375 insertions(+), 0 deletions(-) create mode 100644 include/vm/jar.h create mode 100644 vm/jar.c diff --git a/Makefile b/Makefile index 08cebfe..e915812 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ VM_OBJS = \ vm/field.o \ vm/guard-page.o \ vm/itable.o \ + vm/jar.o \ vm/jato.o \ vm/method.o \ vm/natives.o \ diff --git a/include/vm/jar.h b/include/vm/jar.h new file mode 100644 index 0000000..51f8541 --- /dev/null +++ b/include/vm/jar.h @@ -0,0 +1,6 @@ +#ifndef _VM_JAR_H +#define _VM_JAR_H + +int vm_jar_open(const char *filename); + +#endif diff --git a/vm/jar.c b/vm/jar.c new file mode 100644 index 0000000..42ecafe --- /dev/null +++ b/vm/jar.c @@ -0,0 +1,359 @@ +#include <ctype.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <zip.h> + +#include "lib/list.h" +#include "lib/string.h" +#include "vm/jar.h" + +struct parse_buffer { + const char *data; + unsigned int i; +}; + +/* The following is an implementation of the Jar file format as specified in: + * http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html */ + +struct jar_section { + struct list_head headers; +}; + +struct jar_header { + char *name; + char *value; + + struct list_head node; +}; + +struct jar_section *jar_section_alloc(void); +void jar_section_free(struct jar_section *js); + +static bool parse_section(struct parse_buffer *b, + struct jar_section **section_result); +static bool parse_nonempty_section(struct parse_buffer *b, + struct jar_section **section_result); +static bool parse_newline(struct parse_buffer *b); +static bool parse_header(struct parse_buffer *b, + struct jar_header **header_result); +static bool parse_name(struct parse_buffer *b, char **name_result); +static bool parse_value(struct parse_buffer *b, char **value_result); +static bool parse_continuation(struct parse_buffer *b, + char **continuation_result); +static bool parse_alphanum(struct parse_buffer *b, char *alphanum_result); +static bool parse_headerchar(struct parse_buffer *b, char *headerchar_result); +static bool parse_otherchar(struct parse_buffer *b, char *otherchar_result); + +struct jar_section *jar_section_alloc(void) +{ + struct jar_section *js = malloc(sizeof *js); + INIT_LIST_HEAD(&js->headers); + + return js; +} + +void jar_section_free(struct jar_section *js) +{ + struct jar_header *header, *tmp_header; + + list_for_each_entry_safe(header, tmp_header, &js->headers, node) + free(header); + + free(js); +} + +static bool parse_section(struct parse_buffer *b, + struct jar_section **section_result) +{ + struct jar_section *section = jar_section_alloc(); + + struct jar_header *header; + while (parse_header(b, &header)) + list_add_tail(&header->node, §ion->headers); + + if (!parse_newline(b)) + goto out_free_section; + + while (parse_newline(b)) + ; + + *section_result = section; + return true; + +out_free_section: + jar_section_free(section); + return false; +} + +static bool parse_nonempty_section(struct parse_buffer *b, + struct jar_section **section_result) +{ + struct jar_header *header; + if (!parse_header(b, &header)) + return false; + + struct jar_section *section = jar_section_alloc(); + + while (parse_header(b, &header)) + list_add_tail(&header->node, §ion->headers); + + if (!parse_newline(b)) + goto out_free_section; + + while (parse_newline(b)) + ; + + *section_result = section; + return true; + +out_free_section: + jar_section_free(section); + return false; +} + +static bool parse_newline(struct parse_buffer *b) +{ + if (b->data[b->i] == '\r') { + ++b->i; + + if (b->data[b->i] == '\n') + ++b->i; + + return true; + } + + if (b->data[b->i] == '\n') { + ++b->i; + + return true; + } + + return false; +} + +static bool parse_header(struct parse_buffer *b, + struct jar_header **header_result) +{ + char *name; + if (!parse_name(b, &name)) + return false; + + if (b->data[b->i] != ':') + goto out_free_name; + + ++b->i; + + char *value; + if (!parse_value(b, &value)) + goto out_free_name; + + struct jar_header *header = malloc(sizeof *header); + header->name = name; + header->value = value; + *header_result = header; + + return true; + +out_free_name: + free(name); + return false; +} + +static bool parse_name(struct parse_buffer *b, char **name_result) +{ + char alphanum; + if (!parse_alphanum(b, &alphanum)) + return false; + + struct string *name = alloc_str(); + + str_append(name, "%c", alphanum); + + char headerchar; + while (parse_headerchar(b, &headerchar)) + str_append(name, "%c", headerchar); + + *name_result = strdup(name->value); + free_str(name); + return true; +} + +static bool parse_value(struct parse_buffer *b, char **value_result) +{ + if (b->data[b->i] != ' ') + return false; + + struct string *value = alloc_str(); + + char otherchar; + while (parse_otherchar(b, &otherchar)) + str_append(value, "%c", otherchar); + + if (!parse_newline(b)) + goto out_free_value; + + char *continuation; + while (parse_continuation(b, &continuation)) + str_append(value, "%s", continuation); + + *value_result = strdup(value->value); + free_str(value); + return true; + +out_free_value: + free_str(value); + return false; +} + +static bool parse_continuation(struct parse_buffer *b, + char **continuation_result) +{ + if (b->data[b->i] != ' ') + return false; + + struct string *continuation = alloc_str(); + + char otherchar; + while (parse_otherchar(b, &otherchar)) + str_append(continuation, "%c", otherchar); + + if (!parse_newline(b)) + goto out_free_continuation; + + *continuation_result = strdup(continuation->value); + free_str(continuation); + return true; + +out_free_continuation: + free_str(continuation); + return false; +} + +static bool parse_alphanum(struct parse_buffer *b, char *alphanum_result) +{ + char c = b->data[b->i]; + + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9')) + { + *alphanum_result = c; + ++b->i; + return true; + } + + return false; +} + +static bool parse_headerchar(struct parse_buffer *b, char *headerchar_result) +{ + if (parse_alphanum(b, headerchar_result)) + return true; + + char ch = b->data[b->i]; + if (ch == '-' || ch == '_') { + *headerchar_result = ch; + ++b->i; + return true; + } + + return false; +} + +static bool parse_otherchar(struct parse_buffer *b, char *otherchar_result) +{ + char c = b->data[b->i]; + + if (c == '\0' || c == '\r' || c == '\n') + return false; + + *otherchar_result = c; + ++b->i; + return true; +} + +static int read_manifest(struct zip *zip) +{ + int zip_file_index; + struct zip_stat zip_stat; + struct zip_file *zip_file; + uint8_t *zip_file_buf; + + zip_file_index = zip_name_locate(zip, "META-INF/MANIFEST.MF", 0); + if (zip_file_index == -1) { + NOT_IMPLEMENTED; + return -ENOENT; + } + + if (zip_stat_index(zip, zip_file_index, 0, &zip_stat) == -1) { + NOT_IMPLEMENTED; + return -EIO; + } + + zip_file_buf = malloc(zip_stat.size); + if (!zip_file_buf) { + NOT_IMPLEMENTED; + return -ENOMEM; + } + + zip_file = zip_fopen_index(zip, zip_file_index, 0); + if (!zip_file) { + NOT_IMPLEMENTED; + return -EIO; + } + + for (int offset = 0; offset != zip_stat.size;) { + int ret; + + ret = zip_fread(zip_file, + zip_file_buf + offset, zip_stat.size - offset); + if (ret == -1) { + NOT_IMPLEMENTED; + return -EIO; + } + + offset += ret; + } + + zip_fclose(zip_file); + + struct parse_buffer pb; + pb.data = (char *) zip_file_buf; + pb.i = 0; + + struct jar_section *section; + if (!parse_nonempty_section(&pb, §ion)) { + NOT_IMPLEMENTED; + //printf("parse error, byte offset %d. oops\n", pb.i); + return -EINVAL; + } + + /* This is here just to shut GCC up. */ + if (0 && !parse_section(&pb, §ion)) { + } + + return 0; +} + +int vm_jar_open(const char *filename) +{ + int zip_error; + struct zip *zip; + int err; + + zip = zip_open(filename, 0, &zip_error); + if (!zip) { + NOT_IMPLEMENTED; + return -1; + } + + err = read_manifest(zip); + if (err) + return err; + + return 0; +} diff --git a/vm/jato.c b/vm/jato.c index 081475c..976193a 100644 --- a/vm/jato.c +++ b/vm/jato.c @@ -56,6 +56,7 @@ #include "vm/fault-inject.h" #include "vm/preload.h" #include "vm/itable.h" +#include "vm/jar.h" #include "vm/jni.h" #include "vm/method.h" #include "vm/natives.h" @@ -418,6 +419,14 @@ main(int argc, char *argv[]) if (classloader_add_to_classpath(argv[i])) NOT_IMPLEMENTED; + } else if (!strcmp(argv[i], "-jar")) { + if (++i >= argc) { + NOT_IMPLEMENTED; + break; + } + + if (vm_jar_open(argv[i])) + NOT_IMPLEMENTED; } else if (!strcmp(argv[i], "-Xtrace:asm")) { opt_trace_method = true; opt_trace_machine_code = true; -- 1.6.0.4 ------------------------------------------------------------------------------ Enter the BlackBerry Developer Challenge This is your chance to win up to $100,000 in prizes! For a limited time, vendors submitting new applications to BlackBerry App World(TM) will have the opportunity to enter the BlackBerry Developer Challenge. See full prize details at: http://p.sf.net/sfu/Challenge _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel