Skip to content

Instantly share code, notes, and snippets.

@allbinmani
Last active November 5, 2017 19:18
Show Gist options
  • Save allbinmani/e2846b2e19751850ba4fc2bf5b4eb001 to your computer and use it in GitHub Desktop.
Save allbinmani/e2846b2e19751850ba4fc2bf5b4eb001 to your computer and use it in GitHub Desktop.
GNU Rocket parser and binary/integer value converter
/**
rocket parser and binary/integer value converter
(c) 2017 orIgo / iNSANE^C!S
# Output File Format
The format can be made more compact, if required; if < 128 max keys with max 2 interpolation types, the interpolation type can be incorporated into the high bit of the row field.
Similarily, if less resolution is required for the value field, etc ..
Using 4 bytes per key feels reasonable to me, still leaving room for some future extensions.
## header
offset length meaning
0 2 Signature, "R1" (0x5231)
2 1 # of tracks (ntracks)
followed by, ntracks times:
0 1 length of track name (nlen)
1 nlen name of track, NOT \0 padded
1+nlen 2 # of keys, big endian (nkeys)
followed by, nkeys times:
0 1 row, 8 bit big endian
2 2 value, 16 bit big endian
4 1 interpolation type, 8 bit big endian (4 low bits used, 4 high bits for extensions)
# Interpolation Types
GNU Rocket defines
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <expat.h>
// Scaler multiplier for values
const static float SCALER = 255.0f;
// Some reasonable defaults
const static int MAX_KEYS = 256; // output file format currently supports 64k
const static int MAX_TRACKS = 32;
const static int MAX_NAME = 64;
typedef struct _key_t {
int row;
int interpolation;
int value;
} key_t;
typedef struct _track_t {
int nkeys;
char name[MAX_NAME];
key_t keys[MAX_KEYS];
} track_t;
track_t tracks[MAX_TRACKS];
static int ntracks = 0;
static int depth = 0;
void element_start(void *userData,
const XML_Char *name,
const XML_Char **atts)
{
int ai=0;
if(depth == 0 && strncmp(name, "sync", 4) == 0) {
// attributes: 'rows'
} else if(depth == 1 && strncmp(name, "tracks", 6) == 0) {
// attributes: none
} else if(depth == 2 && strncmp(name, "track", 5) == 0) {
// attributes: 'name'
while( atts[ai] != NULL && atts[ai+1] != NULL) {
if(strncmp(atts[ai], "nam", 3) == 0) {
strncpy(tracks[ntracks].name, atts[ai+1], MAX_NAME);
fprintf(stdout, "track: %s\n", &tracks[ntracks].name);
}
ai+=2;
}
} else if(depth == 3 && strncmp(name, "key", 3) == 0) {
// attributes: 'interpolation', 'value', 'row'
int row=0, interpolation=0, value=0;
key_t *key = &tracks[ntracks].keys[ tracks[ntracks].nkeys++ ];
while( atts[ai] != NULL && atts[ai+1] != NULL) {
if(strncmp(atts[ai], "row", 3) == 0) {
key->row = strtol(atts[ai+1], NULL, 10);
} else if(strncmp(atts[ai], "value", 3) == 0) {
key->value = (int)(strtof(atts[ai+1], NULL)*256.0f);
} else if(strncmp(atts[ai], "interpolation", 3) == 0) {
key->interpolation = strtol(atts[ai+1], NULL, 10);
}
ai+=2;
}
} else {
fprintf(stderr, "Unknown element at depth %d: %s\n", depth, name);
}
depth++;
}
void element_end(void *userData,
const XML_Char *name)
{
if(depth == 1 && strncmp(name, "sync", 4) == 0) {
} else if(depth == 2 && strncmp(name, "tracks", 6) == 0) {
} else if(depth == 3 && strncmp(name, "track", 5) == 0) {
ntracks++;
} else if(depth == 4 && strncmp(name, "key", 3) == 0) {
} else {
// fprintf(stderr, "Warning: unbalanced element at depth %d: %s\n", depth, name);
}
depth--;
}
int main(int argc, char **argv) {
XML_Parser parser = XML_ParserCreate("UTF-8");
if(argc != 3) {
fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
return 2;
}
FILE *fd = fopen(argv[1], "r");
if(!fd) {
perror("could not open input file");
return 1;
}
XML_SetElementHandler(parser,
element_start,
element_end);
char buf[1024];
int len;
while( (len = fread(&buf, 1, 1024, fd)) > 0 ) {
XML_Parse(parser, (const char *)&buf, len, len < sizeof(buf) ? 1 : 0);
}
fclose(fd);
XML_ParserFree(parser);
// Write output file
fd = fopen(argv[2], "wb");
if(!fd) {
perror("could not open output file");
return 1;
}
fputc('R', fd);
fputc('1', fd);
fputc(ntracks&0xff, fd);
for(int i=0; i < ntracks; i++) {
track_t *t = &tracks[i];
fputc(strlen(t->name), fd);
fwrite(t->name, 1, strlen(t->name), fd);
fputc(t->nkey>>8, fd);
fputc(t->nkeys&255, fd);
for(int j=0; j < t->nkeys; j++) {
key_t *k = &t->keys[j];
fputc(k->row&0xff, fd);
fputc(k->value>>8, fd);
fputc(k->value&0xff, fd);
fputc(k->interpolation, fd);
}
}
fclose(fd);
return 0;
}
@allbinmani
Copy link
Author

Compile with gcc -o rocket_parser rocket_parser.c -lexpat

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment