diff options
| author | johannes <johannes.herman@gmail.com> | 2024-02-06 12:29:41 +0100 |
|---|---|---|
| committer | johannes <johannes.herman@gmail.com> | 2024-02-06 12:29:41 +0100 |
| commit | 0ab2c0afc6fd192f4008962ef400b92434e2dc2d (patch) | |
| tree | 31ff61e1945850048ac6b82f23cb428d62e0cb70 | |
| parent | 1bdee2153953e23bf71f7a5e83145bb4d67db567 (diff) | |
added read snap and read tick
| -rw-r--r-- | inc/demo.h | 83 | ||||
| -rw-r--r-- | inc/pack.h | 10 | ||||
| -rw-r--r-- | src/demo.c | 186 | ||||
| -rw-r--r-- | src/main.c | 40 | ||||
| -rw-r--r-- | src/pack.c | 35 |
5 files changed, 344 insertions, 10 deletions
@@ -9,10 +9,10 @@ typedef struct unsigned char version; char netversion[64]; char mapname[64]; - unsigned char mapsize[4]; // Big endian int - unsigned char mapcrc[4]; // Big endian int + unsigned char mapsize[4]; // Big endian int + unsigned char mapcrc[4]; // Big endian int char type[8]; - unsigned char length[4]; // Big endian int + unsigned char length[4]; // Big endian int char timestamp[20]; } demoheader; @@ -22,13 +22,84 @@ typedef struct char data[260]; } demotimeline; +/* demomap struct */ +typedef struct +{ + unsigned char sha256[32]; + unsigned char *data; +} demomap; + +typedef struct +{ + unsigned short type; + unsigned short id; + int numdata; + int *data; +} demosnapitem; + +/* Chunk types */ +typedef struct +{ + int datasize; + int numitems; + int *offsets; + demosnapitem *items; +} demosnap; + +typedef struct +{ + char keyframe; + char innline; + int delta; +} demotick; + +typedef struct +{ +} demodelta; + +typedef struct +{ +} demomessage; + +/* union for different chunks */ +typedef union { + demosnap *snap; + demotick *tick; + demodelta *delta; + demomessage *message; +} chunkdata; + +/* demochunk struct */ +typedef struct +{ + unsigned char type; + chunkdata data; +} demochunk; + +/* demodata struct, stores all chunks */ +typedef struct +{ + int numchunks; + demochunk *chunks; +} demodata; + /* Read demo header from demofile into given demoheader */ /* Returns a positive number on success, negative on fail */ -int readdemoheader(FILE *demofile, demoheader *demoheader); +int readdemoheader(FILE *demofile, demoheader *header); /* Read demo timeline from demofile into given demoheader */ /* Returns a positive number on success, negative on fail */ /* Must have read the header from demofile beforehand */ -int readdemotimeline(FILE *demofile, demotimeline *demotimeline); +int readdemotimeline(FILE *demofile, demotimeline *timeline); + +/* Read demo map from demofile into given demomap */ +/* Returns a positive number on success, negative on fail */ +/* Must have read the demoheader and demotimeline beforehand */ +int readdemomap(FILE *demofile, demomap *map, int mapsize); + +/* Reads a chunk from demofile into given chunk */ +/* Returns a positive number on success, 0 on EOF, and negative number on error */ +/* Will allocate memory if chunk is snap, delta or message */ +int readdemochunk(FILE *demofile, demochunk *chunk, unsigned char version); -#endif // DEMO_H
\ No newline at end of file +#endif // DEMO_H diff --git a/inc/pack.h b/inc/pack.h new file mode 100644 index 0000000..d04d6ca --- /dev/null +++ b/inc/pack.h @@ -0,0 +1,10 @@ +#ifndef PACK_H +#define PACK_H + +#include <stdio.h> + +/* reads a teeworlds packed int from given buffer */ +/* the given pointer is incremented */ +int readint(unsigned char **cp); + +#endif // PACK_H @@ -1,15 +1,29 @@ #include "../inc/demo.h" +#include "../inc/huffman.h" +#include "../inc/pack.h" #include <stdio.h> +#include <stdlib.h> +#include <string.h> + +const unsigned char CHUNK_TICK_MASK = 0b10000000; +const unsigned char CHUNK_TICK_KEYFRAME_MASK = 0b01000000; +const unsigned char CHUNK_TICK_INLINE_MASK = 0b00100000; +const unsigned char CHUNK_TYPE_MASK = 0b01100000; // TODO add NORMAL_ +const unsigned char CHUNK_SIZE_MASK = 0b00011111; + +const unsigned char mapmagic[] = {0x6b, 0xe6, 0xda, 0x4a, 0xce, 0xbd, 0x38, 0x0c, + 0x9b, 0x5b, 0x12, 0x89, 0xc8, 0x42, 0xd7, 0x80}; int reverseint(const unsigned char in[4]) { return (in[0] << 24) | (in[1] << 16) | (in[2] << 8) | in[3]; } +// TODO make version sensitive int readdemoheader(FILE *fp, demoheader *dh) { - if (fscanf(fp,"TWDEMO%*c%c", &dh->version) != 1) + if (fscanf(fp, "TWDEMO%*c%c", &dh->version) != 1) return -1; if (fscanf(fp, "%64c", dh->netversion) != 1) return -2; @@ -41,4 +55,172 @@ int readdemotimeline(FILE *fp, demotimeline *dt) if (fscanf(fp, "%260c", dt->data) != 1) return -1; return 1; -}
\ No newline at end of file +} + +// TODO make version sensitive +int readdemomap(FILE *fp, demomap *dm, int mapsize) +{ + char magicbuf[sizeof(mapmagic)]; + fread(magicbuf, 1, sizeof(mapmagic), fp); + + if (memcmp(magicbuf, mapmagic, sizeof(mapmagic)) != 0) + return -1; + + if (fread(dm->sha256, 1, 32, fp) != 32) + return -2; + + if (fread(dm->data, 1, mapsize, fp) != mapsize) + return -3; + + return 1; +} + +int readdemotick(FILE *fp, char chunkhead, demotick *tick, unsigned char ver) +{ + tick->keyframe = (chunkhead & CHUNK_TICK_KEYFRAME_MASK); + + if (ver >= 5) + { + if (chunkhead & CHUNK_TICK_INLINE_MASK) + { + tick->innline = 1; + tick->delta = (chunkhead & 0x1f); // TODO name this mask? + } + else + { + tick->innline = 0; + unsigned char tickdelta[4]; + fread(tickdelta, 1, 4, fp); + tick->delta = reverseint(tickdelta); + } + } + else + { + if ((chunkhead & 0x3f) != 0) // TODO name this mask? + tick->delta = (chunkhead & 0x3f); + else + { + unsigned char tickdelta[4]; + fread(tickdelta, 1, 4, fp); + } + } + return 1; +} + +int readdemosnap(FILE *fp, demosnap *snap, int size) +{ + unsigned char data[size]; + unsigned char unpacked[1024 * 8]; + + fread(data, sizeof(unsigned char), size, fp); + + int r = decompresshuff((char *)data, size, (char *)unpacked, 1034 * 8); + + unsigned char *cp = unpacked; + + snap->datasize = readint(&cp); + snap->numitems = readint(&cp); + + snap->offsets = (int *)malloc(snap->numitems * sizeof(int)); + snap->items = (demosnapitem *)malloc(snap->numitems * sizeof(int)); + + for (int i = 0; i < snap->numitems; i++) + snap->offsets[i] = readint(&cp); + + for (int i = 0; i < snap->numitems; i++) + { + unsigned int item_key = (unsigned int)readint(&cp); + + snap->items[i].type = (item_key >> 16) & 0xffff; + snap->items[i].id = (item_key & 0xffff); + + if (i == (snap->numitems - 1)) + snap->items[i].numdata = (snap->datasize - snap->offsets[i]) / 4 - 1; + else + snap->items[i].numdata = (snap->offsets[i + 1] - snap->offsets[i]) / 4 - 1; + + snap->items[i].data = (int *)malloc(size * sizeof(int)); + + for (int y = 0; y < snap->items[i].numdata; y++) + snap->items[i].data[y] = readint(&cp); + } + + return 1; +} + +int readdemochunk(FILE *fp, demochunk *chunk, unsigned char ver) +{ + char chunkhead; + chunkhead = (char)fgetc(fp); + + if (chunkhead == EOF) + return 0; + + if (chunkhead & CHUNK_TICK_MASK) + { + demotick *tick = (demotick *)malloc(sizeof(demotick)); + if (readdemotick(fp, chunkhead, tick, ver)) + { + chunk->type = 4; + chunk->data.tick = tick; + printf("TICK={keyframe: %d, innline: %d, delta: %d}\n", tick->keyframe, tick->innline, tick->delta); + } + else + { + printf("[ ERROR ] error while reading tick!\n"); + return -1; + } + } + else + { + unsigned char type = (chunkhead & CHUNK_TYPE_MASK) >> 5; + short size = (chunkhead & CHUNK_SIZE_MASK); + + if (size == 30) + size = (short)fgetc(fp); + else if (size == 31) + fread(&size, sizeof(short), 1, fp); + + if (type == 1) + { + demosnap *snap = (demosnap *)malloc(sizeof(demosnap)); + if (readdemosnap(fp, snap, size)) + { + chunk->type = 1; // TODO make a chunk-type enum + chunk->data.snap = snap; + + printf("SNAPSHOT={datasize: %d, numitems: %d, offsets: [ ", snap->datasize, snap->numitems); + for (int i = 0; i < snap->numitems; i++) + printf("%d, ", snap->offsets[i]); + + printf("], items: [ "); + for (int i = 0; i < snap->numitems; i++) + { + printf("(type: %d, id: %d) { ", snap->items[i].type, snap->items[i].id); + for (int y = 0; y < snap->items[i].numdata; y++) + printf("%d, ", snap->items[i].data[y]); + printf("} "); + } + printf("]\n"); + } + else + { + printf("[ ERROR ] error while reading snapshot!\n"); + return -1; + } + } + else if (type == 2) + { + printf("MESSAGE={"); + fseek(fp, size, SEEK_CUR); + } + else if (type == 3) + { + printf("SNAPSHOT_DELTA={"); + fseek(fp, size, SEEK_CUR); + } + + printf("size: %d}\n", size); + } + return 1; +} @@ -1,9 +1,12 @@ #include "../inc/huffman.h" #include "../inc/demo.h" +#include "../inc/pack.h" #include <stdio.h> #include <stdlib.h> +#include <unistd.h> + int testcompress(char *line) { char inputbuff[4096]; @@ -109,16 +112,49 @@ int testdecompress(char *line) int main() { + inithuff(NULL); + FILE *fp = fopen("data/test.demo", "r"); + FILE *op = fopen("data/out.demo", "w"); + demoheader dh; demotimeline dt; + demomap dm; + int ret = readdemoheader(fp, &dh); - printf("\nheader: %i\n", ret); + dm.data = (unsigned char*) malloc(reverseint(dh.mapsize)); - ret = readdemotimeline(fp, &dt); + printf("\nheader: %i\n", ret); + + if (dh.version >= 4) + ret = readdemotimeline(fp, &dt); printf("\ntimeline: %i\n", ret); + + // TODO should be able to read 5 aswell, change readdemomap to fit + if (dh.version >= 6) + ret = readdemomap(fp, &dm, reverseint(dh.mapsize)); + printf("readdemomap ret: %d\n\n", ret); + + demochunk dc; + int i = 0; + while (readdemochunk(fp, &dc, dh.version) > 0) + { + i++; + } + printf("i: %d\n", i); + char c; + do + { + c = getc(fp); + // printf("%x\n", c & 0xff); + if (c != EOF) + { + putc(c, op); + } + } + while(c != EOF); return EXIT_SUCCESS; diff --git a/src/pack.c b/src/pack.c new file mode 100644 index 0000000..f7be2c8 --- /dev/null +++ b/src/pack.c @@ -0,0 +1,35 @@ +#include <stdio.h> + +int readint(unsigned char **cp) +{ + int result = 0; + int len = 1; + + unsigned char src = **cp; + + (*cp)++; + int sign = (src >> 6) & 1; + + result |= (src & 0b00111111); + for (int i = 0; i < 4; i++) + { + // printf("(%d, ", src); + if ((src & 0b10000000) == 0) + break; + + src = **cp; + (*cp)++; + len++; + + if (i == 3 && (src & 0b11110000) != 0) + printf("[ WARNING ] Non zero int padding!\n"); + + result |= (src & 0b01111111) << (6 + 7 * i); + } + if (len > 1 && src == 0b00000000) + printf("[ WARNING ] Overlong int encoding!\n"); + + result ^= -sign; + + return result; +} |
