#include "libloc-private.h"
#include "stringpool.h"
+enum loc_stringpool_mode {
+ STRINGPOOL_DEFAULT,
+ STRINGPOOL_MMAP,
+};
+
struct loc_stringpool {
struct loc_ctx* ctx;
-
int refcount;
+
+ enum loc_stringpool_mode mode;
+
char* data;
- char* pos;
+ ssize_t length;
- ssize_t max_length;
+ char* pos;
};
-static int loc_stringpool_deallocate(struct loc_stringpool* pool) {
- if (pool->data) {
- int r = munmap(pool->data, pool->max_length);
- if (r) {
- ERROR(pool->ctx, "Could not unmap data at %p: %s\n",
- pool->data, strerror(errno));
+static int __loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool, enum loc_stringpool_mode mode) {
+ struct loc_stringpool* p = calloc(1, sizeof(*p));
+ if (!p)
+ return -ENOMEM;
+
+ p->ctx = loc_ref(ctx);
+ p->refcount = 1;
- return r;
- }
- }
+ // Save mode
+ p->mode = mode;
+
+ *pool = p;
return 0;
}
-static int loc_stringpool_allocate(struct loc_stringpool* pool, size_t length) {
- // Drop old data
- int r = loc_stringpool_deallocate(pool);
- if (r)
- return r;
+LOC_EXPORT int loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool) {
+ return __loc_stringpool_new(ctx, pool, STRINGPOOL_DEFAULT);
+}
- pool->max_length = length;
+static int loc_stringpool_mmap(struct loc_stringpool* pool, FILE* f, size_t length, off_t offset) {
+ if (pool->mode != STRINGPOOL_MMAP)
+ return -EINVAL;
- // Align to page size
- while (pool->max_length % sysconf(_SC_PAGE_SIZE) > 0)
- pool->max_length++;
+ DEBUG(pool->ctx, "Reading string pool starting from %zu (%zu bytes)\n", offset, length);
- DEBUG(pool->ctx, "Allocating pool of %zu bytes\n", pool->max_length);
+ // Map file content into memory
+ pool->data = pool->pos = mmap(NULL, length, PROT_READ,
+ MAP_PRIVATE, fileno(f), offset);
- // Allocate some memory
- pool->data = pool->pos = mmap(NULL, pool->max_length,
- PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ // Store size of section
+ pool->length = length;
- if (pool->data == MAP_FAILED) {
- DEBUG(pool->ctx, "%s\n", strerror(errno));
+ if (pool->data == MAP_FAILED)
return -errno;
- }
-
- DEBUG(pool->ctx, "Allocated pool at %p\n", pool->data);
return 0;
}
-LOC_EXPORT int loc_stringpool_new(struct loc_ctx* ctx, struct loc_stringpool** pool, size_t max_length) {
- struct loc_stringpool* p = calloc(1, sizeof(*p));
- if (!p)
- return -ENOMEM;
-
- p->ctx = loc_ref(ctx);
- p->refcount = 1;
-
- // Allocate the data section
- if (max_length > 0) {
- int r = loc_stringpool_allocate(p, max_length);
- if (r) {
- loc_stringpool_unref(p);
- return r;
- }
- }
+LOC_EXPORT int loc_stringpool_open(struct loc_ctx* ctx, struct loc_stringpool** pool,
+ FILE* f, size_t length, off_t offset) {
+ int r = __loc_stringpool_new(ctx, pool, STRINGPOOL_MMAP);
+ if (r)
+ return r;
- DEBUG(p->ctx, "String pool allocated at %p\n", p);
- DEBUG(p->ctx, " Maximum size: %zu bytes\n", p->max_length);
- *pool = p;
+ // Map data into memory
+ r = loc_stringpool_mmap(*pool, f, length, offset);
+ if (r)
+ return r;
return 0;
}
static void loc_stringpool_free(struct loc_stringpool* pool) {
DEBUG(pool->ctx, "Releasing string pool %p\n", pool);
+ int r;
+
+ switch (pool->mode) {
+ case STRINGPOOL_DEFAULT:
+ if (pool->data)
+ free(pool->data);
+ break;
+
+ case STRINGPOOL_MMAP:
+ if (pool->data) {
+ r = munmap(pool->data, pool->length);
+ if (r)
+ ERROR(pool->ctx, "Could not unmap data at %p: %s\n",
+ pool->data, strerror(errno));
+ }
+ break;
+ }
- loc_stringpool_deallocate(pool);
loc_unref(pool->ctx);
free(pool);
}
if (pos < pool->data)
return -EFAULT;
- if (pos > (pool->data + pool->max_length))
+ if (pos > (pool->data + pool->length))
return -EFAULT;
return pos - pool->data;
return offset + strlen(string) + 1;
}
-static size_t loc_stringpool_space_left(struct loc_stringpool* pool) {
- return pool->max_length - loc_stringpool_get_size(pool);
-}
-
-LOC_EXPORT const char* loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
- if (offset >= (ssize_t)pool->max_length)
+static char* __loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
+ if (offset < 0 || offset >= pool->length)
return NULL;
- const char* string = pool->data + offset;
-
- // If the string is empty, we have reached the end
- if (!*string)
- return NULL;
+ return pool->data + offset;
+}
- return string;
+LOC_EXPORT const char* loc_stringpool_get(struct loc_stringpool* pool, off_t offset) {
+ return __loc_stringpool_get(pool, offset);
}
LOC_EXPORT size_t loc_stringpool_get_size(struct loc_stringpool* pool) {
return -EINVAL;
off_t offset = 0;
- while (offset < pool->max_length) {
+ while (offset < pool->length) {
const char* string = loc_stringpool_get(pool, offset);
if (!string)
break;
return -ENOENT;
}
+static int loc_stringpool_grow(struct loc_stringpool* pool, size_t length) {
+ DEBUG(pool->ctx, "Growing string pool to %zu bytes\n", length);
+
+ // Save pos pointer
+ off_t pos = loc_stringpool_get_offset(pool, pool->pos);
+
+ // Reallocate data section
+ pool->data = realloc(pool->data, length);
+ if (!pool->data)
+ return -ENOMEM;
+
+ pool->length = length;
+
+ // Restore pos
+ pool->pos = __loc_stringpool_get(pool, pos);
+
+ return 0;
+}
+
static off_t loc_stringpool_append(struct loc_stringpool* pool, const char* string) {
if (!string || !*string)
return -EINVAL;
DEBUG(pool->ctx, "Appending '%s' to string pool at %p\n", string, pool);
- // Check if we have enough space left
- size_t l = strlen(string) + 1;
- if (l > loc_stringpool_space_left(pool)) {
- DEBUG(pool->ctx, "Not enough space to append '%s'\n", string);
- DEBUG(pool->ctx, " Need %zu bytes but only have %zu\n", l, loc_stringpool_space_left(pool));
- return -ENOSPC;
+ // Make sure we have enough space
+ int r = loc_stringpool_grow(pool, pool->length + strlen(string) + 1);
+ if (r) {
+ errno = r;
+ return -1;
}
off_t offset = loc_stringpool_get_offset(pool, pool->pos);
// Copy string byte by byte
- while (*string && loc_stringpool_space_left(pool) > 1) {
+ while (*string)
*pool->pos++ = *string++;
- }
// Terminate the string
*pool->pos++ = '\0';
LOC_EXPORT void loc_stringpool_dump(struct loc_stringpool* pool) {
off_t offset = 0;
- while (offset < pool->max_length) {
+ while (offset < pool->length) {
const char* string = loc_stringpool_get(pool, offset);
if (!string)
break;
}
}
-LOC_EXPORT int loc_stringpool_read(struct loc_stringpool* pool, FILE* f, off_t offset, size_t length) {
- DEBUG(pool->ctx, "Reading string pool from %zu (%zu bytes)\n", offset, length);
-
- pool->data = pool->pos = mmap(NULL, length, PROT_READ,
- MAP_PRIVATE, fileno(f), offset);
- pool->max_length = length;
-
- if (pool->data == MAP_FAILED)
- return -errno;
-
- return 0;
-}
-
LOC_EXPORT size_t loc_stringpool_write(struct loc_stringpool* pool, FILE* f) {
size_t size = loc_stringpool_get_size(pool);