2008-02-19 18:06:52 +00:00
|
|
|
/* Copyright (c) 2008, Avian Contributors
|
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2007-09-19 16:22:19 +00:00
|
|
|
#include "zlib-custom.h"
|
2007-07-20 14:36:31 +00:00
|
|
|
#include "system.h"
|
2010-09-20 23:31:23 +00:00
|
|
|
#include "tokenizer.h"
|
2007-08-10 23:45:47 +00:00
|
|
|
#include "finder.h"
|
2007-07-20 14:36:31 +00:00
|
|
|
|
|
|
|
using namespace vm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2010-09-14 02:38:55 +00:00
|
|
|
const bool DebugFind = false;
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
const char*
|
2010-09-20 23:31:23 +00:00
|
|
|
append(System* s, const char* a, const char* b, const char* c)
|
2007-07-20 14:36:31 +00:00
|
|
|
{
|
|
|
|
unsigned al = strlen(a);
|
|
|
|
unsigned bl = strlen(b);
|
|
|
|
unsigned cl = strlen(c);
|
2008-04-13 18:15:04 +00:00
|
|
|
char* p = static_cast<char*>(allocate(s, (al + bl + cl) + 1));
|
2007-07-20 14:36:31 +00:00
|
|
|
memcpy(p, a, al);
|
|
|
|
memcpy(p + al, b, bl);
|
2007-08-10 23:45:47 +00:00
|
|
|
memcpy(p + al + bl, c, cl + 1);
|
2007-07-20 14:36:31 +00:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2007-08-27 13:46:17 +00:00
|
|
|
const char*
|
2008-04-13 18:15:04 +00:00
|
|
|
copy(System* s, const char* a)
|
2007-08-27 13:46:17 +00:00
|
|
|
{
|
|
|
|
unsigned al = strlen(a);
|
2008-04-13 18:15:04 +00:00
|
|
|
char* p = static_cast<char*>(allocate(s, al + 1));
|
2007-08-27 13:46:17 +00:00
|
|
|
memcpy(p, a, al + 1);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
bool
|
|
|
|
equal(const void* a, unsigned al, const void* b, unsigned bl)
|
|
|
|
{
|
|
|
|
if (al == bl) {
|
|
|
|
return memcmp(a, b, al) == 0;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Element {
|
|
|
|
public:
|
2008-11-21 23:20:35 +00:00
|
|
|
class Iterator {
|
|
|
|
public:
|
|
|
|
virtual const char* next(unsigned* size) = 0;
|
|
|
|
virtual void dispose() = 0;
|
|
|
|
};
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
Element(): next(0) { }
|
2008-11-11 15:20:49 +00:00
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
virtual Iterator* iterator() = 0;
|
2007-09-17 00:13:36 +00:00
|
|
|
virtual System::Region* find(const char* name) = 0;
|
|
|
|
virtual bool exists(const char* name) = 0;
|
|
|
|
virtual void dispose() = 0;
|
|
|
|
|
|
|
|
Element* next;
|
|
|
|
};
|
|
|
|
|
|
|
|
class DirectoryElement: public Element {
|
|
|
|
public:
|
2008-11-21 23:20:35 +00:00
|
|
|
class Iterator: public Element::Iterator {
|
|
|
|
public:
|
2008-11-28 04:44:04 +00:00
|
|
|
Iterator(System* s, const char* name, unsigned skip):
|
|
|
|
s(s), name(name), skip(skip), directory(0), last(0), it(0)
|
2008-11-21 23:20:35 +00:00
|
|
|
{
|
|
|
|
if (not s->success(s->open(&directory, name))) {
|
|
|
|
directory = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual const char* next(unsigned* size) {
|
2008-11-28 04:44:04 +00:00
|
|
|
if (it) {
|
|
|
|
const char* v = it->next(size);
|
|
|
|
if (v) {
|
|
|
|
return v;
|
|
|
|
} else {
|
|
|
|
it->dispose();
|
|
|
|
it = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (last) {
|
|
|
|
s->free(last);
|
|
|
|
}
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
if (directory) {
|
|
|
|
for (const char* v = directory->next(); v; v = directory->next()) {
|
|
|
|
if (v[0] != '.') {
|
2008-11-28 04:44:04 +00:00
|
|
|
last = append(s, name, "/", v);
|
|
|
|
if (s->identify(last) == System::TypeDirectory) {
|
|
|
|
it = new (allocate(s, sizeof(Iterator))) Iterator(s, last, skip);
|
|
|
|
it->name = last;
|
|
|
|
}
|
|
|
|
const char* result = last + skip;
|
|
|
|
*size = strlen(result);
|
|
|
|
return result;
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-28 04:44:04 +00:00
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
|
|
|
directory->dispose();
|
|
|
|
s->free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2008-11-28 04:44:04 +00:00
|
|
|
const char* name;
|
|
|
|
unsigned skip;
|
2008-11-21 23:20:35 +00:00
|
|
|
System::Directory* directory;
|
2008-11-28 04:44:04 +00:00
|
|
|
const char* last;
|
|
|
|
Iterator* it;
|
2008-11-21 23:20:35 +00:00
|
|
|
};
|
|
|
|
|
2008-04-13 18:15:04 +00:00
|
|
|
DirectoryElement(System* s, const char* name):
|
|
|
|
s(s), name(name)
|
2007-09-17 00:13:36 +00:00
|
|
|
{ }
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
virtual Element::Iterator* iterator() {
|
2008-11-28 04:44:04 +00:00
|
|
|
return new (allocate(s, sizeof(Iterator)))
|
|
|
|
Iterator(s, name, strlen(name) + 1);
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
virtual System::Region* find(const char* name) {
|
2008-04-13 18:15:04 +00:00
|
|
|
const char* file = append(s, this->name, "/", name);
|
2007-09-17 00:13:36 +00:00
|
|
|
System::Region* region;
|
|
|
|
System::Status status = s->map(®ion, file);
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(file);
|
2007-09-17 00:13:36 +00:00
|
|
|
|
|
|
|
if (s->success(status)) {
|
2010-09-14 02:38:55 +00:00
|
|
|
if (DebugFind) {
|
|
|
|
fprintf(stderr, "found %s in %s\n", name, this->name);
|
|
|
|
}
|
2007-09-17 00:13:36 +00:00
|
|
|
return region;
|
|
|
|
} else {
|
2010-09-20 23:31:23 +00:00
|
|
|
if (DebugFind) {
|
|
|
|
fprintf(stderr, "%s not found in %s\n", name, this->name);
|
|
|
|
}
|
2007-09-17 00:13:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool exists(const char* name) {
|
2008-04-13 18:15:04 +00:00
|
|
|
const char* file = append(s, this->name, "/", name);
|
2007-09-17 00:13:36 +00:00
|
|
|
System::FileType type = s->identify(file);
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(file);
|
2008-11-21 23:20:35 +00:00
|
|
|
return type != System::TypeDoesNotExist;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(name);
|
|
|
|
s->free(this);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
const char* name;
|
|
|
|
};
|
|
|
|
|
|
|
|
class PointerRegion: public System::Region {
|
|
|
|
public:
|
|
|
|
PointerRegion(System* s, const uint8_t* start, size_t length):
|
|
|
|
s(s),
|
|
|
|
start_(start),
|
|
|
|
length_(length)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual const uint8_t* start() {
|
|
|
|
return start_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual size_t length() {
|
|
|
|
return length_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(this);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
const uint8_t* start_;
|
|
|
|
size_t length_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class DataRegion: public System::Region {
|
|
|
|
public:
|
|
|
|
DataRegion(System* s, size_t length):
|
|
|
|
s(s),
|
|
|
|
length_(length)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual const uint8_t* start() {
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual size_t length() {
|
|
|
|
return length_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(this);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
size_t length_;
|
|
|
|
uint8_t data[0];
|
|
|
|
};
|
|
|
|
|
|
|
|
class JarIndex {
|
|
|
|
public:
|
2008-02-26 00:29:26 +00:00
|
|
|
static const unsigned LocalHeaderSize = 30;
|
|
|
|
static const unsigned HeaderSize = 46;
|
2007-09-17 00:13:36 +00:00
|
|
|
|
|
|
|
enum CompressionMethod {
|
|
|
|
Stored = 0,
|
|
|
|
Deflated = 8
|
|
|
|
};
|
|
|
|
|
|
|
|
class Node {
|
|
|
|
public:
|
|
|
|
Node(uint32_t hash, const uint8_t* entry, Node* next):
|
|
|
|
hash(hash), entry(entry), next(next)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
uint32_t hash;
|
|
|
|
const uint8_t* entry;
|
|
|
|
Node* next;
|
|
|
|
};
|
|
|
|
|
|
|
|
JarIndex(System* s, unsigned capacity):
|
|
|
|
s(s),
|
|
|
|
capacity(capacity),
|
|
|
|
position(0),
|
2008-01-13 22:05:08 +00:00
|
|
|
nodes(static_cast<Node*>(allocate(s, sizeof(Node) * capacity)))
|
2007-09-17 00:13:36 +00:00
|
|
|
{
|
|
|
|
memset(table, 0, sizeof(Node*) * capacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t get2(const uint8_t* p) {
|
|
|
|
return
|
|
|
|
(static_cast<uint16_t>(p[1]) << 8) |
|
|
|
|
(static_cast<uint16_t>(p[0]) );
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t get4(const uint8_t* p) {
|
|
|
|
return
|
|
|
|
(static_cast<uint32_t>(p[3]) << 24) |
|
|
|
|
(static_cast<uint32_t>(p[2]) << 16) |
|
|
|
|
(static_cast<uint32_t>(p[1]) << 8) |
|
|
|
|
(static_cast<uint32_t>(p[0]) );
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t signature(const uint8_t* p) {
|
|
|
|
return get4(p);
|
|
|
|
}
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
static uint16_t compressionMethod(const uint8_t* centralHeader) {
|
|
|
|
return get2(centralHeader + 10);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
static uint32_t compressedSize(const uint8_t* centralHeader) {
|
|
|
|
return get4(centralHeader + 20);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
static uint32_t uncompressedSize(const uint8_t* centralHeader) {
|
|
|
|
return get4(centralHeader + 24);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
static uint16_t fileNameLength(const uint8_t* centralHeader) {
|
|
|
|
return get2(centralHeader + 28);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
static uint16_t extraFieldLength(const uint8_t* centralHeader) {
|
|
|
|
return get2(centralHeader + 30);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
static uint16_t commentFieldLength(const uint8_t* centralHeader) {
|
|
|
|
return get2(centralHeader + 32);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
static uint32_t localHeaderOffset(const uint8_t* centralHeader) {
|
|
|
|
return get4(centralHeader + 42);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t localFileNameLength(const uint8_t* localHeader) {
|
|
|
|
return get2(localHeader + 26);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t localExtraFieldLength(const uint8_t* localHeader) {
|
|
|
|
return get2(localHeader + 28);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t centralDirectoryOffset(const uint8_t* centralHeader) {
|
|
|
|
return get4(centralHeader + 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const uint8_t* fileName(const uint8_t* centralHeader) {
|
|
|
|
return centralHeader + 46;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const uint8_t* fileData(const uint8_t* localHeader) {
|
|
|
|
return localHeader + LocalHeaderSize + localFileNameLength(localHeader) +
|
|
|
|
localExtraFieldLength(localHeader);
|
2007-09-17 14:11:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const uint8_t* endOfEntry(const uint8_t* p) {
|
2008-02-26 00:29:26 +00:00
|
|
|
return p + HeaderSize + fileNameLength(p) + extraFieldLength(p) +
|
|
|
|
commentFieldLength(p);
|
2007-09-17 14:11:41 +00:00
|
|
|
}
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
static JarIndex* make(System* s, unsigned capacity) {
|
|
|
|
return new
|
2008-01-13 22:05:08 +00:00
|
|
|
(allocate(s, sizeof(JarIndex) + (sizeof(Node*) * capacity)))
|
2007-09-17 00:13:36 +00:00
|
|
|
JarIndex(s, capacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JarIndex* open(System* s, System::Region* region) {
|
|
|
|
JarIndex* index = make(s, 32);
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
const uint8_t* start = region->start();
|
|
|
|
const uint8_t* end = start + region->length();
|
|
|
|
const uint8_t* p = end - 22;
|
|
|
|
// Find end of central directory record
|
|
|
|
while (p > start) {
|
|
|
|
if (signature(p) == 0x06054b50) {
|
|
|
|
p = region->start() + centralDirectoryOffset(p);
|
|
|
|
|
|
|
|
while (p < end) {
|
|
|
|
if (signature(p) == 0x02014b50) {
|
|
|
|
index = index->add(hash(fileName(p), fileNameLength(p)), p);
|
|
|
|
|
|
|
|
p = endOfEntry(p);
|
|
|
|
} else {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
2007-09-17 00:13:36 +00:00
|
|
|
} else {
|
2008-02-26 00:29:26 +00:00
|
|
|
p--;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
JarIndex* add(uint32_t hash, const uint8_t* entry) {
|
|
|
|
if (position < capacity) {
|
|
|
|
unsigned i = hash & (capacity - 1);
|
|
|
|
table[i] = new (nodes + (position++)) Node(hash, entry, table[i]);
|
|
|
|
return this;
|
|
|
|
} else {
|
|
|
|
JarIndex* index = make(s, capacity * 2);
|
|
|
|
for (unsigned i = 0; i < capacity; ++i) {
|
|
|
|
index->add(nodes[i].hash, nodes[i].entry);
|
|
|
|
}
|
|
|
|
index->add(hash, entry);
|
|
|
|
dispose();
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Node* findNode(const char* name) {
|
|
|
|
unsigned length = strlen(name);
|
|
|
|
unsigned i = hash(name) & (capacity - 1);
|
|
|
|
for (Node* n = table[i]; n; n = n->next) {
|
|
|
|
const uint8_t* p = n->entry;
|
|
|
|
if (equal(name, length, fileName(p), fileNameLength(p))) {
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
System::Region* find(const char* name, const uint8_t* start) {
|
2007-09-17 00:13:36 +00:00
|
|
|
Node* n = findNode(name);
|
|
|
|
if (n) {
|
|
|
|
const uint8_t* p = n->entry;
|
|
|
|
switch (compressionMethod(p)) {
|
|
|
|
case Stored: {
|
2008-01-13 22:05:08 +00:00
|
|
|
return new (allocate(s, sizeof(PointerRegion)))
|
2008-02-26 00:29:26 +00:00
|
|
|
PointerRegion(s, fileData(start + localHeaderOffset(p)),
|
|
|
|
compressedSize(p));
|
2007-09-17 00:13:36 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case Deflated: {
|
|
|
|
DataRegion* region = new
|
2008-01-13 22:05:08 +00:00
|
|
|
(allocate(s, sizeof(DataRegion) + uncompressedSize(p)))
|
2007-09-17 00:13:36 +00:00
|
|
|
DataRegion(s, uncompressedSize(p));
|
|
|
|
|
2007-09-17 14:11:41 +00:00
|
|
|
z_stream zStream; memset(&zStream, 0, sizeof(z_stream));
|
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
zStream.next_in = const_cast<uint8_t*>(fileData(start +
|
|
|
|
localHeaderOffset(p)));
|
2007-09-17 14:11:41 +00:00
|
|
|
zStream.avail_in = compressedSize(p);
|
|
|
|
zStream.next_out = region->data;
|
|
|
|
zStream.avail_out = region->length();
|
|
|
|
|
|
|
|
// -15 means max window size and raw deflate (no zlib wrapper)
|
|
|
|
int r = inflateInit2(&zStream, -15);
|
|
|
|
expect(s, r == Z_OK);
|
|
|
|
|
|
|
|
r = inflate(&zStream, Z_FINISH);
|
|
|
|
expect(s, r == Z_STREAM_END);
|
|
|
|
|
|
|
|
inflateEnd(&zStream);
|
|
|
|
|
|
|
|
return region;
|
2007-09-17 00:13:36 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort(s);
|
|
|
|
}
|
|
|
|
}
|
2007-09-21 14:15:39 +00:00
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool exists(const char* name) {
|
|
|
|
return findNode(name) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dispose() {
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(nodes);
|
|
|
|
s->free(this);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
unsigned capacity;
|
|
|
|
unsigned position;
|
2008-02-26 00:29:26 +00:00
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
Node* nodes;
|
|
|
|
Node* table[0];
|
|
|
|
};
|
|
|
|
|
|
|
|
class JarElement: public Element {
|
|
|
|
public:
|
2008-11-21 23:20:35 +00:00
|
|
|
class Iterator: public Element::Iterator {
|
|
|
|
public:
|
|
|
|
Iterator(System* s, JarIndex* index): s(s), index(index), position(0) { }
|
|
|
|
|
|
|
|
virtual const char* next(unsigned* size) {
|
|
|
|
if (position < index->position) {
|
|
|
|
JarIndex::Node* n = index->nodes + (position++);
|
|
|
|
*size = JarIndex::fileNameLength(n->entry);
|
|
|
|
return reinterpret_cast<const char*>(JarIndex::fileName(n->entry));
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
|
|
|
s->free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
JarIndex* index;
|
|
|
|
unsigned position;
|
|
|
|
};
|
|
|
|
|
2008-04-13 18:15:04 +00:00
|
|
|
JarElement(System* s, const char* name):
|
2008-11-11 15:20:49 +00:00
|
|
|
s(s), name(name), region(0), index(0)
|
2007-09-17 00:13:36 +00:00
|
|
|
{ }
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
virtual Element::Iterator* iterator() {
|
2008-11-28 04:44:04 +00:00
|
|
|
init();
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
return new (allocate(s, sizeof(Iterator))) Iterator(s, index);
|
|
|
|
}
|
|
|
|
|
2007-10-25 22:06:05 +00:00
|
|
|
virtual void init() {
|
2007-09-17 00:13:36 +00:00
|
|
|
if (index == 0) {
|
|
|
|
System::Region* r;
|
2007-10-25 22:06:05 +00:00
|
|
|
if (s->success(s->map(&r, name))) {
|
2007-09-17 00:13:36 +00:00
|
|
|
region = r;
|
|
|
|
index = JarIndex::open(s, r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual System::Region* find(const char* name) {
|
|
|
|
init();
|
2007-09-21 14:15:39 +00:00
|
|
|
|
|
|
|
while (*name == '/') name++;
|
|
|
|
|
2010-09-14 02:38:55 +00:00
|
|
|
System::Region* r = (index ? index->find(name, region->start()) : 0);
|
2010-09-20 23:31:23 +00:00
|
|
|
if (DebugFind) {
|
|
|
|
if (r) {
|
|
|
|
fprintf(stderr, "found %s in %s\n", name, this->name);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "%s not found in %s\n", name, this->name);
|
|
|
|
}
|
2010-09-14 02:38:55 +00:00
|
|
|
}
|
|
|
|
return r;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool exists(const char* name) {
|
|
|
|
init();
|
2007-09-21 14:15:39 +00:00
|
|
|
|
|
|
|
while (*name == '/') name++;
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
return (index ? index->exists(name) : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(name);
|
2007-09-17 00:13:36 +00:00
|
|
|
if (index) {
|
|
|
|
index->dispose();
|
2007-10-25 22:06:05 +00:00
|
|
|
}
|
|
|
|
if (region) {
|
2007-09-17 00:13:36 +00:00
|
|
|
region->dispose();
|
|
|
|
}
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(this);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
const char* name;
|
|
|
|
System::Region* region;
|
|
|
|
JarIndex* index;
|
|
|
|
};
|
|
|
|
|
2007-10-25 22:06:05 +00:00
|
|
|
class BuiltinElement: public JarElement {
|
|
|
|
public:
|
2008-04-13 18:15:04 +00:00
|
|
|
BuiltinElement(System* s, const char* name, const char* libraryName):
|
|
|
|
JarElement(s, name),
|
|
|
|
libraryName(libraryName ? copy(s, libraryName) : 0)
|
2007-10-25 22:06:05 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void init() {
|
|
|
|
if (index == 0) {
|
2010-09-20 23:31:23 +00:00
|
|
|
if (s->success(s->load(&library, libraryName))) {
|
2007-10-25 22:06:05 +00:00
|
|
|
void* p = library->resolve(name);
|
|
|
|
if (p) {
|
|
|
|
uint8_t* (*function)(unsigned*);
|
|
|
|
memcpy(&function, &p, BytesPerWord);
|
|
|
|
|
|
|
|
unsigned size;
|
|
|
|
uint8_t* data = function(&size);
|
|
|
|
if (data) {
|
2008-01-13 22:05:08 +00:00
|
|
|
region = new (allocate(s, sizeof(PointerRegion)))
|
2007-10-25 22:06:05 +00:00
|
|
|
PointerRegion(s, data, size);
|
|
|
|
index = JarIndex::open(s, region);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-03-31 03:43:43 +00:00
|
|
|
|
|
|
|
virtual void dispose() {
|
|
|
|
library->disposeAll();
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(libraryName);
|
2008-04-11 23:37:56 +00:00
|
|
|
JarElement::dispose();
|
2008-03-31 03:43:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System::Library* library;
|
|
|
|
const char* libraryName;
|
2007-10-25 22:06:05 +00:00
|
|
|
};
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
Element*
|
2008-03-31 03:43:43 +00:00
|
|
|
parsePath(System* s, const char* path, const char* bootLibrary)
|
2007-07-20 14:36:31 +00:00
|
|
|
{
|
2007-09-17 00:13:36 +00:00
|
|
|
Element* first = 0;
|
|
|
|
Element* prev = 0;
|
2007-10-24 15:46:09 +00:00
|
|
|
for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) {
|
2007-07-20 14:36:31 +00:00
|
|
|
Tokenizer::Token token(t.next());
|
2007-09-17 00:13:36 +00:00
|
|
|
|
|
|
|
Element* e;
|
2007-10-25 22:06:05 +00:00
|
|
|
if (*token.s == '[' and token.s[token.length - 1] == ']') {
|
2008-01-13 22:05:08 +00:00
|
|
|
char* name = static_cast<char*>(allocate(s, token.length - 1));
|
2007-10-25 22:06:05 +00:00
|
|
|
memcpy(name, token.s + 1, token.length - 1);
|
|
|
|
name[token.length - 2] = 0;
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
e = new (allocate(s, sizeof(BuiltinElement)))
|
2008-04-13 18:15:04 +00:00
|
|
|
BuiltinElement(s, name, bootLibrary);
|
2007-10-25 22:06:05 +00:00
|
|
|
} else {
|
2008-01-13 22:05:08 +00:00
|
|
|
char* name = static_cast<char*>(allocate(s, token.length + 1));
|
2007-10-25 22:06:05 +00:00
|
|
|
memcpy(name, token.s, token.length);
|
|
|
|
name[token.length] = 0;
|
|
|
|
|
|
|
|
switch (s->identify(name)) {
|
2008-11-21 23:20:35 +00:00
|
|
|
case System::TypeFile: {
|
2008-04-13 18:15:04 +00:00
|
|
|
e = new (allocate(s, sizeof(JarElement))) JarElement(s, name);
|
2007-10-25 22:06:05 +00:00
|
|
|
} break;
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
case System::TypeDirectory: {
|
2008-01-13 22:05:08 +00:00
|
|
|
e = new (allocate(s, sizeof(DirectoryElement)))
|
2008-04-13 18:15:04 +00:00
|
|
|
DirectoryElement(s, name);
|
2007-10-25 22:06:05 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default: {
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(name);
|
2007-10-25 22:06:05 +00:00
|
|
|
e = 0;
|
|
|
|
} break;
|
|
|
|
}
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
if (e) {
|
|
|
|
if (prev) {
|
|
|
|
prev->next = e;
|
|
|
|
} else {
|
|
|
|
first = e;
|
|
|
|
}
|
|
|
|
prev = e;
|
|
|
|
}
|
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
return first;
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
class MyIterator: public Finder::IteratorImp {
|
|
|
|
public:
|
|
|
|
MyIterator(System* s, Element* path):
|
|
|
|
s(s), e(path ? path->next : 0), it(path ? path->iterator() : 0)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual const char* next(unsigned* size) {
|
|
|
|
while (it) {
|
|
|
|
const char* v = it->next(size);
|
|
|
|
if (v) {
|
|
|
|
return v;
|
|
|
|
} else {
|
|
|
|
it->dispose();
|
|
|
|
if (e) {
|
|
|
|
it = e->iterator();
|
|
|
|
e = e->next;
|
2008-11-28 04:44:04 +00:00
|
|
|
} else {
|
|
|
|
it = 0;
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
|
|
|
if (it) it->dispose();
|
|
|
|
s->free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
Element* e;
|
|
|
|
Element::Iterator* it;
|
|
|
|
};
|
|
|
|
|
2007-08-10 23:45:47 +00:00
|
|
|
class MyFinder: public Finder {
|
2007-07-20 14:36:31 +00:00
|
|
|
public:
|
2008-03-31 03:43:43 +00:00
|
|
|
MyFinder(System* system, const char* path, const char* bootLibrary):
|
2007-07-20 14:36:31 +00:00
|
|
|
system(system),
|
2008-03-31 03:43:43 +00:00
|
|
|
path_(parsePath(system, path, bootLibrary)),
|
2008-04-13 18:15:04 +00:00
|
|
|
pathString(copy(system, path))
|
2007-07-20 14:36:31 +00:00
|
|
|
{ }
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
virtual IteratorImp* iterator() {
|
|
|
|
return new (allocate(system, sizeof(MyIterator)))
|
|
|
|
MyIterator(system, path_);
|
|
|
|
}
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
virtual System::Region* find(const char* name) {
|
|
|
|
for (Element* e = path_; e; e = e->next) {
|
|
|
|
System::Region* r = e->find(name);
|
|
|
|
if (r) {
|
|
|
|
return r;
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-10 23:45:47 +00:00
|
|
|
virtual bool exists(const char* name) {
|
2007-09-17 00:13:36 +00:00
|
|
|
for (Element* e = path_; e; e = e->next) {
|
|
|
|
if (e->exists(name)) {
|
2007-08-10 23:45:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-08-27 13:46:17 +00:00
|
|
|
virtual const char* path() {
|
|
|
|
return pathString;
|
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
virtual void dispose() {
|
2007-09-17 00:13:36 +00:00
|
|
|
for (Element* e = path_; e;) {
|
|
|
|
Element* t = e;
|
|
|
|
e = e->next;
|
|
|
|
t->dispose();
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
2008-04-13 18:15:04 +00:00
|
|
|
system->free(pathString);
|
|
|
|
system->free(this);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* system;
|
2007-09-17 00:13:36 +00:00
|
|
|
Element* path_;
|
2007-08-27 13:46:17 +00:00
|
|
|
const char* pathString;
|
2007-07-20 14:36:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
2007-08-10 23:45:47 +00:00
|
|
|
Finder*
|
2008-03-31 03:43:43 +00:00
|
|
|
makeFinder(System* s, const char* path, const char* bootLibrary)
|
2007-07-20 14:36:31 +00:00
|
|
|
{
|
2008-03-31 03:43:43 +00:00
|
|
|
return new (allocate(s, sizeof(MyFinder))) MyFinder(s, path, bootLibrary);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vm
|