mirror of
https://github.com/corda/corda.git
synced 2025-06-21 00:23:09 +00:00
sketch of JAR support in Finder
This commit is contained in:
461
src/finder.cpp
461
src/finder.cpp
@ -1,8 +1,4 @@
|
||||
#include "sys/mman.h"
|
||||
#include "sys/types.h"
|
||||
#include "sys/stat.h"
|
||||
#include "fcntl.h"
|
||||
|
||||
#include "zlib.h"
|
||||
#include "system.h"
|
||||
#include "finder.h"
|
||||
|
||||
@ -32,7 +28,341 @@ copy(System* s, const char* a)
|
||||
return p;
|
||||
}
|
||||
|
||||
const char**
|
||||
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:
|
||||
Element(): next(0) { }
|
||||
virtual ~Element() { }
|
||||
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:
|
||||
DirectoryElement(System* s, const char* name):
|
||||
s(s), name(name)
|
||||
{ }
|
||||
|
||||
virtual System::Region* find(const char* name) {
|
||||
const char* file = append(s, this->name, "/", name);
|
||||
System::Region* region;
|
||||
System::Status status = s->map(®ion, file);
|
||||
s->free(file);
|
||||
|
||||
if (s->success(status)) {
|
||||
return region;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool exists(const char* name) {
|
||||
const char* file = append(s, this->name, "/", name);
|
||||
System::FileType type = s->identify(file);
|
||||
s->free(file);
|
||||
return type != System::DoesNotExist;
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
s->free(name);
|
||||
s->free(this);
|
||||
}
|
||||
|
||||
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() {
|
||||
s->free(this);
|
||||
}
|
||||
|
||||
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() {
|
||||
s->free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
size_t length_;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
class JarIndex {
|
||||
public:
|
||||
static const unsigned HeaderSize = 30;
|
||||
|
||||
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),
|
||||
nodes(static_cast<Node*>(s->allocate(sizeof(Node) * capacity))),
|
||||
zStream(0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static uint32_t compressionMethod(const uint8_t* p) {
|
||||
return get4(p + 8);
|
||||
}
|
||||
|
||||
static uint32_t compressedSize(const uint8_t* p) {
|
||||
return get4(p + 18);
|
||||
}
|
||||
|
||||
static uint32_t uncompressedSize(const uint8_t* p) {
|
||||
return get4(p + 22);
|
||||
}
|
||||
|
||||
static uint16_t fileNameLength(const uint8_t* p) {
|
||||
return get2(p + 26);
|
||||
}
|
||||
|
||||
static uint16_t extraFieldLength(const uint8_t* p) {
|
||||
return get2(p + 28);
|
||||
}
|
||||
|
||||
static const uint8_t* fileName(const uint8_t* p) {
|
||||
return p + 30;
|
||||
}
|
||||
|
||||
static JarIndex* make(System* s, unsigned capacity) {
|
||||
return new
|
||||
(s->allocate(sizeof(JarIndex) + (sizeof(Node*) * capacity)))
|
||||
JarIndex(s, capacity);
|
||||
}
|
||||
|
||||
static JarIndex* open(System* s, System::Region* region) {
|
||||
JarIndex* index = make(s, 32);
|
||||
|
||||
const uint8_t* p = region->start();
|
||||
const uint8_t* end = p + region->length();
|
||||
while (p < end) {
|
||||
if (signature(p) == 0x04034b50) {
|
||||
index = index->add(hash(fileName(p), fileNameLength(p)), p);
|
||||
|
||||
p += HeaderSize
|
||||
+ fileNameLength(p)
|
||||
+ extraFieldLength(p)
|
||||
+ compressedSize(p);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
System::Region* find(const char* name) {
|
||||
Node* n = findNode(name);
|
||||
if (n) {
|
||||
const uint8_t* p = n->entry;
|
||||
switch (compressionMethod(p)) {
|
||||
case Stored: {
|
||||
return new (s->allocate(sizeof(PointerRegion)))
|
||||
PointerRegion(s, p + fileNameLength(p) + extraFieldLength(p),
|
||||
compressedSize(p));
|
||||
} break;
|
||||
|
||||
case Deflated: {
|
||||
DataRegion* region = new
|
||||
(s->allocate(sizeof(DataRegion) + uncompressedSize(p)))
|
||||
DataRegion(s, uncompressedSize(p));
|
||||
|
||||
if (zStream == 0) {
|
||||
zStream = static_cast<z_stream*>(s->allocate(sizeof(z_stream)));
|
||||
memset(zStream, 0, sizeof(z_stream));
|
||||
int r = inflateInit(zStream);
|
||||
assert(s, r == Z_OK);
|
||||
}
|
||||
|
||||
zStream->next_in = const_cast<uint8_t*>
|
||||
(p + fileNameLength(p) + extraFieldLength(p));
|
||||
zStream->avail_in = compressedSize(p);
|
||||
zStream->next_out = region->data;
|
||||
zStream->avail_out = region->length();
|
||||
|
||||
int r = inflate(zStream, Z_SYNC_FLUSH);
|
||||
assert(s, r == Z_STREAM_END);
|
||||
} break;
|
||||
|
||||
default:
|
||||
abort(s);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool exists(const char* name) {
|
||||
return findNode(name) != 0;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
if (zStream) {
|
||||
inflateEnd(zStream);
|
||||
s->free(zStream);
|
||||
}
|
||||
s->free(nodes);
|
||||
s->free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
unsigned capacity;
|
||||
unsigned position;
|
||||
Node* nodes;
|
||||
z_stream* zStream;
|
||||
Node* table[0];
|
||||
};
|
||||
|
||||
class JarElement: public Element {
|
||||
public:
|
||||
JarElement(System* s, const char* name):
|
||||
s(s), name(name)
|
||||
{ }
|
||||
|
||||
void init() {
|
||||
if (index == 0) {
|
||||
System::Region* r;
|
||||
if (s->success(s->map(&r, this->name))) {
|
||||
region = r;
|
||||
index = JarIndex::open(s, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual System::Region* find(const char* name) {
|
||||
init();
|
||||
return (index ? index->find(name) : 0);
|
||||
}
|
||||
|
||||
virtual bool exists(const char* name) {
|
||||
init();
|
||||
return (index ? index->exists(name) : 0);
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
s->free(name);
|
||||
if (index) {
|
||||
index->dispose();
|
||||
region->dispose();
|
||||
}
|
||||
s->free(this);
|
||||
}
|
||||
|
||||
System* s;
|
||||
const char* name;
|
||||
System::Region* region;
|
||||
JarIndex* index;
|
||||
};
|
||||
|
||||
Element*
|
||||
parsePath(System* s, const char* path)
|
||||
{
|
||||
class Tokenizer {
|
||||
@ -62,24 +392,43 @@ parsePath(System* s, const char* path)
|
||||
char delimiter;
|
||||
};
|
||||
|
||||
unsigned count = 0;
|
||||
for (Tokenizer t(path, ':'); t.hasMore(); t.next()) ++ count;
|
||||
|
||||
const char** v = static_cast<const char**>
|
||||
(s->allocate((count + 1) * sizeof(const char*)));
|
||||
|
||||
unsigned i = 0;
|
||||
for (Tokenizer t(path, ':'); t.hasMore(); ++i) {
|
||||
Element* first = 0;
|
||||
Element* prev = 0;
|
||||
for (Tokenizer t(path, ':'); t.hasMore();) {
|
||||
Tokenizer::Token token(t.next());
|
||||
char* p = static_cast<char*>(s->allocate(token.length + 1));
|
||||
memcpy(p, token.s, token.length);
|
||||
p[token.length] = 0;
|
||||
v[i] = p;
|
||||
char* name = static_cast<char*>(s->allocate(token.length + 1));
|
||||
memcpy(name, token.s, token.length);
|
||||
name[token.length] = 0;
|
||||
|
||||
Element* e;
|
||||
switch (s->identify(name)) {
|
||||
case System::File: {
|
||||
e = new (s->allocate(sizeof(JarElement)))
|
||||
JarElement(s, name);
|
||||
} break;
|
||||
|
||||
case System::Directory: {
|
||||
e = new (s->allocate(sizeof(DirectoryElement)))
|
||||
DirectoryElement(s, name);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
s->free(name);
|
||||
e = 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (e) {
|
||||
if (prev) {
|
||||
prev->next = e;
|
||||
} else {
|
||||
first = e;
|
||||
}
|
||||
prev = e;
|
||||
}
|
||||
}
|
||||
|
||||
v[i] = 0;
|
||||
|
||||
return v;
|
||||
return first;
|
||||
}
|
||||
|
||||
class MyFinder: public Finder {
|
||||
@ -90,67 +439,20 @@ class MyFinder: public Finder {
|
||||
pathString(copy(system, path))
|
||||
{ }
|
||||
|
||||
class Data: public Finder::Data {
|
||||
public:
|
||||
Data(System* system, uint8_t* start, size_t length):
|
||||
system(system),
|
||||
start_(start),
|
||||
length_(length)
|
||||
{ }
|
||||
|
||||
virtual const uint8_t* start() {
|
||||
return start_;
|
||||
}
|
||||
|
||||
virtual size_t length() {
|
||||
return length_;
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
if (start_) {
|
||||
munmap(start_, length_);
|
||||
}
|
||||
system->free(this);
|
||||
}
|
||||
|
||||
System* system;
|
||||
uint8_t* start_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
virtual Data* find(const char* name) {
|
||||
Data* d = new (system->allocate(sizeof(Data))) Data(system, 0, 0);
|
||||
|
||||
for (const char** p = path_; *p; ++p) {
|
||||
const char* file = append(system, *p, "/", name);
|
||||
int fd = open(file, O_RDONLY);
|
||||
system->free(file);
|
||||
|
||||
if (fd != -1) {
|
||||
struct stat s;
|
||||
int r = fstat(fd, &s);
|
||||
if (r != -1) {
|
||||
void* data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (data) {
|
||||
d->start_ = static_cast<uint8_t*>(data);
|
||||
d->length_ = s.st_size;
|
||||
return d;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
system->free(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual bool exists(const char* name) {
|
||||
for (const char** p = path_; *p; ++p) {
|
||||
const char* file = append(system, *p, "/", name);
|
||||
struct stat s;
|
||||
int r = stat(file, &s);
|
||||
system->free(file);
|
||||
if (r == 0) {
|
||||
for (Element* e = path_; e; e = e->next) {
|
||||
if (e->exists(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -163,16 +465,17 @@ class MyFinder: public Finder {
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
for (const char** p = path_; *p; ++p) {
|
||||
system->free(*p);
|
||||
for (Element* e = path_; e;) {
|
||||
Element* t = e;
|
||||
e = e->next;
|
||||
t->dispose();
|
||||
}
|
||||
system->free(path_);
|
||||
system->free(pathString);
|
||||
system->free(this);
|
||||
}
|
||||
|
||||
System* system;
|
||||
const char** path_;
|
||||
Element* path_;
|
||||
const char* pathString;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user