Last active
November 5, 2017 19:18
-
-
Save allbinmani/e2846b2e19751850ba4fc2bf5b4eb001 to your computer and use it in GitHub Desktop.
GNU Rocket parser and binary/integer value converter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Compile with
gcc -o rocket_parser rocket_parser.c -lexpat