diff options
Diffstat (limited to 'libs/lmo/src/lmo_core.c')
-rw-r--r-- | libs/lmo/src/lmo_core.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/libs/lmo/src/lmo_core.c b/libs/lmo/src/lmo_core.c new file mode 100644 index 0000000000..b3cb7c0989 --- /dev/null +++ b/libs/lmo/src/lmo_core.c @@ -0,0 +1,231 @@ +/* + * lmo - Lua Machine Objects - Base functions + * + * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lmo.h" + +extern char _lmo_error[1024]; + +static int lmo_read32( int fd, uint32_t *val ) +{ + uint8_t buffer[5]; + + if( read(fd, buffer, 4) < 4 ) + return -1; + + buffer[4] = 0; + *val = ntohl(*((uint32_t *) buffer)); + + return 4; +} + +static char * error(const char *message, int add_errno) +{ + memset(_lmo_error, 0, sizeof(_lmo_error)); + + if( add_errno ) + snprintf(_lmo_error, sizeof(_lmo_error), + "%s: %s", message, strerror(errno)); + else + snprintf(_lmo_error, sizeof(_lmo_error), "%s", message); + + return NULL; +} + +const char * lmo_error(void) +{ + return _lmo_error; +} + +lmo_archive_t * lmo_open(const char *file) +{ + int in = -1; + uint32_t idx_offset = 0; + uint32_t i; + struct stat s; + + lmo_archive_t *ar = NULL; + lmo_entry_t *head = NULL; + lmo_entry_t *entry = NULL; + + if( stat(file, &s) == -1 ) + { + error("Can not stat file", 1); + goto cleanup; + } + + if( (in = open(file, O_RDONLY)) == -1 ) + { + error("Can not open file", 1); + goto cleanup; + } + + if( lseek(in, -sizeof(uint32_t), SEEK_END) == -1 ) + { + error("Can not seek to eof", 1); + goto cleanup; + } + + if( lmo_read32(in, &idx_offset) != 4 ) + { + error("Unexpected EOF while reading index offset", 0); + goto cleanup; + } + + if( lseek(in, idx_offset, SEEK_SET) == -1 ) + { + error("Can not seek to index offset", 1); + goto cleanup; + } + + if( (ar = (lmo_archive_t *) malloc(sizeof(lmo_archive_t))) != NULL ) + { + ar->fd = in; + ar->length = idx_offset; + + for( i = idx_offset; + i < (s.st_size - sizeof(uint32_t)); + i += (4 * sizeof(uint32_t)) + ) { + if( (entry = (lmo_entry_t *) malloc(sizeof(lmo_entry_t))) != NULL ) + { + if( (lmo_read32(ar->fd, &entry->key_id) == 4) && + (lmo_read32(ar->fd, &entry->val_id) == 4) && + (lmo_read32(ar->fd, &entry->offset) == 4) && + (lmo_read32(ar->fd, &entry->length) == 4) + ) { + entry->next = head; + head = entry; + } + else + { + error("Unexpected EOF while reading index entry", 0); + goto cleanup; + } + } + else + { + error("Out of memory", 0); + goto cleanup; + } + } + + ar->index = head; + + if( lseek(ar->fd, 0, SEEK_SET) == -1 ) + { + error("Can not seek to start", 1); + goto cleanup; + } + + if( (ar->mmap = mmap(NULL, ar->length, PROT_READ, MAP_SHARED, ar->fd, 0)) == MAP_FAILED ) + { + error("Failed to memory map archive contents", 1); + goto cleanup; + } + + return ar; + } + else + { + error("Out of memory", 0); + goto cleanup; + } + + + cleanup: + + if( in > -1 ) + close(in); + + if( head != NULL ) + { + entry = head; + + while( entry != NULL ) + { + head = entry->next; + free(entry); + entry = head; + } + + head = entry = NULL; + } + + if( ar != NULL ) + { + if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) ) + munmap(ar->mmap, ar->length); + + free(ar); + ar = NULL; + } + + return NULL; +} + +void lmo_close(lmo_archive_t *ar) +{ + lmo_entry_t *head = NULL; + lmo_entry_t *entry = NULL; + + if( ar != NULL ) + { + entry = ar->index; + + while( entry != NULL ) + { + head = entry->next; + free(entry); + entry = head; + } + + head = entry = NULL; + + if( (ar->mmap != NULL) && (ar->mmap != MAP_FAILED) ) + munmap(ar->mmap, ar->length); + + close(ar->fd); + free(ar); + + ar = NULL; + } +} + +int lmo_lookup(lmo_archive_t *ar, const char *key, char *dest, int len) +{ + uint32_t look_key = sfh_hash(key, strlen(key)); + int copy_len = -1; + + lmo_entry_t *entry = ar->index; + + while( entry != NULL ) + { + if( entry->key_id == look_key ) + { + copy_len = (len > entry->length) ? entry->length : len; + memcpy(dest, &ar->mmap[entry->offset], copy_len); + + break; + } + + entry = entry->next; + } + + return copy_len; +} + |