ardour
rdff.c
Go to the documentation of this file.
1 /*
2  RDFF - RDF in RIFF
3  Copyright 2011 David Robillard <http://drobilla.net>
4 
5  Permission to use, copy, modify, and/or distribute this software for any
6  purpose with or without fee is hereby granted, provided that the above
7  copyright notice and this permission notice appear in all copies.
8 
9  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 
18 #include <assert.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "rdff.h"
25 
26 #define CHUNK_ID_LEN 4
27 
28 static const char FILE_TYPE[CHUNK_ID_LEN] = "RDFF"; /* RDFF File ID */
29 static const char CHUNK_TRIP[CHUNK_ID_LEN] = "trip"; /* Triple Chunk ID */
30 static const char CHUNK_URID[CHUNK_ID_LEN] = "urid"; /* URI-ID Chunk ID*/
31 
32 struct _RDFF {
33  FILE* fd;
34  uint32_t size;
35  bool write;
36 };
37 
38 RDFF
39 rdff_open(const char* path, bool write)
40 {
41  FILE* fd = fopen(path, (write ? "w" : "r"));
42  if (!fd) {
43  fprintf(stderr, "%s\n", strerror(errno));
44  return NULL;
45  }
46 
47  uint32_t size = 0;
48 
49  if (write) {
50  fwrite("RIFF", CHUNK_ID_LEN, 1, fd); /* RIFF chunk ID */
51  fwrite(&size, sizeof(size), 1, fd); /* RIFF chunk size */
52  fwrite(FILE_TYPE, CHUNK_ID_LEN, 1, fd); /* File type */
53  } else {
54  char magic[CHUNK_ID_LEN];
55  if (fread(magic, CHUNK_ID_LEN, 1, fd) != 1
56  || strncmp(magic, "RIFF", CHUNK_ID_LEN)) {
57  fclose(fd);
58  fprintf(stderr, "%s: error: not a RIFF file\n", path);
59  return NULL;
60  }
61 
62  if (fread(&size, sizeof(size), 1, fd) != 1) {
63  fclose(fd);
64  fprintf(stderr, "%s: error: missing RIFF chunk size\n", path);
65  return NULL;
66  }
67 
68  if (fread(magic, CHUNK_ID_LEN, 1, fd) != 1
69  || strncmp(magic, FILE_TYPE, CHUNK_ID_LEN)) {
70  fclose(fd);
71  fprintf(stderr, "%s: error: not an %s RIFF file\n",
72  FILE_TYPE, path);
73  return NULL;
74  }
75  }
76 
77  RDFF ret = (RDFF)malloc(sizeof(struct _RDFF));
78  ret->fd = fd;
79  ret->size = size;
80  ret->write = write;
81  return ret;
82 }
83 
84 #define WRITE(ptr, size, nmemb, stream) \
85  if (fwrite(ptr, size, nmemb, stream) != nmemb) { \
86  return RDFF_STATUS_UNKNOWN_ERROR; \
87  }
88 
91  uint32_t id,
92  uint32_t len,
93  const char* uri)
94 {
95  const uint32_t chunk_size = sizeof(id) + len + 1;
96  WRITE(CHUNK_URID, CHUNK_ID_LEN, 1, file->fd);
97  WRITE(&chunk_size, sizeof(chunk_size), 1, file->fd);
98  WRITE(&id, sizeof(id), 1, file->fd);
99  WRITE(uri, len + 1, 1, file->fd);
100  if ((chunk_size % 2)) {
101  WRITE("", 1, 1, file->fd); /* pad */
102  }
103  file->size += 8 + chunk_size;
104  return RDFF_STATUS_OK;
105 }
106 
109  uint32_t subject,
110  uint32_t predicate,
111  uint32_t object_type,
112  uint32_t object_size,
113  const void* object)
114 {
115  const uint32_t chunk_size = sizeof(RDFFTripleChunk) + object_size;
116  WRITE(CHUNK_TRIP, CHUNK_ID_LEN, 1, file->fd);
117  WRITE(&chunk_size, sizeof(chunk_size), 1, file->fd);
118  WRITE(&subject, sizeof(subject), 1, file->fd);
119  WRITE(&predicate, sizeof(predicate), 1, file->fd);
120  WRITE(&object_type, sizeof(object_type), 1, file->fd);
121  WRITE(&object_size, sizeof(object_size), 1, file->fd);
122  WRITE(object, object_size, 1, file->fd);
123  if ((object_size % 2)) {
124  WRITE("", 1, 1, file->fd); /* write pad */
125  }
126  file->size += 8 + chunk_size;
127  return RDFF_STATUS_OK;
128 }
129 
132  RDFFChunk** buf)
133 {
134  if (feof(file->fd))
135  return RDFF_STATUS_EOF;
136 
137 #define READ(ptr, size, nmemb, stream) \
138  if (fread(ptr, size, nmemb, stream) != nmemb) { \
139  return RDFF_STATUS_CORRUPT; \
140  }
141 
142  const uint32_t alloc_size = (*buf)->size;
143 
144  READ((*buf)->type, sizeof((*buf)->type), 1, file->fd);
145  READ(&(*buf)->size, sizeof((*buf)->size), 1, file->fd);
146  if ((*buf)->size > alloc_size) {
147  *buf = realloc(*buf, sizeof(RDFFChunk) + (*buf)->size);
148  }
149  READ((*buf)->data, (*buf)->size, 1, file->fd);
150  if (((*buf)->size % 2)) {
151  char pad;
152  READ(&pad, 1, 1, file->fd); /* skip pad */
153  }
154  return RDFF_STATUS_OK;
155 }
156 
157 bool
158 rdff_chunk_is_uri(RDFFChunk* chunk)
159 
160 {
161  return !strncmp(chunk->type, CHUNK_URID, CHUNK_ID_LEN);
162 }
163 
164 bool
165 rdff_chunk_is_triple(RDFFChunk* chunk)
166 {
167  return !strncmp(chunk->type, CHUNK_TRIP, CHUNK_ID_LEN);
168 }
169 
170 void
172 {
173  if (file) {
174  if (file->write) {
175  fseek(file->fd, 4, SEEK_SET);
176  if (fwrite(&file->size, sizeof(file->size), 1, file->fd) != 1) {
177  fprintf(stderr, "failed to write RIFF header size\n");
178  }
179  }
180  fclose(file->fd);
181  }
182 
183  free(file);
184 }
185 
186 #ifdef STANDALONE
187 // Test program
188 int
189 main(int argc, char** argv)
190 {
191  if (argc != 2) {
192  fprintf(stderr, "Usage: %s FILENAME\n", argv[0]);
193  return 1;
194  }
195 
196  const char* const filename = argv[1];
197 
198  RDFF file = rdff_open(filename, true);
199  if (!file)
200  goto fail;
201 
202  static const int N_URIS = 16;
203  static const int N_RECORDS = 16;
204 
205  char uri[64];
206  for (int i = 0; i < N_URIS; ++i) {
207  snprintf(uri, sizeof(uri), "http://example.org/uri%02d", i + 1);
208  rdff_write_uri(file, i + 1, strlen(uri), uri);
209  }
210 
211  char val[6];
212  for (int i = 0; i < N_RECORDS; ++i) {
213  snprintf(val, sizeof(val), "VAL%02d", i);
214  rdff_write_triple(file,
215  0,
216  rand() % N_URIS,
217  0,
218  sizeof(val),
219  val);
220  }
221 
222  rdff_close(file);
223 
224  file = rdff_open(filename, false);
225  if (!file)
226  goto fail;
227 
228  RDFFChunk* chunk = malloc(sizeof(RDFFChunk));
229  chunk->size = 0;
230  for (int i = 0; i < N_URIS; ++i) {
231  if (rdff_read_chunk(file, &chunk)
232  || strncmp(chunk->type, CHUNK_URID, 4)) {
233  fprintf(stderr, "error: expected %s chunk\n", CHUNK_URID);
234  goto fail;
235  }
236  RDFFURIChunk* body = (RDFFURIChunk*)chunk->data;
237  printf("URI: %s\n", body->uri);
238  }
239 
240  for (int i = 0; i < N_RECORDS; ++i) {
241  if (rdff_read_chunk(file, &chunk)
242  || strncmp(chunk->type, CHUNK_TRIP, 4)) {
243  fprintf(stderr, "error: expected %s chunk\n", CHUNK_TRIP);
244  goto fail;
245  }
246  RDFFTripleChunk* body = (RDFFTripleChunk*)chunk->data;
247  printf("KEY %d = %s\n", body->predicate, body->object);
248  }
249 
250  free(chunk);
251  rdff_close(file);
252 
253  return 0;
254 
255 fail:
256  rdff_close(file);
257  fprintf(stderr, "Test failed\n");
258  return 1;
259 }
260 #endif // STANDALONE
bool rdff_chunk_is_triple(RDFFChunk *chunk)
Definition: rdff.c:165
const char magic[]
bool rdff_chunk_is_uri(RDFFChunk *chunk)
Definition: rdff.c:158
#define WRITE(ptr, size, nmemb, stream)
Definition: rdff.c:84
int main(int argc, char *argv[])
Definition: load_session.cc:14
static const char CHUNK_URID[CHUNK_ID_LEN]
Definition: rdff.c:30
uint32_t size
Definition: rdff.c:34
RDFF rdff_open(const char *path, bool write)
Definition: rdff.c:39
RDFFStatus
Definition: rdff.h:42
RDFFStatus rdff_read_chunk(RDFF file, RDFFChunk **buf)
Definition: rdff.c:131
Definition: rdff.c:32
struct _RDFF * RDFF
Definition: rdff.h:37
#define READ(ptr, size, nmemb, stream)
RDFFStatus rdff_write_triple(RDFF file, uint32_t subject, uint32_t predicate, uint32_t object_type, uint32_t object_size, const void *object)
Definition: rdff.c:108
FILE * fd
Definition: rdff.c:33
RDFFStatus rdff_write_uri(RDFF file, uint32_t id, uint32_t len, const char *uri)
Definition: rdff.c:90
void rdff_close(RDFF file)
Definition: rdff.c:171
#define CHUNK_ID_LEN
Definition: rdff.c:26
static const char FILE_TYPE[CHUNK_ID_LEN]
Definition: rdff.c:28
static const char CHUNK_TRIP[CHUNK_ID_LEN]
Definition: rdff.c:29
bool write
Definition: rdff.c:35