13
0

lv2_pfile => rdff.

git-svn-id: svn://localhost/ardour2/branches/3.0@9221 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2011-03-29 02:10:57 +00:00
parent 2c0cd4d430
commit 09943e1d57
5 changed files with 176 additions and 179 deletions

View File

@ -1,121 +0,0 @@
/*
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.
*/
#ifndef LV2PFILE_H
#define LV2PFILE_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __GNUC__
# define PACKED __attribute__((__packed__))
#else
# define PACKED
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _LV2PFile* LV2PFile;
typedef struct _LV2PFile_Iterator* LV2PFile_Iterator;
typedef enum {
LV2_PFILE_OK = 0,
LV2_PFILE_UNKNOWN_ERROR = 1,
LV2_PFILE_EOF = 2,
LV2_PFILE_CORRUPT = 3
} LV2PFileStatus;
typedef struct {
char type[4];
uint32_t size;
char data[];
} PACKED LV2PFileChunkHeader;
typedef struct {
uint32_t id;
char uri[];
} PACKED LV2PFileURIChunk;
typedef struct {
uint32_t key;
uint32_t type;
uint32_t size;
char value[];
} PACKED LV2PFileValueChunk;
/**
Open/Create a new persist file.
*/
LV2PFile
lv2_pfile_open(const char* path, bool write);
/**
Write a URI ID to @a file.
*/
LV2PFileStatus
lv2_pfile_write_uri(LV2PFile file,
uint32_t id,
const char* uri,
uint32_t size);
/**
Write a key/value record to @a file.
*/
LV2PFileStatus
lv2_pfile_write_value(LV2PFile file,
uint32_t key,
const void* value,
uint32_t size,
uint32_t type);
LV2PFileStatus
lv2_pfile_read_chunk(LV2PFile file,
LV2PFileChunkHeader** buf);
/**
Read a record from a persist file.
@a key and @a value are allocated with malloc and must be freed by caller.
*/
#if 0
LV2PFileStatus
lv2_pfile_read(LV2PFile file,
char** key,
uint32_t* key_len,
char** type,
uint32_t* type_len,
void** value,
uint64_t* size);
#endif
/**
Close @a file.
After this call, @a file is invalid.
*/
void
lv2_pfile_close(LV2PFile file);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV2PFILE_H */

View File

