/** * Parse a comment in with "slash splat" or double slash notation, * leave the reader on the first character after the last end of comment mark. */ static inline int parseComment(struct Reader* reader) { char chars[2]; int ret = Reader_read(reader, &chars, 2); if (ret) { printf("Warning: expected comment\n"); return OUT_OF_CONTENT_TO_READ; } if (chars[0] != '/') { printf("Warning: expected a comment starting with '/', instead found '%c'\n",chars[0]); return UNPARSABLE; } switch (chars[1]) { case '*':; do { readUntil('*', reader); } while (!(ret = Reader_read(reader, &chars, 1)) && chars[0] != '/'); if (ret) { printf("Unterminated multiline comment\n"); return OUT_OF_CONTENT_TO_READ; } return 0; case '/':; return readUntil('\n', reader); default: printf("Warning: expected a comment starting with \"//\" or \"/*\", " "instead found \"/%c\"\n",chars[1]); return UNPARSABLE; } }
static inline int parseString(struct Reader* reader, struct Allocator* allocator, String** output) { #define BUFF_SZ (1<<8) #define BUFF_MAX (1<<20) int curSize = BUFF_SZ; struct Allocator* localAllocator = Allocator_child(allocator); uint8_t* buffer = Allocator_malloc(localAllocator, curSize); if (readUntil('"', reader) || Reader_read(reader, buffer, 1)) { printf("Unterminated string\n"); Allocator_free(localAllocator); return OUT_OF_CONTENT_TO_READ; } for (int i = 0; i < BUFF_MAX - 1; i++) { if (buffer[i] == '\\') { // \x01 (skip the x) Reader_skip(reader, 1); uint8_t hex[2]; if (Reader_read(reader, (char*)hex, 2)) { printf("Unexpected end of input parsing escape sequence\n"); Allocator_free(localAllocator); return OUT_OF_CONTENT_TO_READ; } int byte = Hex_decodeByte(hex[0], hex[1]); if (byte == -1) { printf("Invalid escape \"%c%c\" after \"%.*s\"\n",hex[0],hex[1],i+1,buffer); Allocator_free(localAllocator); return UNPARSABLE; } buffer[i] = (uint8_t) byte; } else if (buffer[i] == '"') { *output = String_newBinary((char*)buffer, i, allocator); Allocator_free(localAllocator); return 0; } if (i == curSize - 1) { curSize <<= 1; buffer = Allocator_realloc(localAllocator, buffer, curSize); } if (Reader_read(reader, buffer + i + 1, 1)) { if (i+1 <= 20) { printf("Unterminated string \"%.*s\"\n", i+1, buffer); } else { printf("Unterminated string starting with \"%.*s...\"\n", 20, buffer); } Allocator_free(localAllocator); return OUT_OF_CONTENT_TO_READ; } } printf("Maximum string length of %d bytes exceeded.\n",BUFF_SZ); Allocator_free(localAllocator); return UNPARSABLE; #undef BUFF_SZ #undef BUFF_MAX }
/** @see BencSerializer.h */ static int32_t parseString(struct Reader* reader, struct Allocator* allocator, String** output) { #define OUT_OF_CONTENT_TO_READ -2 #define UNPARSABLE -3 /* Strings longer than 1*10^21-1 represent numbers definitly larger than uint64. */ #define NUMBER_MAXLENGTH 21 char number[32]; char nextChar; int ret; /* Parse the size of the string. */ size_t i = 0; for (i = 0; ; i++) { ret = Reader_read(reader, &nextChar, 1); if (ret != 0) { return OUT_OF_CONTENT_TO_READ; } if (nextChar == ':') { /* Found the separator. */ break; } if (nextChar < '0' || nextChar > '9') { /* Invalid character. */ return UNPARSABLE; } if (i >= NUMBER_MAXLENGTH) { /* Massive huge number. */ return UNPARSABLE; } number[i] = nextChar; } number[i] = '\0'; size_t length = strtoul(number, NULL, 10); char* bytes = Allocator_malloc(allocator, length + 1); String* string = Allocator_malloc(allocator, sizeof(String)); /* Put a null terminator after the end so it can be treated as a normal string. */ bytes[length] = '\0'; if (Reader_read(reader, bytes, length) != 0) { return OUT_OF_CONTENT_TO_READ; } string->bytes = bytes; string->len = length; *output = string; return 0; #undef OUT_OF_CONTENT_TO_READ #undef UNPARSABLE #undef NUMBER_MAXLENGTH }
/** @see BencSerializer.h */ static int32_t parseList(struct Reader* reader, struct Allocator* allocator, List* output) { #define OUT_OF_CONTENT_TO_READ -2 #define UNPARSABLE -3 char nextChar; if (Reader_read(reader, &nextChar, 1) != 0) { return OUT_OF_CONTENT_TO_READ; } if (nextChar != 'l') { return UNPARSABLE; } Object* element; struct List_Item* thisEntry = NULL; struct List_Item** lastEntryPointer = output; int ret; if (Reader_read(reader, &nextChar, 0) != 0) { return OUT_OF_CONTENT_TO_READ; } *lastEntryPointer = NULL; while (nextChar != 'e') { ret = parseGeneric(reader, allocator, &element); if (ret != 0) { return ret; } thisEntry = Allocator_malloc(allocator, sizeof(struct List_Item)); thisEntry->elem = element; /* Read backwards so that the list reads out forward. */ *lastEntryPointer = thisEntry; lastEntryPointer = &(thisEntry->next); if (Reader_read(reader, &nextChar, 0) != 0) { return OUT_OF_CONTENT_TO_READ; } } if (thisEntry) { thisEntry->next = NULL; } /* move the pointer to after the 'e' at the end of the list. */ Reader_skip(reader, 1); return 0; #undef OUT_OF_CONTENT_TO_READ #undef UNPARSABLE }
static ALuint read_le32(Reader *stream) { ALubyte buf[4]; if(Reader_read(stream, buf, 4) != 4) return 0; return (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0]; }
static ALushort read_le16(Reader *stream) { ALubyte buf[2]; if(Reader_read(stream, buf, 2) != 2) return 0; return (buf[1]<<8) | buf[0]; }
static ALubyte read_8(Reader *stream) { ALubyte buf[1]; if(Reader_read(stream, buf, 1) != 1) return 0; return buf[0]; }
/** @see BencSerializer.h */ static int32_t parseDictionary(struct Reader* reader, struct Allocator* allocator, Dict* output) { uint8_t nextChar; readUntil('{', reader); String* key; Object* value; struct Dict_Entry* entryPointer; struct Dict_Entry* lastEntryPointer = NULL; int ret = 0; for (;;) { while (!ret) { ret = Reader_read(reader, &nextChar, 0); switch (nextChar) { case '"': break; case '}': Reader_skip(reader, 1); *output = lastEntryPointer; return 0; case '/': parseComment(reader); continue; default: Reader_skip(reader, 1); continue; } break; } if (ret) { printf("Unterminated dictionary\n"); return OUT_OF_CONTENT_TO_READ; } // Get key and value. if ((ret = parseString(reader, allocator, &key)) != 0) { return ret; } readUntil(':', reader); if ((ret = parseGeneric(reader, allocator, &value)) != 0) { return ret; } /* Allocate the entry. */ entryPointer = Allocator_malloc(allocator, sizeof(struct Dict_Entry)); entryPointer->next = lastEntryPointer; entryPointer->key = key; entryPointer->val = value; lastEntryPointer = entryPointer; } }
/** @see BencSerializer.h */ static int32_t parseint64_t(struct Reader* reader, int64_t* output) { uint8_t buffer[32]; for (int i = 0; i < 21; i++) { int32_t status = Reader_read(reader, buffer + i, 0); if (i == 0 && buffer[i] == '-' && status == 0) { // It's just a negative number, no need to fail it. continue; } if (buffer[i] < '0' || buffer[i] > '9' || status != 0 /* end of input */) { buffer[i] = '\0'; int64_t out = strtol((char*)buffer, NULL, 10); // Failed parse causes 0 to be set. if (out == 0 && buffer[0] != '0' && (buffer[0] != '-' || buffer[1] != '0')) { printf("Failed to parse \"%s\": not a number\n",buffer); return UNPARSABLE; } if ((out == INT64_MAX || out == INT64_MIN) && errno == ERANGE) { printf("Failed to parse \"%s\": number too large/small\n",buffer); return UNPARSABLE; } *output = out; return 0; } Reader_skip(reader, 1); } // Larger than the max possible int64. buffer[22] = '\0'; printf("Failed to parse \"%s\": number too large\n",buffer); return UNPARSABLE; }
int main() { struct Allocator* alloc = MallocAllocator_new(1024); struct Random* rand = Random_new(alloc, NULL, NULL); FILE* tmp = tmpfile(); uint8_t buffer1[2048]; size_t checkSize; Random_bytes(rand, buffer1, 2048); checkSize = fwrite(buffer1, 1, 2048, tmp); if (checkSize != 2048) { return 1; } uint8_t buffer2[1024]; rewind(tmp); struct Reader* r = FileReader_new(tmp, alloc); Reader_read(r, buffer2, 128); Reader_skip(r, 128); Reader_read(r, buffer2+128, 128); Reader_skip(r, 512); Reader_read(r, buffer2+128+128, 256); Reader_skip(r, 300); Reader_read(r, buffer2+128+128+256, 128); Assert_true(r->bytesRead == 128+128+128+512+256+300+128); uint8_t* ptr1 = buffer1; uint8_t* ptr2 = buffer2; #define SKIP(x) ptr1 += x #define CMP(x) Assert_true(!Bits_memcmp(ptr1, ptr2, x)); ptr1 += x; ptr2 += x CMP(128); SKIP(128); CMP(128); SKIP(512); CMP(256); SKIP(300); CMP(128); Allocator_free(alloc); return 0; }
static void skip(Reader *stream, ALuint amt) { while(amt > 0 && !READERR(stream)) { char buf[4096]; amt -= Reader_read(stream, buf, minu(sizeof(buf), amt)); } }
static void PresetHeader_read(PresetHeader *self, Reader *stream) { Reader_read(stream, self->mName, sizeof(self->mName)); self->mPreset = read_le16(stream); self->mBank = read_le16(stream); self->mZoneIdx = read_le16(stream); self->mLibrary = read_le32(stream); self->mGenre = read_le32(stream); self->mMorphology = read_le32(stream); }
/** * Read until 1 char after the target character. */ static inline int readUntil(uint8_t target, struct Reader* reader) { uint8_t nextChar; do { if (Reader_read(reader, (char*)&nextChar, 1)) { printf("Unexpected end of input while looking for '%c'\n",target); return OUT_OF_CONTENT_TO_READ; } } while (nextChar != target); return 0; }
/** @see BencSerializer.h */ static int32_t parseint64_t(struct Reader* reader, int64_t* output) { #define OUT_OF_CONTENT_TO_READ -2 #define UNPARSABLE -3 char buffer[32]; int i; for (i = 0; ; i++) { if (Reader_read(reader, buffer + i, 1) != 0) { return OUT_OF_CONTENT_TO_READ; } if (i == 0) { if (buffer[i] != 'i') { /* Not an int. */ return UNPARSABLE; } else { continue; } } if (buffer[i] == 'e') { break; } if (i == 1 && buffer[i] == '-') { /* It's just a negative number, no need to fail it. */ continue; } if (buffer[i] < '0' || buffer[i] > '9') { return UNPARSABLE; } if (i > 21) { /* Larger than the max possible int64. */ return UNPARSABLE; } } /* buffer + 1, skip the 'i' */ int64_t out = strtol(buffer + 1, NULL, 10); /* Failed parse causes 0 to be set. */ if (out == 0 && buffer[1] != '0' && (buffer[1] != '-' || buffer[2] != '0')) { return UNPARSABLE; } if ((out == LONG_MAX || out == LONG_MIN) && errno == ERANGE) { /* errno (holds nose) */ return UNPARSABLE; } *output = out; return 0; #undef OUT_OF_CONTENT_TO_READ #undef UNPARSABLE }
static void SampleHeader_read(SampleHeader *self, Reader *stream) { Reader_read(stream, self->mName, sizeof(self->mName)); self->mStart = read_le32(stream); self->mEnd = read_le32(stream); self->mStartloop = read_le32(stream); self->mEndloop = read_le32(stream); self->mSampleRate = read_le32(stream); self->mOriginalKey = read_8(stream); self->mCorrection = read_8(stream); self->mSampleLink = read_le16(stream); self->mSampleType = read_le16(stream); }
struct VersionList* VersionList_parse(String* str, struct Allocator* alloc) { const uint8_t numberSize = str->bytes[0]; if (str->len < 1 || numberSize == 0 || numberSize > 4) { return NULL; } uint32_t length = (str->len - 1) / numberSize; if ((length * numberSize) != (str->len - 1)) { return NULL; } struct VersionList* list = VersionList_new(length, alloc); struct Reader* r = ArrayReader_new(str->bytes + 1, str->len - 1, alloc); for (int i = 0; i < (int)list->length; i++) { uint32_t ver = 0; Reader_read(r, (uint8_t*) &ver, numberSize); ver = Endian_bigEndianToHost32(ver); list->versions[i] = ver >> ((4-numberSize) * 8); } return list; }
static void InstrumentHeader_read(InstrumentHeader *self, Reader *stream) { Reader_read(stream, self->mName, sizeof(self->mName)); self->mZoneIdx = read_le16(stream); }
/** @see BencSerializer.h */ static int32_t parseList(struct Reader* reader, struct Allocator* allocator, List* output) { char nextChar; readUntil('[', reader); Object* element; struct List_Item* thisEntry = NULL; struct List_Item** lastEntryPointer = output; int ret; for (;;) { for (;;) { if (Reader_read(reader, &nextChar, 0) != 0) { printf("Unterminated list\n"); return OUT_OF_CONTENT_TO_READ; } if (nextChar == '/') { if ((ret = parseComment(reader)) != 0) { return ret; } continue; } switch (nextChar) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '[': case '{': case '"': break; case ']': Reader_skip(reader, 1); return 0; default: // FIXME: silently skipping anything we don't understand // might not be the best idea Reader_skip(reader, 1); continue; } break; } if ((ret = parseGeneric(reader, allocator, &element)) != 0) { return ret; } thisEntry = Allocator_malloc(allocator, sizeof(struct List_Item)); thisEntry->elem = element; thisEntry->next = NULL; // Read backwards so that the list reads out forward. *lastEntryPointer = thisEntry; lastEntryPointer = &(thisEntry->next); } }
/** * Parse an unknown data type. * This is not exposed to the world because it is expected that one would * know what type they are parsing to begin with. This is used by parseDictionary * and parseList to grab pieces of data which are of unknown type and parse them. * * @param reader the reader to get the stream of data from. * @param allocator the means of storing the parsed data. * @param output a pointer which will be pointed to the output. */ static int32_t parseGeneric(struct Reader* reader, struct Allocator* allocator, Object** output) { #define OUT_OF_CONTENT_TO_READ -2 #define UNPARSABLE -3 int ret; char firstChar; ret = Reader_read(reader, &firstChar, 0); if (ret != 0) { return OUT_OF_CONTENT_TO_READ; } Object* out = Allocator_malloc(allocator, sizeof(Object)); if (firstChar <= '9' && firstChar >= '0') { /* It's a string! */ String* string = NULL; ret = parseString(reader, allocator, &string); out->type = Object_STRING; out->as.string = string; } else { switch (firstChar) { case 'i':; /* int64_t. Int is special because it is not a pointer but a int64_t. */ int64_t bint = 0; ret = parseint64_t(reader, &bint); out->type = Object_INTEGER; out->as.number = bint; break; case 'l':; /* List. */ List* list = Allocator_calloc(allocator, sizeof(List), 1); ret = parseList(reader, allocator, list); out->type = Object_LIST; out->as.list = list; break; case 'd':; /* Dictionary. */ Dict* dict = Allocator_calloc(allocator, sizeof(Dict), 1); ret = parseDictionary(reader, allocator, dict); out->type = Object_DICT; out->as.dictionary = dict; break; default: return UNPARSABLE; } } if (ret != 0) { /* Something went wrong while parsing. */ return ret; } *output = out; return 0; #undef OUT_OF_CONTENT_TO_READ #undef UNPARSABLE }
/** @see BencSerializer.h */ static int32_t parseDictionary(struct Reader* reader, struct Allocator* allocator, Dict* output) { #define OUT_OF_CONTENT_TO_READ -2 #define UNPARSABLE -3 char nextChar; if (Reader_read(reader, &nextChar, 1) < 0) { return OUT_OF_CONTENT_TO_READ; } if (nextChar != 'd') { /* Not a dictionary. */ return UNPARSABLE; } String* key; Object* value; struct Dict_Entry* entryPointer; struct Dict_Entry* lastEntryPointer = NULL; int ret; for (;;) { /* Peek at the next char. */ if (Reader_read(reader, &nextChar, 0) < 0) { /* Ran over read buffer. */ return OUT_OF_CONTENT_TO_READ; } if (nextChar == 'e') { /* Got to the end. */ break; } /* Get key and value. */ ret = parseString(reader, allocator, &key); if (ret != 0) { return ret; } ret = parseGeneric(reader, allocator, &value); if (ret != 0) { return ret; } /* Allocate the entry. */ entryPointer = Allocator_malloc(allocator, sizeof(struct Dict_Entry)); entryPointer->next = lastEntryPointer; entryPointer->key = key; entryPointer->val = value; lastEntryPointer = entryPointer; } /* We got an 'e', leave the pointer on the next char after it. */ Reader_skip(reader, 1); *output = lastEntryPointer; return 0; #undef OUT_OF_CONTENT_TO_READ #undef UNPARSABLE }
static int32_t parseGeneric(struct Reader* reader, struct Allocator* allocator, Object** output) { int ret = 0; char firstChar; for (;;) { ret = Reader_read(reader, &firstChar, 0); switch (firstChar) { case ' ': case '\r': case '\n': case '\t': Reader_skip(reader, 1); continue; case '/':; if ((ret = parseComment(reader)) != 0) { return ret; } continue; default: break; } if (ret) { printf("Unexpected end of input\n"); return OUT_OF_CONTENT_TO_READ; } break; } Object* out = Allocator_malloc(allocator, sizeof(Object)); switch (firstChar) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':; // int64_t. Int is special because it is not a pointer but a int64_t. int64_t bint; if ((ret = parseint64_t(reader, &bint)) == UNPARSABLE) { break; } out->type = Object_INTEGER; out->as.number = bint; break; case '[':; // List. List* list = Allocator_calloc(allocator, sizeof(List), 1); ret = parseList(reader, allocator, list); out->type = Object_LIST; out->as.list = list; break; case '{':; // Dictionary Dict* dict = Allocator_calloc(allocator, sizeof(Dict), 1); ret = parseDictionary(reader, allocator, dict); out->type = Object_DICT; out->as.dictionary = dict; break; case '"':; // String String* string = NULL; ret = parseString(reader, allocator, &string); out->type = Object_STRING; out->as.string = string; break; default: printf("While looking for something to parse: " "expected one of 0 1 2 3 4 5 6 7 8 9 [ { \", found '%c'\n", firstChar); return UNPARSABLE; } if (ret != 0) { // Something went wrong while parsing. return ret; } *output = out; return 0; }