From d520514a8762e69d4d89183989dd9370e14cd49f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 21 Feb 2011 16:05:28 -0700 Subject: [PATCH] add support for Class-Path manifest attribute This attribute, found in some JAR manifests, indicates additional JARs and/or directories to append to the classpath. Tomcat in particular uses it. --- src/finder.cpp | 170 +++++++++++++++++++++++++++++++++++------------- src/finder.h | 16 +++++ src/main.cpp | 16 ----- src/tokenizer.h | 15 +++-- 4 files changed, 152 insertions(+), 65 deletions(-) diff --git a/src/finder.cpp b/src/finder.cpp index b0e25ef82a..2199dd5207 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -632,59 +632,139 @@ class BuiltinElement: public JarElement { const char* libraryName; }; +void +add(Element** first, Element** last, Element* e) +{ + if (*last) { + (*last)->next = e; + } else { + *first = e; + } + *last = e; +} + +unsigned +baseName(const char* name, char fileSeparator) +{ + const char* p = name; + const char* last = 0; + while (*p) { + if (*p == fileSeparator) { + last = p; + } + ++p; + } + + return last ? (last + 1) - name : 0; +} + +void +add(System* s, Element** first, Element** last, Allocator* allocator, + const char* name, unsigned nameLength, const char* bootLibrary); + +void +addJar(System* s, Element** first, Element** last, Allocator* allocator, + const char* name, const char* bootLibrary) +{ + if (DebugFind) { + fprintf(stderr, "add jar %s\n", name); + } + + JarElement* e = new (allocator->allocate(sizeof(JarElement))) + JarElement(s, allocator, name); + + add(first, last, e); + + System::Region* region = e->find("META-INF/MANIFEST.MF"); + if (region) { + unsigned start = 0; + unsigned length; + while (readLine(region->start(), region->length(), &start, &length)) { + const unsigned PrefixLength = 12; + if (strncmp("Class-Path: ", reinterpret_cast + (region->start() + start), PrefixLength) == 0) + { + for (Tokenizer t(reinterpret_cast + (region->start() + start + PrefixLength), + length - PrefixLength, ' '); + t.hasMore();) + { + Tokenizer::Token token(t.next()); + + unsigned base = baseName(name, s->fileSeparator()); + + RUNTIME_ARRAY(char, n, base + token.length + 1); + memcpy(RUNTIME_ARRAY_BODY(n), name, base); + memcpy(RUNTIME_ARRAY_BODY(n) + base, token.s, token.length); + RUNTIME_ARRAY_BODY(n)[base + token.length] = 0; + + add(s, first, last, allocator, RUNTIME_ARRAY_BODY(n), + base + token.length, bootLibrary); + } + } + start += length; + } + + region->dispose(); + } +} + +void +add(System* s, Element** first, Element** last, Allocator* allocator, + const char* token, unsigned tokenLength, const char* bootLibrary) +{ + if (*token == '[' and token[tokenLength - 1] == ']') { + char* name = static_cast(allocator->allocate(tokenLength - 1)); + memcpy(name, token + 1, tokenLength - 1); + name[tokenLength - 2] = 0; + + if (DebugFind) { + fprintf(stderr, "add builtin %s\n", name); + } + + add(first, last, new (allocator->allocate(sizeof(BuiltinElement))) + BuiltinElement(s, allocator, name, bootLibrary)); + } else { + char* name = static_cast(allocator->allocate(tokenLength + 1)); + memcpy(name, token, tokenLength); + name[tokenLength] = 0; + + unsigned length; + switch (s->stat(name, &length)) { + case System::TypeFile: { + addJar(s, first, last, allocator, name, bootLibrary); + } break; + + case System::TypeDirectory: { + if (DebugFind) { + fprintf(stderr, "add directory %s\n", name); + } + + add(first, last, new (allocator->allocate(sizeof(DirectoryElement))) + DirectoryElement(s, allocator, name)); + } break; + + default: { + if (DebugFind) { + fprintf(stderr, "ignore nonexistent %s\n", name); + } + + allocator->free(name, strlen(name) + 1); + } break; + } + } +} + Element* parsePath(System* s, Allocator* allocator, const char* path, const char* bootLibrary) { Element* first = 0; - Element* prev = 0; + Element* last = 0; for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) { Tokenizer::Token token(t.next()); - Element* e; - if (*token.s == '[' and token.s[token.length - 1] == ']') { - char* name = static_cast(allocator->allocate(token.length - 1)); - memcpy(name, token.s + 1, token.length - 1); - name[token.length - 2] = 0; - - e = new (allocator->allocate(sizeof(BuiltinElement))) - BuiltinElement(s, allocator, name, bootLibrary); - } else { - char* name = static_cast(allocator->allocate(token.length + 1)); - memcpy(name, token.s, token.length); - name[token.length] = 0; - - unsigned length; - switch (s->stat(name, &length)) { - case System::TypeFile: { - e = new (allocator->allocate(sizeof(JarElement))) - JarElement(s, allocator, name); - } break; - - case System::TypeDirectory: { - e = new (allocator->allocate(sizeof(DirectoryElement))) - DirectoryElement(s, allocator, name); - } break; - - default: { - allocator->free(name, strlen(name) + 1); - e = 0; - } break; - } - } - - if (DebugFind) { - fprintf(stderr, "add element %.*s %p\n", token.length, token.s, e); - } - - if (e) { - if (prev) { - prev->next = e; - } else { - first = e; - } - prev = e; - } + add(s, &first, &last, allocator, token.s, token.length, bootLibrary); } return first; diff --git a/src/finder.h b/src/finder.h index 203abb49e3..7546fb8b9c 100644 --- a/src/finder.h +++ b/src/finder.h @@ -17,6 +17,22 @@ namespace vm { +inline bool +readLine(const uint8_t* base, unsigned total, unsigned* start, + unsigned* length) +{ + const uint8_t* p = base + *start; + const uint8_t* end = base + total; + while (p != end and (*p == '\n' or *p == '\r')) ++ p; + + *start = p - base; + while (p != end and not (*p == '\n' or *p == '\r')) ++ p; + + *length = (p - base) - *start; + + return *length != 0; +} + class Finder { public: class IteratorImp { diff --git a/src/main.cpp b/src/main.cpp index 9996e6078d..d04fbe3f34 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,22 +74,6 @@ vmNativeCall(void*, void*, unsigned, unsigned) namespace { -bool -readLine(const uint8_t* base, unsigned total, unsigned* start, - unsigned* length) -{ - const uint8_t* p = base + *start; - const uint8_t* end = base + total; - while (p != end and (*p == '\n' or *p == '\r')) ++ p; - - *start = p - base; - while (p != end and not (*p == '\n' or *p == '\r')) ++ p; - - *length = (p - base) - *start; - - return *length != 0; -} - const char* mainClass(const char* jar) { diff --git a/src/tokenizer.h b/src/tokenizer.h index 4036e7d197..ac008055ff 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -23,20 +23,27 @@ class Tokenizer { unsigned length; }; - Tokenizer(const char* s, char delimiter): s(s), delimiter(delimiter) { } + Tokenizer(const char* s, char delimiter): + s(s), limit(0), delimiter(delimiter) + { } + + Tokenizer(const char* s, unsigned length, char delimiter): + s(s), limit(s + length), delimiter(delimiter) + { } bool hasMore() { - while (*s == delimiter) ++s; - return *s != 0; + while (*s == delimiter and s != limit) ++s; + return *s != 0 and s != limit; } Token next() { const char* p = s; - while (*s and *s != delimiter) ++s; + while (*s and *s != delimiter and s != limit) ++s; return Token(p, s - p); } const char* s; + const char* limit; char delimiter; };