@ -46,7 +46,7 @@
#include <locale.h> #include <locale.h>
#include "lv2ext/lv2_persist.h" #include "lv2ext/lv2_persist.h"
#include "lv2_pfile.h" #include "rdff.h"
#define NS_DC "http://dublincore.org/documents/dcmi-namespace/" #define NS_DC "http://dublincore.org/documents/dcmi-namespace/"
#define NS_LV2 "http://lv2plug.in/ns/lv2core#" #define NS_LV2 "http://lv2plug.in/ns/lv2core#"
@ -442,12 +442,12 @@ LV2Plugin::add_state(XMLNode* root) const
&state); &state);
// Open state file // Open state file
LV2PFile file = lv2_pfile_open(state_path.c_str(), true); RDFF file = rdff_open(state_path.c_str(), true);
// Write all referenced URIs to state file // Write all referenced URIs to state file
for (PersistState::URIs::const_iterator i = state.uris.begin(); for (PersistState::URIs::const_iterator i = state.uris.begin();
i != state.uris.end(); ++i) { i != state.uris.end(); ++i) {
lv2_pfile_write_uri(file, i->first, rdff_write_uri(file, i->first,
i->second.c_str(), i->second.length() + 1); i->second.c_str(), i->second.length() + 1);
} }
@ -456,7 +456,7 @@ LV2Plugin::add_state(XMLNode* root) const
i != state.values.end(); ++i) { i != state.values.end(); ++i) {
const uint32_t key = i->first; const uint32_t key = i->first;
const PersistValue& val = i->second; const PersistValue& val = i->second;
lv2_pfile_write_value(file, rdff_write_value(file,
key, key,
val.value, val.value,
val.size, val.size,
@ -464,7 +464,7 @@ LV2Plugin::add_state(XMLNode* root) const
} }
// Close state file // Close state file
lv2_pfile_close(file); rdff_close(file);
root->add_property("state-file", state_filename); root->add_property("state-file", state_filename);
} }
@ -631,21 +631,20 @@ LV2Plugin::set_state(const XMLNode& node, int version)
_instance, "http://lv2plug.in/ns/ext/persist"); _instance, "http://lv2plug.in/ns/ext/persist");
if (persist) { if (persist) {
cout << "Loading LV2 state from " << state_path << endl; cout << "Loading LV2 state from " << state_path << endl;
LV2PFile file = lv2_pfile_open(state_path.c_str(), false); RDFF file = rdff_open(state_path.c_str(), false);
PersistState state(_uri_map); PersistState state(_uri_map);
// Load file into state object // Load file into state object
LV2PFileChunkHeader* chunk = (LV2PFileChunkHeader*)malloc( RDFFChunk* chunk = (RDFFChunk*)malloc(sizeof(RDFFChunk));
sizeof(LV2PFileChunkHeader));
chunk->size = 0; chunk->size = 0;
while (!lv2_pfile_read_chunk(file, &chunk)) { while (!rdff_read_chunk(file, &chunk)) {
if (!strncmp(chunk->type, "URID", 4)) { if (!strncmp(chunk->type, "URID", 4)) {
LV2PFileURIChunk* body = (LV2PFileURIChunk*)chunk->data; RDFFURIChunk* body = (RDFFURIChunk*)chunk->data;
printf("READ URI %u: %s\n", body->id, body->uri); printf("READ URI %u: %s\n", body->id, body->uri);
state.add_uri(body->id, body->uri); state.add_uri(body->id, body->uri);
} else if (!strncmp(chunk->type, "KVAL", 4)) { } else if (!strncmp(chunk->type, "KVAL", 4)) {
LV2PFileValueChunk* body = (LV2PFileValueChunk*)chunk->data; RDFFValueChunk* body = (RDFFValueChunk*)chunk->data;
printf("READ VAL %u = %s (size: %u type: %u)\n", printf("READ VAL %u = %s (size: %u type: %u)\n",
body->key, body->value, body->size, body->type); body->key, body->value, body->size, body->type);
state.add_value(body->key, state.add_value(body->key,
@ -660,7 +659,7 @@ LV2Plugin::set_state(const XMLNode& node, int version)
persist->restore(_instance->lv2_handle, persist->restore(_instance->lv2_handle,
&LV2Plugin::lv2_persist_retrieve_callback, &LV2Plugin::lv2_persist_retrieve_callback,
&state); &state);
lv2_pfile_close(file); rdff_close(file);
} else { } else {
warning << string_compose( warning << string_compose(
_("Plugin \"%1\% failed to return LV2 persist data"), _("Plugin \"%1\% failed to return LV2 persist data"),

View File

@ -1,7 +1,5 @@
/* /*
Portable file-based LV2 Persist implementation. RDFF - RDF in RIFF
See <http://lv2plug.in/ns/ext/persist> for details.
Copyright 2011 David Robillard <http://drobilla.net> Copyright 2011 David Robillard <http://drobilla.net>
This is free software; you can redistribute it and/or modify it This is free software; you can redistribute it and/or modify it
@ -26,22 +24,22 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "lv2_pfile.h" #include "rdff.h"
#define CHUNK_ID_LEN 4 #define CHUNK_ID_LEN 4
static const char FILE_TYPE[CHUNK_ID_LEN] = "LV2F"; /* LV2 RIFF File */ static const char FILE_TYPE[CHUNK_ID_LEN] = "RDFF"; /* RDFF File ID */
static const char CHUNK_KVAL[CHUNK_ID_LEN] = "KVAL"; /* Key/Value Chunk */ static const char CHUNK_KVAL[CHUNK_ID_LEN] = "KVAL"; /* Key/Value Chunk ID */
static const char CHUNK_URID[CHUNK_ID_LEN] = "URID"; /* URI ID Chunk */ static const char CHUNK_URID[CHUNK_ID_LEN] = "URID"; /* URI-ID Chunk ID*/
struct _LV2PFile { struct _RDFF {
FILE* fd; FILE* fd;
uint32_t size; uint32_t size;
bool write; bool write;
}; };
LV2PFile RDFF
lv2_pfile_open(const char* path, bool write) rdff_open(const char* path, bool write)
{ {
FILE* fd = fopen(path, (write ? "w" : "r")); FILE* fd = fopen(path, (write ? "w" : "r"));
if (!fd) { if (!fd) {
@ -78,7 +76,7 @@ lv2_pfile_open(const char* path, bool write)
} }
} }
LV2PFile ret = (LV2PFile)malloc(sizeof(struct _LV2PFile)); RDFF ret = (RDFF)malloc(sizeof(struct _RDFF));
ret->fd = fd; ret->fd = fd;
ret->size = size; ret->size = size;
ret->write = write; ret->write = write;
@ -87,14 +85,14 @@ lv2_pfile_open(const char* path, bool write)
#define WRITE(ptr, size, nmemb, stream) \ #define WRITE(ptr, size, nmemb, stream) \
if (fwrite(ptr, size, nmemb, stream) != nmemb) { \ if (fwrite(ptr, size, nmemb, stream) != nmemb) { \
return LV2_PFILE_UNKNOWN_ERROR; \ return RDFF_STATUS_UNKNOWN_ERROR; \
} }
LV2PFileStatus RDFFStatus
lv2_pfile_write_uri(LV2PFile file, rdff_write_uri(RDFF file,
uint32_t id, uint32_t id,
const char* uri, const char* uri,
uint32_t len) uint32_t len)
{ {
const uint32_t chunk_size = sizeof(id) + len + 1; const uint32_t chunk_size = sizeof(id) + len + 1;
WRITE(CHUNK_URID, CHUNK_ID_LEN, 1, file->fd); WRITE(CHUNK_URID, CHUNK_ID_LEN, 1, file->fd);
@ -105,15 +103,15 @@ lv2_pfile_write_uri(LV2PFile file,
WRITE("", 1, 1, file->fd); /* pad */ WRITE("", 1, 1, file->fd); /* pad */
} }
file->size += 8 + chunk_size; file->size += 8 + chunk_size;
return LV2_PFILE_OK; return RDFF_STATUS_OK;
} }
LV2PFileStatus RDFFStatus
lv2_pfile_write_value(LV2PFile file, rdff_write_value(RDFF file,
uint32_t key, uint32_t key,
const void* value, const void* value,
uint32_t size, uint32_t size,
uint32_t type) uint32_t type)
{ {
const uint32_t chunk_size = sizeof(key) + sizeof(type) + sizeof(size) + size; const uint32_t chunk_size = sizeof(key) + sizeof(type) + sizeof(size) + size;
WRITE(CHUNK_KVAL, CHUNK_ID_LEN, 1, file->fd); WRITE(CHUNK_KVAL, CHUNK_ID_LEN, 1, file->fd);
@ -126,19 +124,19 @@ lv2_pfile_write_value(LV2PFile file,
WRITE("", 1, 1, file->fd); /* write pad */ WRITE("", 1, 1, file->fd); /* write pad */
} }
file->size += 8 + chunk_size; file->size += 8 + chunk_size;
return LV2_PFILE_OK; return RDFF_STATUS_OK;
} }
LV2PFileStatus RDFFStatus
lv2_pfile_read_chunk(LV2PFile file, rdff_read_chunk(RDFF file,
LV2PFileChunkHeader** buf) RDFFChunk** buf)
{ {
if (feof(file->fd)) if (feof(file->fd))
return LV2_PFILE_EOF; return RDFF_STATUS_EOF;
#define READ(ptr, size, nmemb, stream) \ #define READ(ptr, size, nmemb, stream) \
if (fread(ptr, size, nmemb, stream) != nmemb) { \ if (fread(ptr, size, nmemb, stream) != nmemb) { \
return LV2_PFILE_CORRUPT; \ return RDFF_STATUS_CORRUPT; \
} }
const uint32_t alloc_size = (*buf)->size; const uint32_t alloc_size = (*buf)->size;
@ -146,18 +144,18 @@ lv2_pfile_read_chunk(LV2PFile file,
READ((*buf)->type, sizeof((*buf)->type), 1, file->fd); READ((*buf)->type, sizeof((*buf)->type), 1, file->fd);
READ(&(*buf)->size, sizeof((*buf)->size), 1, file->fd); READ(&(*buf)->size, sizeof((*buf)->size), 1, file->fd);
if ((*buf)->size > alloc_size) { if ((*buf)->size > alloc_size) {
*buf = realloc(*buf, sizeof(LV2PFileChunkHeader) + (*buf)->size); *buf = realloc(*buf, sizeof(RDFFChunk) + (*buf)->size);
} }
READ((*buf)->data, (*buf)->size, 1, file->fd); READ((*buf)->data, (*buf)->size, 1, file->fd);
if (((*buf)->size % 2)) { if (((*buf)->size % 2)) {
char pad; char pad;
READ(&pad, 1, 1, file->fd); /* skip pad */ READ(&pad, 1, 1, file->fd); /* skip pad */
} }
return LV2_PFILE_OK; return RDFF_STATUS_OK;
} }
void void
lv2_pfile_close(LV2PFile file) rdff_close(RDFF file)
{ {
if (file) { if (file) {
if (file->write) { if (file->write) {
@ -184,7 +182,7 @@ main(int argc, char** argv)
const char* const filename = argv[1]; const char* const filename = argv[1];
LV2PFile file = lv2_pfile_open(filename, true); RDFF file = rdff_open(filename, true);
if (!file) if (!file)
goto fail; goto fail;
@ -194,54 +192,54 @@ main(int argc, char** argv)
char uri[64]; char uri[64];
for (int i = 0; i < N_URIS; ++i) { for (int i = 0; i < N_URIS; ++i) {
snprintf(uri, sizeof(uri), "http://example.org/uri%02d", i + 1); snprintf(uri, sizeof(uri), "http://example.org/uri%02d", i + 1);
lv2_pfile_write_uri(file, i + 1, uri, strlen(uri) + 1); rdff_write_uri(file, i + 1, uri, strlen(uri) + 1);
} }
char val[6]; char val[6];
for (int i = 0; i < N_RECORDS; ++i) { for (int i = 0; i < N_RECORDS; ++i) {
snprintf(val, sizeof(val), "VAL%02d", i); snprintf(val, sizeof(val), "VAL%02d", i);
lv2_pfile_write_value(file, rdff_write_value(file,
rand() % N_URIS, rand() % N_URIS,
val, val,
sizeof(val), sizeof(val),
0); 0);
} }
lv2_pfile_close(file); rdff_close(file);
file = lv2_pfile_open(filename, false); file = rdff_open(filename, false);
if (!file) if (!file)
goto fail; goto fail;
LV2PFileChunkHeader* chunk = malloc(sizeof(LV2PFileChunkHeader)); RDFFChunk* chunk = malloc(sizeof(RDFFChunk));
chunk->size = 0; chunk->size = 0;
for (int i = 0; i < N_URIS; ++i) { for (int i = 0; i < N_URIS; ++i) {
if (lv2_pfile_read_chunk(file, &chunk) if (rdff_read_chunk(file, &chunk)
|| strncmp(chunk->type, "URID", 4)) { || strncmp(chunk->type, "URID", 4)) {
fprintf(stderr, "error: expected URID chunk\n"); fprintf(stderr, "error: expected URID chunk\n");
goto fail; goto fail;
} }
LV2PFileURIChunk* body = (LV2PFileURIChunk*)chunk->data; RDFFURIChunk* body = (RDFFURIChunk*)chunk->data;
printf("URI: %s\n", body->uri); printf("URI: %s\n", body->uri);
} }
for (int i = 0; i < N_RECORDS; ++i) { for (int i = 0; i < N_RECORDS; ++i) {
if (lv2_pfile_read_chunk(file, &chunk) if (rdff_read_chunk(file, &chunk)
|| strncmp(chunk->type, "KVAL", 4)) { || strncmp(chunk->type, "KVAL", 4)) {
fprintf(stderr, "error: expected KVAL chunk\n"); fprintf(stderr, "error: expected KVAL chunk\n");
goto fail; goto fail;
} }
LV2PFileValueChunk* body = (LV2PFileValueChunk*)chunk->data; RDFFValueChunk* body = (RDFFValueChunk*)chunk->data;
printf("KEY %d = %s\n", body->key, body->value); printf("KEY %d = %s\n", body->key, body->value);
} }
free(chunk); free(chunk);
lv2_pfile_close(file); rdff_close(file);
return 0; return 0;
fail: fail:
lv2_pfile_close(file); rdff_close(file);
fprintf(stderr, "Test failed\n"); fprintf(stderr, "Test failed\n");
return 1; return 1;
} }

121
libs/ardour/rdff.h Normal file
View File

@ -0,0 +1,121 @@
/*
RDFF - RDF in RIFF
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.
*/
#ifndef RDFF_RDFF_H
#define RDFF_RDFF_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __GNUC__
# define PACKED __attribute__((__packed__))
#else
# define PACKED
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _RDFF* RDFF;
typedef enum {
RDFF_STATUS_OK = 0,
RDFF_STATUS_UNKNOWN_ERROR = 1,
RDFF_STATUS_EOF = 2,
RDFF_STATUS_CORRUPT = 3
} RDFFStatus;
/**
Generic RIFF chunk header.
*/
typedef struct {
char type[4];
uint32_t size;
char data[];
} PACKED RDFFChunk;
/**
Body of a URID chunk.
*/
typedef struct {
uint32_t id;
char uri[];
} PACKED RDFFURIChunk;
/**
Body of a KVAL chunk.
*/
typedef struct {
uint32_t key;
uint32_t type;
uint32_t size;
char value[];
} PACKED RDFFValueChunk;
/**
Open/Create a new RDFF file.
*/
RDFF
rdff_open(const char* path, bool write);
/**
Write a URI ID to @a file.
*/
RDFFStatus
rdff_write_uri(RDFF file,
uint32_t id,
const char* uri,
uint32_t len);
/**
Write a key/value record to @a file.
*/
RDFFStatus
rdff_write_value(RDFF file,
uint32_t key,
const void* value,
uint32_t size,
uint32_t type);
/**
Read a chunk from @a file.
@param buf MUST point to an RDFFChunk dynamically allocated with malloc.
The @a size field (i.e. (*buf)->size) MUST be set to the amount of available
memory in the chunk (not including the header). If this is insufficient,
*buf will be resized using realloc.
*/
RDFFStatus
rdff_read_chunk(RDFF file,
RDFFChunk** buf);
/**
Close @a file.
After this call, @a file is invalid.
*/
void
rdff_close(RDFF file);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* RDFF_RDFF_H */

View File

@ -327,7 +327,7 @@ def build(bld):
#obj.add_objects = 'default/libs/surfaces/control_protocol/smpte_1.o' #obj.add_objects = 'default/libs/surfaces/control_protocol/smpte_1.o'
if bld.env['HAVE_SLV2']: if bld.env['HAVE_SLV2']:
obj.source += [ 'lv2_plugin.cc', 'lv2_event_buffer.cc', 'uri_map.cc', 'lv2_pfile.c' ] obj.source += [ 'lv2_plugin.cc', 'lv2_event_buffer.cc', 'uri_map.cc', 'rdff.c' ]
obj.uselib += ' SLV2 ' + ' RASQAL ' obj.uselib += ' SLV2 ' + ' RASQAL '
if bld.env['VST_SUPPORT']: if bld.env['VST_SUPPORT']: