summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjohannes <johannes.herman@gmail.com>2024-02-06 12:29:41 +0100
committerjohannes <johannes.herman@gmail.com>2024-02-06 12:29:41 +0100
commit0ab2c0afc6fd192f4008962ef400b92434e2dc2d (patch)
tree31ff61e1945850048ac6b82f23cb428d62e0cb70
parent1bdee2153953e23bf71f7a5e83145bb4d67db567 (diff)
added read snap and read tick
-rw-r--r--inc/demo.h83
-rw-r--r--inc/pack.h10
-rw-r--r--src/demo.c186
-rw-r--r--src/main.c40
-rw-r--r--src/pack.c35
5 files changed, 344 insertions, 10 deletions
diff --git a/inc/demo.h b/inc/demo.h
index 154a333..0b398b0 100644
--- a/inc/demo.h
+++ b/inc/demo.h
@@ -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
diff --git a/src/demo.c b/src/demo.c
index 0be8611..f3f250c 100644
--- a/src/demo.c
+++ b/src/demo.c
@@ -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;
+}
diff --git a/src/main.c b/src/main.c
index 1c94aef..4356716 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
+}