2014-04-21 02:14:48 +00:00
|
|
|
/* Copyright (c) 2008-2014, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
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. */
|
|
|
|
|
2014-02-07 21:24:56 +00:00
|
|
|
#include <avian/system/system.h>
|
2013-02-21 23:18:20 +00:00
|
|
|
#include <avian/util/string.h>
|
|
|
|
#include <avian/util/runtime-array.h>
|
2013-12-11 04:36:55 +00:00
|
|
|
#include <avian/util/list.h>
|
2014-06-28 23:24:24 +00:00
|
|
|
#include <avian/util/hash.h>
|
2013-02-21 23:18:20 +00:00
|
|
|
|
2013-02-27 20:25:50 +00:00
|
|
|
#include "avian/zlib-custom.h"
|
|
|
|
#include "avian/finder.h"
|
|
|
|
#include "avian/lzma.h"
|
2014-02-25 18:32:17 +00:00
|
|
|
#include "avian/append.h"
|
2013-02-11 00:51:59 +00:00
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
using namespace vm;
|
2013-02-21 23:18:20 +00:00
|
|
|
using namespace avian::util;
|
2007-07-20 14:36:31 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2010-09-14 02:38:55 +00:00
|
|
|
const bool DebugFind = false;
|
2011-07-18 01:48:12 +00:00
|
|
|
const bool DebugStat = false;
|
2010-09-14 02:38:55 +00:00
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
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;
|
2010-11-05 19:18:28 +00:00
|
|
|
virtual System::FileType stat(const char* name, unsigned* length,
|
|
|
|
bool tryDirectory) = 0;
|
2011-03-26 01:14:21 +00:00
|
|
|
virtual const char* urlPrefix() = 0;
|
2011-04-01 01:16:57 +00:00
|
|
|
virtual const char* sourceUrl() = 0;
|
2007-09-17 00:13:36 +00:00
|
|
|
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:
|
2010-11-05 19:18:28 +00:00
|
|
|
Iterator(System* s, Allocator* allocator, const char* name, unsigned skip):
|
|
|
|
s(s), allocator(allocator), 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) {
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(last, strlen(last) + 1);
|
2008-11-28 04:44:04 +00:00
|
|
|
}
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
if (directory) {
|
|
|
|
for (const char* v = directory->next(); v; v = directory->next()) {
|
|
|
|
if (v[0] != '.') {
|
2010-11-05 19:18:28 +00:00
|
|
|
last = append(allocator, name, "/", v);
|
|
|
|
unsigned length;
|
|
|
|
if (s->stat(last, &length) == System::TypeDirectory) {
|
|
|
|
it = new (allocator->allocate(sizeof(Iterator)))
|
|
|
|
Iterator(s, allocator, last, skip);
|
2008-11-28 04:44:04 +00:00
|
|
|
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();
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(this, sizeof(*this));
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2010-11-05 19:18:28 +00:00
|
|
|
Allocator* allocator;
|
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
|
|
|
};
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
DirectoryElement(System* s, Allocator* allocator, const char* name):
|
2011-07-11 16:56:53 +00:00
|
|
|
s(s),
|
|
|
|
allocator(allocator),
|
|
|
|
originalName(name),
|
|
|
|
name(s->toAbsolutePath(allocator, name)),
|
|
|
|
urlPrefix_(append(allocator, "file:", this->name, "/")),
|
|
|
|
sourceUrl_(append(allocator, "file:", this->name))
|
2007-09-17 00:13:36 +00:00
|
|
|
{ }
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
virtual Element::Iterator* iterator() {
|
2010-11-05 19:18:28 +00:00
|
|
|
return new (allocator->allocate(sizeof(Iterator)))
|
|
|
|
Iterator(s, allocator, 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) {
|
2010-11-05 19:18:28 +00:00
|
|
|
const char* file = append(allocator, this->name, "/", name);
|
2007-09-17 00:13:36 +00:00
|
|
|
System::Region* region;
|
|
|
|
System::Status status = s->map(®ion, file);
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(file, strlen(file) + 1);
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
virtual System::FileType stat(const char* name, unsigned* length, bool) {
|
|
|
|
const char* file = append(allocator, this->name, "/", name);
|
|
|
|
System::FileType type = s->stat(file, length);
|
2011-07-18 01:48:12 +00:00
|
|
|
if (DebugStat) {
|
|
|
|
fprintf(stderr, "stat %s in %s: %d\n", name, this->name, type);
|
|
|
|
}
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(file, strlen(file) + 1);
|
|
|
|
return type;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2011-03-26 01:14:21 +00:00
|
|
|
virtual const char* urlPrefix() {
|
|
|
|
return urlPrefix_;
|
|
|
|
}
|
|
|
|
|
2011-04-01 01:16:57 +00:00
|
|
|
virtual const char* sourceUrl() {
|
|
|
|
return sourceUrl_;
|
|
|
|
}
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
virtual void dispose() {
|
2011-07-11 16:56:53 +00:00
|
|
|
allocator->free(originalName, strlen(originalName) + 1);
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(name, strlen(name) + 1);
|
2011-03-26 01:14:21 +00:00
|
|
|
allocator->free(urlPrefix_, strlen(urlPrefix_) + 1);
|
2011-04-01 01:16:57 +00:00
|
|
|
allocator->free(sourceUrl_, strlen(sourceUrl_) + 1);
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(this, sizeof(*this));
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2010-11-05 19:18:28 +00:00
|
|
|
Allocator* allocator;
|
2011-07-11 16:56:53 +00:00
|
|
|
const char* originalName;
|
2007-09-17 00:13:36 +00:00
|
|
|
const char* name;
|
2011-03-26 01:14:21 +00:00
|
|
|
const char* urlPrefix_;
|
2011-04-01 01:16:57 +00:00
|
|
|
const char* sourceUrl_;
|
2007-09-17 00:13:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class PointerRegion: public System::Region {
|
|
|
|
public:
|
2010-11-05 19:18:28 +00:00
|
|
|
PointerRegion(System* s, Allocator* allocator, const uint8_t* start,
|
2012-06-02 15:06:22 +00:00
|
|
|
size_t length, bool freePointer = false):
|
2007-09-17 00:13:36 +00:00
|
|
|
s(s),
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator(allocator),
|
2007-09-17 00:13:36 +00:00
|
|
|
start_(start),
|
2012-06-02 15:06:22 +00:00
|
|
|
length_(length),
|
|
|
|
freePointer(freePointer)
|
2007-09-17 00:13:36 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual const uint8_t* start() {
|
|
|
|
return start_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual size_t length() {
|
|
|
|
return length_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2012-06-02 15:06:22 +00:00
|
|
|
if (freePointer) {
|
|
|
|
allocator->free(start_, length_);
|
|
|
|
}
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(this, sizeof(*this));
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2010-11-05 19:18:28 +00:00
|
|
|
Allocator* allocator;
|
2007-09-17 00:13:36 +00:00
|
|
|
const uint8_t* start_;
|
|
|
|
size_t length_;
|
2012-06-02 15:06:22 +00:00
|
|
|
bool freePointer;
|
2007-09-17 00:13:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class DataRegion: public System::Region {
|
|
|
|
public:
|
2010-11-05 19:18:28 +00:00
|
|
|
DataRegion(System* s, Allocator* allocator, size_t length):
|
2007-09-17 00:13:36 +00:00
|
|
|
s(s),
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator(allocator),
|
2007-09-17 00:13:36 +00:00
|
|
|
length_(length)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual const uint8_t* start() {
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual size_t length() {
|
|
|
|
return length_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2010-11-27 18:25:02 +00:00
|
|
|
allocator->free(this, sizeof(*this) + length_);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2010-11-05 19:18:28 +00:00
|
|
|
Allocator* allocator;
|
2007-09-17 00:13:36 +00:00
|
|
|
size_t length_;
|
|
|
|
uint8_t data[0];
|
|
|
|
};
|
|
|
|
|
|
|
|
class JarIndex {
|
|
|
|
public:
|
|
|
|
enum CompressionMethod {
|
|
|
|
Stored = 0,
|
|
|
|
Deflated = 8
|
|
|
|
};
|
|
|
|
|
2013-12-11 04:36:55 +00:00
|
|
|
class Entry {
|
|
|
|
public:
|
|
|
|
Entry(uint32_t hash, const uint8_t* entry):
|
|
|
|
hash(hash),
|
|
|
|
entry(entry) {}
|
2007-09-17 00:13:36 +00:00
|
|
|
|
|
|
|
uint32_t hash;
|
|
|
|
const uint8_t* entry;
|
|
|
|
};
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
JarIndex(System* s, Allocator* allocator, unsigned capacity):
|
2007-09-17 00:13:36 +00:00
|
|
|
s(s),
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator(allocator),
|
2007-09-17 00:13:36 +00:00
|
|
|
capacity(capacity),
|
|
|
|
position(0),
|
2013-12-11 04:36:55 +00:00
|
|
|
nodes(static_cast<List<Entry>*>(allocator->allocate(sizeof(List<Entry>) * capacity)))
|
2007-09-17 00:13:36 +00:00
|
|
|
{
|
2013-12-11 04:36:55 +00:00
|
|
|
memset(table, 0, sizeof(List<Entry>*) * capacity);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
static JarIndex* make(System* s, Allocator* allocator, unsigned capacity) {
|
2007-09-17 00:13:36 +00:00
|
|
|
return new
|
2013-12-11 04:36:55 +00:00
|
|
|
(allocator->allocate(sizeof(JarIndex) + (sizeof(List<Entry>*) * capacity)))
|
2010-11-05 19:18:28 +00:00
|
|
|
JarIndex(s, allocator, capacity);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
static JarIndex* open(System* s, Allocator* allocator,
|
|
|
|
System::Region* region)
|
|
|
|
{
|
|
|
|
JarIndex* index = make(s, allocator, 32);
|
2007-09-17 00:13:36 +00:00
|
|
|
|
2008-02-26 00:29:26 +00:00
|
|
|
const uint8_t* start = region->start();
|
|
|
|
const uint8_t* end = start + region->length();
|
2011-03-04 23:55:31 +00:00
|
|
|
const uint8_t* p = end - CentralDirectorySearchStart;
|
2008-02-26 00:29:26 +00:00
|
|
|
// Find end of central directory record
|
|
|
|
while (p > start) {
|
2011-03-04 23:55:31 +00:00
|
|
|
if (signature(p) == CentralDirectorySignature) {
|
2013-12-11 04:36:55 +00:00
|
|
|
p = region->start() + centralDirectoryOffset(p);
|
|
|
|
|
|
|
|
while (p < end) {
|
|
|
|
if (signature(p) == EntrySignature) {
|
2014-06-27 00:17:16 +00:00
|
|
|
index = index->add(Entry(hash(Slice<const uint8_t>(fileName(p), fileNameLength(p))), p));
|
2013-12-11 04:36:55 +00:00
|
|
|
|
|
|
|
p = endOfEntry(p);
|
|
|
|
} else {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
2007-09-17 00:13:36 +00:00
|
|
|
} else {
|
2013-12-11 04:36:55 +00:00
|
|
|
p--;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
2013-12-11 04:36:55 +00:00
|
|
|
JarIndex* add(const Entry& entry) {
|
2007-09-17 00:13:36 +00:00
|
|
|
if (position < capacity) {
|
2013-12-11 04:36:55 +00:00
|
|
|
unsigned i = entry.hash & (capacity - 1);
|
|
|
|
table[i] = new (nodes + (position++)) List<Entry>(entry, table[i]);
|
2007-09-17 00:13:36 +00:00
|
|
|
return this;
|
|
|
|
} else {
|
2010-11-05 19:18:28 +00:00
|
|
|
JarIndex* index = make(s, allocator, capacity * 2);
|
2007-09-17 00:13:36 +00:00
|
|
|
for (unsigned i = 0; i < capacity; ++i) {
|
2013-12-11 04:36:55 +00:00
|
|
|
index->add(nodes[i].item);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
2013-12-11 04:36:55 +00:00
|
|
|
index->add(entry);
|
2007-09-17 00:13:36 +00:00
|
|
|
dispose();
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-11 04:36:55 +00:00
|
|
|
List<Entry>* findNode(const char* name) {
|
2007-09-17 00:13:36 +00:00
|
|
|
unsigned length = strlen(name);
|
|
|
|
unsigned i = hash(name) & (capacity - 1);
|
2013-12-11 04:36:55 +00:00
|
|
|
for (List<Entry>* n = table[i]; n; n = n->next) {
|
|
|
|
const uint8_t* p = n->item.entry;
|
2007-09-17 00:13:36 +00:00
|
|
|
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) {
|
2013-12-11 04:36:55 +00:00
|
|
|
List<Entry>* n = findNode(name);
|
2007-09-17 00:13:36 +00:00
|
|
|
if (n) {
|
2013-12-11 04:36:55 +00:00
|
|
|
const uint8_t* p = n->item.entry;
|
2007-09-17 00:13:36 +00:00
|
|
|
switch (compressionMethod(p)) {
|
|
|
|
case Stored: {
|
2010-11-05 19:18:28 +00:00
|
|
|
return new (allocator->allocate(sizeof(PointerRegion)))
|
|
|
|
PointerRegion(s, allocator, fileData(start + localHeaderOffset(p)),
|
2013-12-11 04:36:55 +00:00
|
|
|
compressedSize(p));
|
2007-09-17 00:13:36 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case Deflated: {
|
|
|
|
DataRegion* region = new
|
2010-11-05 19:18:28 +00:00
|
|
|
(allocator->allocate(sizeof(DataRegion) + uncompressedSize(p)))
|
|
|
|
DataRegion(s, allocator, uncompressedSize(p));
|
2007-09-17 00:13:36 +00:00
|
|
|
|
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 +
|
2013-12-11 04:36:55 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
System::FileType stat(const char* name, unsigned* length, bool tryDirectory)
|
|
|
|
{
|
2013-12-11 04:36:55 +00:00
|
|
|
List<Entry>* node = findNode(name);
|
2010-11-05 19:18:28 +00:00
|
|
|
if (node) {
|
2013-12-11 04:36:55 +00:00
|
|
|
*length = uncompressedSize(node->item.entry);
|
2010-11-05 19:18:28 +00:00
|
|
|
return System::TypeFile;
|
|
|
|
} else if (tryDirectory) {
|
|
|
|
*length = 0;
|
|
|
|
|
|
|
|
// try again with '/' appended
|
|
|
|
unsigned length = strlen(name);
|
|
|
|
RUNTIME_ARRAY(char, n, length + 2);
|
|
|
|
memcpy(RUNTIME_ARRAY_BODY(n), name, length);
|
|
|
|
RUNTIME_ARRAY_BODY(n)[length] = '/';
|
|
|
|
RUNTIME_ARRAY_BODY(n)[length + 1] = 0;
|
|
|
|
|
2011-01-21 23:14:21 +00:00
|
|
|
node = findNode(RUNTIME_ARRAY_BODY(n));
|
2010-11-05 19:18:28 +00:00
|
|
|
if (node) {
|
|
|
|
return System::TypeDirectory;
|
|
|
|
} else {
|
|
|
|
return System::TypeDoesNotExist;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*length = 0;
|
|
|
|
return System::TypeDoesNotExist;
|
|
|
|
}
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dispose() {
|
2013-12-11 04:36:55 +00:00
|
|
|
allocator->free(nodes, sizeof(List<Entry>) * capacity);
|
|
|
|
allocator->free(this, sizeof(*this) + (sizeof(List<Entry>*) * capacity));
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2010-11-05 19:18:28 +00:00
|
|
|
Allocator* allocator;
|
2007-09-17 00:13:36 +00:00
|
|
|
unsigned capacity;
|
|
|
|
unsigned position;
|
2008-02-26 00:29:26 +00:00
|
|
|
|
2013-12-11 04:36:55 +00:00
|
|
|
List<Entry>* nodes;
|
|
|
|
List<Entry>* table[0];
|
2007-09-17 00:13:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class JarElement: public Element {
|
|
|
|
public:
|
2008-11-21 23:20:35 +00:00
|
|
|
class Iterator: public Element::Iterator {
|
|
|
|
public:
|
2010-11-05 19:18:28 +00:00
|
|
|
Iterator(System* s, Allocator* allocator, JarIndex* index):
|
|
|
|
s(s), allocator(allocator), index(index), position(0)
|
|
|
|
{ }
|
2008-11-21 23:20:35 +00:00
|
|
|
|
|
|
|
virtual const char* next(unsigned* size) {
|
|
|
|
if (position < index->position) {
|
2013-12-11 04:36:55 +00:00
|
|
|
List<JarIndex::Entry>* n = index->nodes + (position++);
|
|
|
|
*size = fileNameLength(n->item.entry);
|
|
|
|
return reinterpret_cast<const char*>(fileName(n->item.entry));
|
2008-11-21 23:20:35 +00:00
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(this, sizeof(*this));
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2010-11-05 19:18:28 +00:00
|
|
|
Allocator* allocator;
|
2008-11-21 23:20:35 +00:00
|
|
|
JarIndex* index;
|
|
|
|
unsigned position;
|
|
|
|
};
|
|
|
|
|
2011-07-11 16:56:53 +00:00
|
|
|
JarElement(System* s, Allocator* allocator, const char* name,
|
|
|
|
bool canonicalizePath = true):
|
|
|
|
s(s),
|
|
|
|
allocator(allocator),
|
|
|
|
originalName(name),
|
|
|
|
name(name and canonicalizePath
|
|
|
|
? s->toAbsolutePath(allocator, name) : name),
|
|
|
|
urlPrefix_(this->name
|
|
|
|
? append(allocator, "jar:file:", this->name, "!/") : 0),
|
|
|
|
sourceUrl_(this->name
|
|
|
|
? append(allocator, "file:", this->name) : 0),
|
2011-03-26 01:14:21 +00:00
|
|
|
region(0), index(0)
|
2010-11-05 19:18:28 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
JarElement(System* s, Allocator* allocator, const uint8_t* jarData,
|
|
|
|
unsigned jarLength):
|
|
|
|
s(s),
|
|
|
|
allocator(allocator),
|
2012-03-13 16:30:41 +00:00
|
|
|
originalName(0),
|
2010-11-05 19:18:28 +00:00
|
|
|
name(0),
|
2011-03-26 01:14:21 +00:00
|
|
|
urlPrefix_(name ? append(allocator, "jar:file:", name, "!/") : 0),
|
2011-04-01 01:16:57 +00:00
|
|
|
sourceUrl_(name ? append(allocator, "file:", name) : 0),
|
2010-11-05 19:18:28 +00:00
|
|
|
region(new (allocator->allocate(sizeof(PointerRegion)))
|
|
|
|
PointerRegion(s, allocator, jarData, jarLength)),
|
|
|
|
index(JarIndex::open(s, allocator, region))
|
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();
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
return new (allocator->allocate(sizeof(Iterator)))
|
|
|
|
Iterator(s, allocator, index);
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2010-11-05 19:18:28 +00:00
|
|
|
index = JarIndex::open(s, allocator, r);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
virtual System::FileType stat(const char* name, unsigned* length,
|
|
|
|
bool tryDirectory)
|
|
|
|
{
|
2007-09-17 00:13:36 +00:00
|
|
|
init();
|
2007-09-21 14:15:39 +00:00
|
|
|
|
|
|
|
while (*name == '/') name++;
|
|
|
|
|
2011-07-18 01:48:12 +00:00
|
|
|
System::FileType type = (index ? index->stat(name, length, tryDirectory)
|
|
|
|
: System::TypeDoesNotExist);
|
|
|
|
if (DebugStat) {
|
|
|
|
fprintf(stderr, "stat %s in %s: %d\n", name, this->name, type);
|
|
|
|
}
|
|
|
|
return type;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2011-03-26 01:14:21 +00:00
|
|
|
virtual const char* urlPrefix() {
|
|
|
|
return urlPrefix_;
|
|
|
|
}
|
|
|
|
|
2011-04-01 01:16:57 +00:00
|
|
|
virtual const char* sourceUrl() {
|
|
|
|
return sourceUrl_;
|
|
|
|
}
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
virtual void dispose() {
|
2010-11-05 19:18:28 +00:00
|
|
|
dispose(sizeof(*this));
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose(unsigned size) {
|
2012-03-13 16:30:41 +00:00
|
|
|
if (name) {
|
|
|
|
if (originalName != name) {
|
|
|
|
allocator->free(originalName, strlen(originalName) + 1);
|
|
|
|
}
|
|
|
|
allocator->free(name, strlen(name) + 1);
|
|
|
|
allocator->free(urlPrefix_, strlen(urlPrefix_) + 1);
|
|
|
|
allocator->free(sourceUrl_, strlen(sourceUrl_) + 1);
|
2011-07-11 16:56:53 +00:00
|
|
|
}
|
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();
|
|
|
|
}
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(this, size);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2010-11-05 19:18:28 +00:00
|
|
|
Allocator* allocator;
|
2011-07-11 16:56:53 +00:00
|
|
|
const char* originalName;
|
2007-09-17 00:13:36 +00:00
|
|
|
const char* name;
|
2011-03-26 01:14:21 +00:00
|
|
|
const char* urlPrefix_;
|
2011-04-01 01:16:57 +00:00
|
|
|
const char* sourceUrl_;
|
2007-09-17 00:13:36 +00:00
|
|
|
System::Region* region;
|
|
|
|
JarIndex* index;
|
|
|
|
};
|
|
|
|
|
2007-10-25 22:06:05 +00:00
|
|
|
class BuiltinElement: public JarElement {
|
|
|
|
public:
|
2010-11-05 19:18:28 +00:00
|
|
|
BuiltinElement(System* s, Allocator* allocator, const char* name,
|
|
|
|
const char* libraryName):
|
2011-07-11 16:56:53 +00:00
|
|
|
JarElement(s, allocator, name, false),
|
2010-11-05 19:18:28 +00:00
|
|
|
libraryName(libraryName ? copy(allocator, 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))) {
|
2014-01-19 02:41:43 +00:00
|
|
|
bool lzma = strncmp("lzma.", name, 5) == 0;
|
2012-06-02 15:06:22 +00:00
|
|
|
const char* symbolName = lzma ? name + 5 : name;
|
|
|
|
|
|
|
|
void* p = library->resolve(symbolName);
|
2007-10-25 22:06:05 +00:00
|
|
|
if (p) {
|
|
|
|
uint8_t* (*function)(unsigned*);
|
|
|
|
memcpy(&function, &p, BytesPerWord);
|
|
|
|
|
|
|
|
unsigned size;
|
|
|
|
uint8_t* data = function(&size);
|
|
|
|
if (data) {
|
2012-06-02 15:06:22 +00:00
|
|
|
bool freePointer;
|
|
|
|
if (lzma) {
|
|
|
|
#ifdef AVIAN_USE_LZMA
|
|
|
|
unsigned outSize;
|
|
|
|
data = decodeLZMA(s, allocator, data, size, &outSize);
|
|
|
|
size = outSize;
|
|
|
|
freePointer = true;
|
|
|
|
#else
|
|
|
|
abort(s);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
freePointer = false;
|
|
|
|
}
|
2010-11-05 19:18:28 +00:00
|
|
|
region = new (allocator->allocate(sizeof(PointerRegion)))
|
2012-06-02 15:06:22 +00:00
|
|
|
PointerRegion(s, allocator, data, size, freePointer);
|
2010-11-05 19:18:28 +00:00
|
|
|
index = JarIndex::open(s, allocator, region);
|
2012-06-02 15:06:22 +00:00
|
|
|
} else if (DebugFind) {
|
|
|
|
fprintf(stderr, "%s in %s returned null\n", symbolName,
|
|
|
|
libraryName);
|
2007-10-25 22:06:05 +00:00
|
|
|
}
|
2012-06-02 15:06:22 +00:00
|
|
|
} else if (DebugFind) {
|
|
|
|
fprintf(stderr, "unable to find %s in %s\n", symbolName,
|
|
|
|
libraryName);
|
2007-10-25 22:06:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-03-31 03:43:43 +00:00
|
|
|
|
2011-03-26 01:14:21 +00:00
|
|
|
virtual const char* urlPrefix() {
|
2012-10-06 21:33:24 +00:00
|
|
|
return "avianvmresource:";
|
2011-03-26 01:14:21 +00:00
|
|
|
}
|
|
|
|
|
2011-04-01 01:16:57 +00:00
|
|
|
virtual const char* sourceUrl() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-03-31 03:43:43 +00:00
|
|
|
virtual void dispose() {
|
|
|
|
library->disposeAll();
|
2010-11-05 19:18:28 +00:00
|
|
|
if (libraryName) {
|
|
|
|
allocator->free(libraryName, strlen(libraryName) + 1);
|
|
|
|
}
|
|
|
|
JarElement::dispose(sizeof(*this));
|
2008-03-31 03:43:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System::Library* library;
|
|
|
|
const char* libraryName;
|
2007-10-25 22:06:05 +00:00
|
|
|
};
|
|
|
|
|
2011-02-21 23:05:28 +00:00
|
|
|
void
|
|
|
|
add(Element** first, Element** last, Element* e)
|
2007-07-20 14:36:31 +00:00
|
|
|
{
|
2011-02-21 23:05:28 +00:00
|
|
|
if (*last) {
|
|
|
|
(*last)->next = e;
|
|
|
|
} else {
|
|
|
|
*first = e;
|
|
|
|
}
|
|
|
|
*last = e;
|
|
|
|
}
|
2007-09-17 00:13:36 +00:00
|
|
|
|
2011-02-21 23:05:28 +00:00
|
|
|
unsigned
|
|
|
|
baseName(const char* name, char fileSeparator)
|
|
|
|
{
|
|
|
|
const char* p = name;
|
|
|
|
const char* last = 0;
|
|
|
|
while (*p) {
|
|
|
|
if (*p == fileSeparator) {
|
|
|
|
last = p;
|
|
|
|
}
|
|
|
|
++p;
|
|
|
|
}
|
2007-10-25 22:06:05 +00:00
|
|
|
|
2011-02-21 23:05:28 +00:00
|
|
|
return last ? (last + 1) - name : 0;
|
|
|
|
}
|
2007-10-25 22:06:05 +00:00
|
|
|
|
2011-02-21 23:05:28 +00:00
|
|
|
void
|
|
|
|
add(System* s, Element** first, Element** last, Allocator* allocator,
|
|
|
|
const char* name, unsigned nameLength, const char* bootLibrary);
|
|
|
|
|
2011-05-16 16:34:10 +00:00
|
|
|
void
|
|
|
|
addTokens(System* s, Element** first, Element** last, Allocator* allocator,
|
|
|
|
const char* jarName, unsigned jarNameBase, const char* tokens,
|
|
|
|
unsigned tokensLength, const char* bootLibrary)
|
|
|
|
{
|
2013-02-21 23:18:20 +00:00
|
|
|
for (Tokenizer t(String(tokens, tokensLength), ' '); t.hasMore();) {
|
|
|
|
String token(t.next());
|
2011-05-16 16:34:10 +00:00
|
|
|
|
|
|
|
RUNTIME_ARRAY(char, n, jarNameBase + token.length + 1);
|
|
|
|
memcpy(RUNTIME_ARRAY_BODY(n), jarName, jarNameBase);
|
2013-02-21 23:18:20 +00:00
|
|
|
memcpy(RUNTIME_ARRAY_BODY(n) + jarNameBase, token.text, token.length);
|
2011-05-16 16:34:10 +00:00
|
|
|
RUNTIME_ARRAY_BODY(n)[jarNameBase + token.length] = 0;
|
|
|
|
|
|
|
|
add(s, first, last, allocator, RUNTIME_ARRAY_BODY(n),
|
|
|
|
jarNameBase + token.length, bootLibrary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
continuationLine(const uint8_t* base, unsigned total, unsigned* start,
|
|
|
|
unsigned* length)
|
|
|
|
{
|
|
|
|
return readLine(base, total, start, length)
|
|
|
|
and *length > 0
|
|
|
|
and base[*start] == ' ';
|
|
|
|
}
|
|
|
|
|
2011-02-21 23:05:28 +00:00
|
|
|
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);
|
|
|
|
|
2011-05-16 16:34:10 +00:00
|
|
|
unsigned nameBase = baseName(name, s->fileSeparator());
|
|
|
|
|
2011-02-21 23:05:28 +00:00
|
|
|
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)) {
|
2011-05-16 16:34:10 +00:00
|
|
|
unsigned multilineTotal = 0;
|
|
|
|
|
2011-02-21 23:05:28 +00:00
|
|
|
const unsigned PrefixLength = 12;
|
2011-05-16 16:34:10 +00:00
|
|
|
if (length > PrefixLength
|
|
|
|
and strncmp("Class-Path: ", reinterpret_cast<const char*>
|
|
|
|
(region->start() + start), PrefixLength) == 0)
|
2011-02-21 23:05:28 +00:00
|
|
|
{
|
2011-05-16 16:34:10 +00:00
|
|
|
{ unsigned nextStart = start + length;
|
|
|
|
unsigned nextLength;
|
|
|
|
while (continuationLine
|
|
|
|
(region->start(), region->length(), &nextStart, &nextLength))
|
|
|
|
{
|
|
|
|
multilineTotal += nextLength;
|
|
|
|
nextStart += nextLength;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* line = reinterpret_cast<const char*>
|
|
|
|
(region->start() + start + PrefixLength);
|
|
|
|
|
|
|
|
unsigned lineLength = length - PrefixLength;
|
|
|
|
|
|
|
|
if (multilineTotal) {
|
|
|
|
RUNTIME_ARRAY
|
|
|
|
(char, n, (length - PrefixLength) + multilineTotal + 1);
|
|
|
|
|
|
|
|
memcpy(RUNTIME_ARRAY_BODY(n), line, lineLength);
|
|
|
|
|
|
|
|
unsigned offset = lineLength;
|
|
|
|
{ unsigned nextStart = start + length;
|
|
|
|
unsigned nextLength;
|
|
|
|
while (continuationLine
|
|
|
|
(region->start(), region->length(), &nextStart,
|
|
|
|
&nextLength))
|
|
|
|
{
|
|
|
|
unsigned continuationLength = nextLength - 1;
|
|
|
|
|
|
|
|
memcpy(RUNTIME_ARRAY_BODY(n) + offset,
|
|
|
|
region->start() + nextStart + 1, continuationLength);
|
|
|
|
|
|
|
|
offset += continuationLength;
|
|
|
|
nextStart += nextLength;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
addTokens(s, first, last, allocator, name, nameBase,
|
|
|
|
RUNTIME_ARRAY_BODY(n), offset, bootLibrary);
|
|
|
|
} else {
|
|
|
|
addTokens(s, first, last, allocator, name, nameBase, line,
|
|
|
|
lineLength, bootLibrary);
|
2011-02-21 23:05:28 +00:00
|
|
|
}
|
2007-10-25 22:06:05 +00:00
|
|
|
}
|
2011-05-16 16:34:10 +00:00
|
|
|
|
|
|
|
start += length + multilineTotal;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
|
2011-02-21 23:05:28 +00:00
|
|
|
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<char*>(allocator->allocate(tokenLength - 1));
|
|
|
|
memcpy(name, token + 1, tokenLength - 1);
|
|
|
|
name[tokenLength - 2] = 0;
|
|
|
|
|
2010-11-27 23:27:22 +00:00
|
|
|
if (DebugFind) {
|
2011-02-21 23:05:28 +00:00
|
|
|
fprintf(stderr, "add builtin %s\n", name);
|
2010-11-27 23:27:22 +00:00
|
|
|
}
|
2011-02-21 23:05:28 +00:00
|
|
|
|
|
|
|
add(first, last, new (allocator->allocate(sizeof(BuiltinElement)))
|
|
|
|
BuiltinElement(s, allocator, name, bootLibrary));
|
|
|
|
} else {
|
|
|
|
char* name = static_cast<char*>(allocator->allocate(tokenLength + 1));
|
|
|
|
memcpy(name, token, tokenLength);
|
|
|
|
name[tokenLength] = 0;
|
2010-11-27 23:27:22 +00:00
|
|
|
|
2011-02-21 23:05:28 +00:00
|
|
|
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);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
2011-02-21 23:05:28 +00:00
|
|
|
|
|
|
|
allocator->free(name, strlen(name) + 1);
|
|
|
|
} break;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
}
|
2011-02-21 23:05:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Element*
|
|
|
|
parsePath(System* s, Allocator* allocator, const char* path,
|
|
|
|
const char* bootLibrary)
|
|
|
|
{
|
|
|
|
Element* first = 0;
|
|
|
|
Element* last = 0;
|
|
|
|
for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) {
|
2013-02-21 23:18:20 +00:00
|
|
|
String token(t.next());
|
2011-02-21 23:05:28 +00:00
|
|
|
|
2013-02-21 23:18:20 +00:00
|
|
|
add(s, &first, &last, allocator, token.text, token.length, bootLibrary);
|
2011-02-21 23:05:28 +00:00
|
|
|
}
|
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:
|
2010-11-05 19:18:28 +00:00
|
|
|
MyIterator(System* s, Allocator* allocator, Element* path):
|
|
|
|
s(s), allocator(allocator), e(path ? path->next : 0),
|
|
|
|
it(path ? path->iterator() : 0)
|
2008-11-21 23:20:35 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
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();
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(this, sizeof(*this));
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2010-11-05 19:18:28 +00:00
|
|
|
Allocator* allocator;
|
2008-11-21 23:20:35 +00:00
|
|
|
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:
|
2010-11-05 19:18:28 +00:00
|
|
|
MyFinder(System* system, Allocator* allocator, const char* path,
|
|
|
|
const char* bootLibrary):
|
|
|
|
system(system),
|
|
|
|
allocator(allocator),
|
|
|
|
path_(parsePath(system, allocator, path, bootLibrary)),
|
|
|
|
pathString(copy(allocator, path))
|
|
|
|
{ }
|
|
|
|
|
|
|
|
MyFinder(System* system, Allocator* allocator, const uint8_t* jarData,
|
|
|
|
unsigned jarLength):
|
2007-07-20 14:36:31 +00:00
|
|
|
system(system),
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator(allocator),
|
|
|
|
path_(new (allocator->allocate(sizeof(JarElement)))
|
|
|
|
JarElement(system, allocator, jarData, jarLength)),
|
|
|
|
pathString(0)
|
2007-07-20 14:36:31 +00:00
|
|
|
{ }
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
virtual IteratorImp* iterator() {
|
2010-11-05 19:18:28 +00:00
|
|
|
return new (allocator->allocate(sizeof(MyIterator)))
|
|
|
|
MyIterator(system, allocator, path_);
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
virtual System::FileType stat(const char* name, unsigned* length,
|
|
|
|
bool tryDirectory)
|
|
|
|
{
|
2007-09-17 00:13:36 +00:00
|
|
|
for (Element* e = path_; e; e = e->next) {
|
2010-11-05 19:18:28 +00:00
|
|
|
System::FileType type = e->stat(name, length, tryDirectory);
|
|
|
|
if (type != System::TypeDoesNotExist) {
|
|
|
|
return type;
|
2007-08-10 23:45:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
return System::TypeDoesNotExist;
|
2007-08-10 23:45:47 +00:00
|
|
|
}
|
|
|
|
|
2011-03-26 01:14:21 +00:00
|
|
|
virtual const char* urlPrefix(const char* name) {
|
2013-10-28 13:08:11 +00:00
|
|
|
void *finderElementPtr = NULL;
|
|
|
|
return nextUrlPrefix(name, finderElementPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual const char* nextUrlPrefix(const char* name,
|
|
|
|
void *&finderElementPtr)
|
|
|
|
{
|
|
|
|
Element *&e = reinterpret_cast<Element*&>(finderElementPtr);
|
|
|
|
e = e ? e->next : path_;
|
|
|
|
for (; e; e = e->next) {
|
2011-03-26 01:14:21 +00:00
|
|
|
unsigned length;
|
|
|
|
System::FileType type = e->stat(name, &length, true);
|
|
|
|
if (type != System::TypeDoesNotExist) {
|
|
|
|
return e->urlPrefix();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-04-01 01:16:57 +00:00
|
|
|
virtual const char* sourceUrl(const char* name) {
|
|
|
|
for (Element* e = path_; e; e = e->next) {
|
|
|
|
unsigned length;
|
|
|
|
System::FileType type = e->stat(name, &length, true);
|
|
|
|
if (type != System::TypeDoesNotExist) {
|
|
|
|
return e->sourceUrl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
2012-03-13 16:30:41 +00:00
|
|
|
if (pathString) {
|
|
|
|
allocator->free(pathString, strlen(pathString) + 1);
|
|
|
|
}
|
2010-11-05 19:18:28 +00:00
|
|
|
allocator->free(this, sizeof(*this));
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* system;
|
2010-11-05 19:18:28 +00:00
|
|
|
Allocator* allocator;
|
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 {
|
|
|
|
|
2013-11-08 15:35:10 +00:00
|
|
|
AVIAN_EXPORT Finder*
|
2010-11-05 19:18:28 +00:00
|
|
|
makeFinder(System* s, Allocator* a, const char* path, const char* bootLibrary)
|
|
|
|
{
|
|
|
|
return new (a->allocate(sizeof(MyFinder))) MyFinder(s, a, path, bootLibrary);
|
|
|
|
}
|
|
|
|
|
|
|
|
Finder*
|
|
|
|
makeFinder(System* s, Allocator* a, const uint8_t* jarData, unsigned jarLength)
|
2007-07-20 14:36:31 +00:00
|
|
|
{
|
2010-11-05 19:18:28 +00:00
|
|
|
return new (a->allocate(sizeof(MyFinder)))
|
|
|
|
MyFinder(s, a, jarData, jarLength);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vm
|