3 Copyright 2011 David Robillard <http://drobilla.net>
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.
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.
26 #define CHUNK_ID_LEN 4
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*/
39 rdff_open(const char* path
, bool write
)
41 FILE* fd
= fopen(path
, (write
? "w" : "r"));
43 fprintf(stderr
, "%s\n", strerror(errno
));
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 */
54 char magic
[CHUNK_ID_LEN
];
55 if (fread(magic
, CHUNK_ID_LEN
, 1, fd
) != 1
56 || strncmp(magic
, "RIFF", CHUNK_ID_LEN
)) {
58 fprintf(stderr
, "%s: error: not a RIFF file\n", path
);
62 if (fread(&size
, sizeof(size
), 1, fd
) != 1) {
64 fprintf(stderr
, "%s: error: missing RIFF chunk size\n", path
);
68 if (fread(magic
, CHUNK_ID_LEN
, 1, fd
) != 1
69 || strncmp(magic
, FILE_TYPE
, CHUNK_ID_LEN
)) {
71 fprintf(stderr
, "%s: error: not an %s RIFF file\n",
77 RDFF ret
= (RDFF
)malloc(sizeof(struct _RDFF
));
84 #define WRITE(ptr, size, nmemb, stream) \
85 if (fwrite(ptr, size, nmemb, stream) != nmemb) { \
86 return RDFF_STATUS_UNKNOWN_ERROR; \
90 rdff_write_uri(RDFF file
,
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 */
103 file
->size
+= 8 + chunk_size
;
104 return RDFF_STATUS_OK
;
108 rdff_write_triple(RDFF file
,
111 uint32_t object_type
,
112 uint32_t object_size
,
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 */
126 file
->size
+= 8 + chunk_size
;
127 return RDFF_STATUS_OK
;
131 rdff_read_chunk(RDFF file
,
135 return RDFF_STATUS_EOF
;
137 #define READ(ptr, size, nmemb, stream) \
138 if (fread(ptr, size, nmemb, stream) != nmemb) { \
139 return RDFF_STATUS_CORRUPT; \
142 const uint32_t alloc_size
= (*buf
)->size
;
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
);
149 READ((*buf
)->data
, (*buf
)->size
, 1, file
->fd
);
150 if (((*buf
)->size
% 2)) {
152 READ(&pad
, 1, 1, file
->fd
); /* skip pad */
154 return RDFF_STATUS_OK
;
158 rdff_chunk_is_uri(RDFFChunk
* chunk
)
161 return !strncmp(chunk
->type
, CHUNK_URID
, CHUNK_ID_LEN
);
165 rdff_chunk_is_triple(RDFFChunk
* chunk
)
167 return !strncmp(chunk
->type
, CHUNK_TRIP
, CHUNK_ID_LEN
);
171 rdff_close(RDFF file
)
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");
189 main(int argc
, char** argv
)
192 fprintf(stderr
, "Usage: %s FILENAME\n", argv
[0]);
196 const char* const filename
= argv
[1];
198 RDFF file
= rdff_open(filename
, true);
202 static const int N_URIS
= 16;
203 static const int N_RECORDS
= 16;
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
);
212 for (int i
= 0; i
< N_RECORDS
; ++i
) {
213 snprintf(val
, sizeof(val
), "VAL%02d", i
);
214 rdff_write_triple(file
,
224 file
= rdff_open(filename
, false);
228 RDFFChunk
* chunk
= malloc(sizeof(RDFFChunk
));
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
);
236 RDFFURIChunk
* body
= (RDFFURIChunk
*)chunk
->data
;
237 printf("URI: %s\n", body
->uri
);
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
);
246 RDFFTripleChunk
* body
= (RDFFTripleChunk
*)chunk
->data
;
247 printf("KEY %d = %s\n", body
->predicate
, body
->object
);
257 fprintf(stderr
, "Test failed\n");