diff options
Diffstat (limited to 'libs/ardour/lv2_pfile.c')
-rw-r--r-- | libs/ardour/lv2_pfile.c | 233 |
1 files changed, 149 insertions, 84 deletions
diff --git a/libs/ardour/lv2_pfile.c b/libs/ardour/lv2_pfile.c index f5c1c02a78..cdf14b2ed2 100644 --- a/libs/ardour/lv2_pfile.c +++ b/libs/ardour/lv2_pfile.c @@ -1,21 +1,24 @@ -/* Portable file-based implementation of LV2 Persist. - * See <http://lv2plug.in/ns/ext/persist> for details. - * Copyright (C) 2010 David Robillard <http://drobilla.net> - * - * This file is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This file is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this file; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ +/* + Portable file-based LV2 Persist implementation. + See <http://lv2plug.in/ns/ext/persist> for details. + + Copyright 2011 David Robillard <http://drobilla.net> + + This is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This software is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this sofware; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + 02110-1301 USA. +*/ #include <assert.h> #include <errno.h> @@ -25,8 +28,16 @@ #include "lv2_pfile.h" +#define CHUNK_ID_LEN 4 + +static const char FILE_TYPE[CHUNK_ID_LEN] = "LV2F"; /* LV2 RIFF File */ +static const char CHUNK_KVAL[CHUNK_ID_LEN] = "KVAL"; /* Key/Value Chunk */ +static const char CHUNK_URID[CHUNK_ID_LEN] = "URID"; /* URI ID Chunk */ + struct _LV2PFile { - FILE* fd; + FILE* fd; + uint32_t size; + bool write; }; LV2PFile @@ -38,88 +49,125 @@ lv2_pfile_open(const char* path, bool write) return NULL; } - static const char* const magic = "LV2PFILE"; - static const size_t magic_len = 8; + uint32_t size = 0; + if (write) { - fwrite(magic, magic_len, 1, fd); + fwrite("RIFF", CHUNK_ID_LEN, 1, fd); /* RIFF chunk ID */ + fwrite(&size, sizeof(size), 1, fd); /* RIFF chunk size */ + fwrite(FILE_TYPE, CHUNK_ID_LEN, 1, fd); /* LV2 RIFF file type */ } else { - char file_magic[magic_len]; - if (fread(file_magic, magic_len, 1, fd) != 1 - || strncmp(file_magic, magic, magic_len)) { + char magic[CHUNK_ID_LEN]; + if (fread(magic, CHUNK_ID_LEN, 1, fd) != 1 + || strncmp(magic, "RIFF", CHUNK_ID_LEN)) { + fclose(fd); + fprintf(stderr, "%s: error: not a RIFF file\n", path); + return NULL; + } + + if (fread(&size, sizeof(size), 1, fd) != 1) { + fclose(fd); + fprintf(stderr, "%s: error: missing RIFF chunk size\n", path); + return NULL; + } + + if (fread(magic, CHUNK_ID_LEN, 1, fd) != 1 + || strncmp(magic, FILE_TYPE, CHUNK_ID_LEN)) { fclose(fd); + fprintf(stderr, "%s: error: not an LV2 RIFF file\n", path); return NULL; } } - LV2PFile ret = (LV2PFile)malloc(sizeof(LV2PFile)); - ret->fd = fd; + LV2PFile ret = (LV2PFile)malloc(sizeof(struct _LV2PFile)); + ret->fd = fd; + ret->size = size; + ret->write = write; return ret; } -LV2PFileStatus -lv2_pfile_write(LV2PFile file, - const char* key, - const void* value, - uint64_t size, - const char* type) -{ #define WRITE(ptr, size, nmemb, stream) \ if (fwrite(ptr, size, nmemb, stream) != nmemb) { \ return LV2_PFILE_UNKNOWN_ERROR; \ } - const uint32_t key_len = strlen(key); - WRITE(&key_len, sizeof(key_len), 1, file->fd); - WRITE(key, key_len + 1, 1, file->fd); - - const uint32_t type_len = strlen(type); - WRITE(&type_len, sizeof(type_len), 1, file->fd); - WRITE(type, type_len + 1, 1, file->fd); - - WRITE(&size, sizeof(size), 1, file->fd); - WRITE(value, size, 1, file->fd); +LV2PFileStatus +lv2_pfile_write_uri(LV2PFile file, + uint32_t id, + const char* uri, + uint32_t len) +{ + const uint32_t chunk_size = sizeof(id) + len + 1; + WRITE(CHUNK_URID, CHUNK_ID_LEN, 1, file->fd); + WRITE(&chunk_size, sizeof(chunk_size), 1, file->fd); + WRITE(&id, sizeof(id), 1, file->fd); + WRITE(uri, len + 1, 1, file->fd); + if ((chunk_size % 2)) { + WRITE("", 1, 1, file->fd); /* pad */ + } + file->size += 8 + chunk_size; + return LV2_PFILE_OK; +} +LV2PFileStatus +lv2_pfile_write_value(LV2PFile file, + uint32_t key, + const void* value, + uint32_t size, + uint32_t type) +{ + const uint32_t chunk_size = sizeof(key) + sizeof(type) + sizeof(size) + size; + WRITE(CHUNK_KVAL, CHUNK_ID_LEN, 1, file->fd); + WRITE(&chunk_size, sizeof(chunk_size), 1, file->fd); + WRITE(&key, sizeof(key), 1, file->fd); + WRITE(&type, sizeof(type), 1, file->fd); + WRITE(&size, sizeof(size), 1, file->fd); + WRITE(value, size, 1, file->fd); + if ((size % 2)) { + WRITE("", 1, 1, file->fd); /* write pad */ + } + file->size += 8 + chunk_size; return LV2_PFILE_OK; } LV2PFileStatus -lv2_pfile_read(LV2PFile file, - char** key, - uint32_t* key_len, - char** type, - uint32_t* type_len, - void** value, - uint64_t* size) +lv2_pfile_read_chunk(LV2PFile file, + LV2PFileChunkHeader** buf) { if (feof(file->fd)) return LV2_PFILE_EOF; #define READ(ptr, size, nmemb, stream) \ if (fread(ptr, size, nmemb, stream) != nmemb) { \ - assert(false); \ return LV2_PFILE_CORRUPT; \ } - READ(key_len, sizeof(*key_len), 1, file->fd); - *key = (char*)malloc(*key_len + 1); - READ(*key, *key_len + 1, 1, file->fd); - - READ(type_len, sizeof(*type_len), 1, file->fd); - *type = (char*)malloc(*type_len + 1); - READ(*type, *type_len + 1, 1, file->fd); - - READ(size, sizeof(*size), 1, file->fd); - *value = malloc(*size); - READ(*value, *size, 1, file->fd); + const uint32_t alloc_size = (*buf)->size; + READ((*buf)->type, sizeof((*buf)->type), 1, file->fd); + READ(&(*buf)->size, sizeof((*buf)->size), 1, file->fd); + if ((*buf)->size > alloc_size) { + *buf = realloc(*buf, sizeof(LV2PFileChunkHeader) + (*buf)->size); + } + READ((*buf)->data, (*buf)->size, 1, file->fd); + if (((*buf)->size % 2)) { + char pad; + READ(&pad, 1, 1, file->fd); /* skip pad */ + } return LV2_PFILE_OK; } void lv2_pfile_close(LV2PFile file) { - if (file) + if (file) { + if (file->write) { + fseek(file->fd, 4, SEEK_SET); + if (fwrite(&file->size, sizeof(file->size), 1, file->fd) != 1) { + fprintf(stderr, "failed to write RIFF header size\n"); + } + } fclose(file->fd); + } free(file); } @@ -140,14 +188,23 @@ main(int argc, char** argv) if (!file) goto fail; - char wkey[6]; - char wval[6]; - const char* wtype = "http://example.org/type"; -#define NUM_RECORDS 32 - for (int i = 0; i < NUM_RECORDS; ++i) { - snprintf(wkey, sizeof(wkey), "KEY%02d", i); - snprintf(wval, sizeof(wval), "VAL%02d", i); - lv2_pfile_write(file, wkey, wval, strlen(wval) + 1, wtype); + static const int N_URIS = 16; + static const int N_RECORDS = 16; + + char uri[64]; + for (int i = 0; i < N_URIS; ++i) { + snprintf(uri, sizeof(uri), "http://example.org/uri%02d", i + 1); + lv2_pfile_write_uri(file, i + 1, uri, strlen(uri) + 1); + } + + char val[6]; + for (int i = 0; i < N_RECORDS; ++i) { + snprintf(val, sizeof(val), "VAL%02d", i); + lv2_pfile_write_value(file, + rand() % N_URIS, + val, + sizeof(val), + 0); } lv2_pfile_close(file); @@ -156,23 +213,31 @@ main(int argc, char** argv) if (!file) goto fail; - char* rkey; - uint32_t rkey_len; - char* rtype; - uint32_t rtype_len; - uint64_t rsize; - void* rval; - for (int i = 0; i < NUM_RECORDS; ++i) { - if (lv2_pfile_read(file, &rkey, &rkey_len, &rtype, &rtype_len, &rval, &rsize)) + LV2PFileChunkHeader* chunk = malloc(sizeof(LV2PFileChunkHeader)); + chunk->size = 0; + for (int i = 0; i < N_URIS; ++i) { + if (lv2_pfile_read_chunk(file, &chunk) + || strncmp(chunk->type, "URID", 4)) { + fprintf(stderr, "error: expected URID chunk\n"); goto fail; + } + LV2PFileURIChunk* body = (LV2PFileURIChunk*)chunk->data; + printf("URI: %s\n", body->uri); + } - printf("%s = %s :: %s\n", rkey, (char*)rval, rtype); - free(rkey); - free(rtype); - free(rval); + for (int i = 0; i < N_RECORDS; ++i) { + if (lv2_pfile_read_chunk(file, &chunk) + || strncmp(chunk->type, "KVAL", 4)) { + fprintf(stderr, "error: expected KVAL chunk\n"); + goto fail; + } + LV2PFileValueChunk* body = (LV2PFileValueChunk*)chunk->data; + printf("KEY %d = %s\n", body->key, body->value); } + free(chunk); lv2_pfile_close(file); + return 0; fail: |