浏览代码

Merge remote-tracking branch 'origin/serialization'

Eiyeron Fulmincendii 10 年之前
父节点
当前提交
067601e90c
共有 2 个文件被更改,包括 302 次插入0 次删除
  1. 233 0
      info/archive_structure.md
  2. 69 0
      info/map_serialization.md

+ 233 - 0
info/archive_structure.md

@@ -0,0 +1,233 @@
+# Walrus RPG PIAF (PIAF is an Archive Format)
+## Control Header
+```markdown
+WRPG_PIAF_MAGIC_HEADER : "WRPGPIAF"          <=> 8 bytes (not \0 terminated)
+WRPG_PIAF_CHECKSUM     :  unsigned long long <=> 8 bytes
+WRPG_PIAF_VERSION      :  unsigned int       <=> 4 bytes
+WRPG_PIAF_NB_FILES     :  unsigned int       <=> 4 bytes
+WRPG_PIAF_DATA_SIZE    :  unsigned int       <=> 4 bytes
+<padding>              :  <filler>           <=> 4 bytes
+```
+Effective size : 32 bytes.
+
+## File table
+```markdown
+WRPG_PIAF_FILENAME         : char[8]      <=> 8 bytes (not \0 terminated)
+WRPG_PIAF_FILE_TYPE        : enumeration  <=> 4 bytes
+WRPG_PIAF_COMPRESSION_TYPE : enumeration  <=> 4 bytes
+WRPG_PIAF_FILE_SIZE        : unsigned int <=> 4 bytes
+WPRG_PIAF_DATA_OFFSET      : unsigned int <=> 4 bytes // To being able to point directly to file data
+```
+Effective size = 24 bytes per file.
+
+## File types
+```markdown
+0 = UNKNOWN
+1 = MAP
+2 = EVENT_LIST
+3 = TEXT
+4 = SPRITESHEET
+```
+
+## Compression types
+```markdown
+0 = RAW
+1 = ZLIB
+2 = RLE (?)
+```
+
+## Archive draft
+### class / structure
+```c++
+
+struct WRPG_PIAF_FILE_ENTRY {
+  char filename[9]; // or 9 if you want to put that \0.
+  enum WRPG_PIAF_FILE_TYPE file_type;
+  enum WRPG_PIAF_COMPRESSION_TYPE file_compresison;
+  unsigned int file_size;
+  unsigned int data_offset;
+}
+
+struct WRPG_PIAF_FILE {
+  char magic_header[9];
+  unsigned long long checksum;
+   // 0xAABBCCCC form
+   // AA = major version, BB = minor version, CC = hotfix
+  unsigned int version;
+  unsigned int nb_files;
+  unsigned int data_size;
+  unsigned int padidng;
+  WRPG_PIAF_FILE_ENTRY* entries;
+};
+
+```
+### Loading
+Here's the current state of the parser. Working on a x64 Linux. It should work everywhere because it doesn't care about endianess anymore.
+
+Take note that it'll read big-endian only, so work on the file writer will have to be done to make it universal.
+```c++
+#include <iostream>
+#include <cstring>
+
+#define CURRENT_PIAF_VERSION 0x00000000
+enum WRPG_PIAF_FILE_TYPE { FT_UNKNOWN, MAP, EVENT_LIST, TEXT, SPRITESHEET };
+enum WRPG_PIAF_COMPRESSION_TYPE { COMP_UNKNOWN, RAW, ZLIB, RLE };
+
+struct WRPG_PIAF_FILE_ENTRY {
+  char filename[9]; // or 9 if you want to put that \0.
+  enum WRPG_PIAF_FILE_TYPE file_type;
+  enum WRPG_PIAF_COMPRESSION_TYPE file_compression;
+  unsigned file_size;
+  unsigned data_offset;
+};
+
+struct WRPG_PIAF_FILE {
+  char magic_header[9];
+  unsigned long long checksum;
+  // 0xAABBCCCC form
+  // AA = major version, BB = minor version, CC = hotfix
+  unsigned version;
+  unsigned nb_files;
+  unsigned data_size;
+  unsigned padding;
+  WRPG_PIAF_FILE_ENTRY *entries;
+};
+
+unsigned read_unsigned(void *ptr) {
+  unsigned result = 0;
+  char *data = (char *)ptr;
+  for (int i = 0; i < sizeof(unsigned); i++)
+    result |= data[i] << (8 * (sizeof(unsigned) - 1 - i));
+  return result;
+}
+unsigned read_unsigned_long_long(void *ptr) {
+  unsigned long long result = 0;
+  char *data = (char *)ptr;
+  for (int i = 0; i < sizeof(unsigned long long); i++)
+    result |= data[i] << (8 * (sizeof(unsigned long long) - 1 - i));
+  return result;
+}
+
+struct WRPG_PIAF_FILE *load_structure_from_data(void *data, ssize_t size) {
+  if (data == nullptr || size < 32) {
+    fprintf(stderr, "Bad pointer/size\n");
+    return nullptr; // NPE
+  }
+
+  char *data_char = (char *)data;
+  if (strncmp(data_char, "WRPGPIAF", 8) != 0) {
+    // BAD_COOKIE exception
+    fprintf(stderr, "Bad version\n");
+    return nullptr;
+  }
+
+  unsigned long long checksum = read_unsigned_long_long(&data_char[8]);
+  bool check_ok = true;
+  // checksum routine goes here
+  if (!check_ok) {
+    fprintf(stderr, "Bad checksum\n");
+    // BAD_CHECKSUM exception
+    return nullptr;
+  }
+
+  unsigned file_version = read_unsigned(&data_char[16]);
+  if (file_version != CURRENT_PIAF_VERSION) {
+    fprintf(stderr, "Bad file version\n");
+    // BAD_VERSION exception
+    // Or manage older versions.
+    return nullptr;
+  }
+
+  unsigned nb_files = read_unsigned(&data_char[20]);
+  printf("NB FILES : %d\n", nb_files);
+  unsigned data_size = read_unsigned(&data_char[24]);
+
+  if (data_size != size - 32 - 24 * nb_files) {
+    // BAD_SIZE exception
+    printf("Data size mismatch\n");
+    return nullptr;
+  }
+
+  struct WRPG_PIAF_FILE_ENTRY *file_table = nullptr;
+  if (nb_files > 0) {
+    file_table = (WRPG_PIAF_FILE_ENTRY *)malloc(
+        nb_files * sizeof(struct WRPG_PIAF_FILE_ENTRY));
+    if (file_table == nullptr) {
+      fprintf(stderr, "NPE Filetable\n");
+      // NO_MORE_MEMORY exception
+      return nullptr;
+    }
+    // I don't know if that works. It should because these structs are POD but
+    // well...
+    memcpy(file_table, &data_char[32], sizeof(WRPG_PIAF_FILE_ENTRY) * nb_files);
+  }
+  struct WRPG_PIAF_FILE *file =
+      (WRPG_PIAF_FILE *)malloc(sizeof(struct WRPG_PIAF_FILE));
+  if (file == nullptr) {
+    // NO_MORE_MEMORY exception
+    free(file_table);
+    return nullptr;
+  }
+
+  // Now the structure is parsed.
+
+  memcpy(file->magic_header, data_char, 8);
+  for (size_t i = 0; i < nb_files; i++) {
+    char *file_entry = &data_char[32 + 24 * i];
+    memcpy(file_table[i].filename, file_entry, 8);
+    file_table[i].filename[8] = '\0'; // Making sure that there is a terminator.
+    file_table[i].file_type =
+        static_cast<WRPG_PIAF_FILE_TYPE>(read_unsigned(&file_entry[8]));
+    file_table[i].file_compression =
+        static_cast<WRPG_PIAF_COMPRESSION_TYPE>(read_unsigned(&file_entry[12]));
+    file_table[i].file_size = read_unsigned(&file_entry[16]);
+    file_table[i].data_offset = read_unsigned(&file_entry[20]);
+  }
+  file->magic_header[8] = '\0';
+  file->checksum = checksum;
+  file->version = file_version;
+  file->nb_files = nb_files;
+  file->data_size = data_size;
+  file->padding = 0XDEADBEEF;
+  file->entries = file_table;
+
+  return file;
+}
+
+int main(int argc, char const *argv[]) {
+  /* code */
+  char data[] = {'W', 'R', 'P', 'G', 'P', 'I', 'A', 'F', /*checksum*/ 0, 0, 0,
+                 0, 0, 0, 0, 0, /*version*/ 0, 0, 0, 0, /*nb_files*/ 0, 0, 0, 2,
+                 /*data size*/ 0, 0, 0, 1, /*padding*/ 0, 0, 0, 0,
+                 /*File 1*/ 'T', 'e', 's', 't', 'i', 'n', 'g', '\0',
+                 /*filetype*/ 0, 0, 0, MAP, /*file compression*/ 0, 0, 0, RAW,
+                 /*filesize*/ 0, 0, 0, 1, /*offset*/ 0, 0, 0, 0,
+                 /*File 2*/ 'T', 'e', 's', 't', 'i', 'n', 'g', '2',
+                 /*filetype*/ 0, 0, 0, MAP, /*file compression*/ 0, 0, 0, RAW,
+                 /*filesize*/ 0, 0, 0, 0, /*offset*/ 0, 0, 0, 0,
+                 /* data*/ 42
+
+  };
+  WRPG_PIAF_FILE *archive = load_structure_from_data(data, sizeof(data));
+  if (archive == nullptr) {
+    printf("Failed\n");
+  } else {
+    printf("Result\n");
+    printf("magic_header : %s\n", archive->magic_header);
+    printf("checksum : 0x%llx\n", archive->checksum);
+    printf("version : 0x%08x\n", archive->version);
+    printf("nb_files : %u\n", archive->nb_files);
+    printf("data_size : %u\n", archive->data_size);
+    printf("entries : %x\n", archive->entries);
+    for (size_t i = 0; i < archive->nb_files; i++) {
+      printf("> File N°%d\n", i);
+      printf(">   name : %s\n", archive->entries[i].filename);
+      printf(">   file_type : %u\n", archive->entries[i].file_type);
+      printf(">   file_size : %u\n", archive->entries[i].file_size);
+      printf(">   data_offset : %u\n", archive->entries[i].data_offset);
+      /* code */
+    }
+  }
+  return 0;
+}
+```

+ 69 - 0
info/map_serialization.md

@@ -0,0 +1,69 @@
+```markdown
+MAP_MAGIC_HEADER : 'WRPG_MAP'    <=> 8 bytes
+MAP_WIDTH        : unsigned int  <=> 4 bytes
+MAP_HEIGHT       : unsigned int  <=> 4 bytes
+MAP_N_LAYERS     : unsigned char <=> 4 byte
+MAP_COMPRESSION  : enumeration   <=> 4 bytes (IIRC, unless we force using some sort of enum class and use a smaller size)
+  - 0 : RAW
+  - 1 : RLE_PER_LAYER (stop when a layer ends)
+  - 2 : RLE_ALL_LAYERS (stop at the end of the last layer)
+  - 3 : ZLIB (?)
+  - 4 : ...
+MAP_DATA         : variable size <=> n*4 bytes
+// MAP_CHECKSUM?
+Size for a map of n*m * l layers = 24 bytes + up to n*m*l*4 bytes
+```
+
+Loader draft:
+```c++
+struct Map_Data {
+    char magic_string[8];
+    unsigned width : 4;
+    unsigned height : 4;
+    unsigned n_layers : 4;
+    enum Map_Compression compression;
+}
+/*
+#include <cstring>
+  Map load_map(void* data) throw MapLoadException {
+    struct Map_Data mdata = (struct Map_Data *) data[0]; // HAHA, wait, there is a problem : padding the address to the size of the header.
+    return Map();
+  }
+*/
+#include <cstring>
+  Map load_map(void* data) throw MapLoadException {
+    unsigned map_width = 0, map_height = 0, map_n_layers = 0;
+    enum Map_Compression map_compression = RAW; // or whatever Map_Compression will be
+    char* cdata = (char*) data;
+    unsigned* udata = (unsigned*) data;
+    if(cdata == NULL) throw NPE(); // Null Pointer Exception
+    if(strncmp(cdata, "WRPG_MAP", 8)) throw MLE("Bad map header.");
+    // Assuming big endian
+    map_width = ((cdata[8]&7) << 24) | ((cdata[9]&7) << 16) | ((cdata[10]&7) << 8) | (((cdata[11]&7)));
+    map_height = ((cdata[12]&7) << 24) | ((cdata[13]&7) << 16) | ((cdata[14]&7) << 8) | (((cdata[15]&7)));
+    map_n_layers = ((cdata[16]&7) << 24) | ((cdata[17]&7) << 16) | ((cdata[18]&7) << 8) | (((cdata[19]&7)));
+    if(map_n_layers < 1 || map_n_layers > 2) thorw MLE("Wrong map layer number.");
+
+    map_compression = ((cdata[20]&7) << 24) | ((cdata[21]&7) << 16) | ((cdata[22]&7) << 8) | (((cdata[23]&7)));
+
+    unsigned *layer0, *layer1;
+    switch(map_compression) {
+      // copy layers from &udata[6] and &udata[6*(map_width*map_height/sizeof(unsigned))]
+      case RAW:
+      // TODO
+      break;
+      case RLE_PER_LAYER:
+      // TDOO
+      break;
+      case RLE_ALL_LAYERS:
+      // TODO
+      break;
+      case ZLIB:
+      // TODO
+      break;
+      default:
+        throw MLE("Wrong compression");
+    }
+
+    return Map(map_width, map_height, layer0, layer1);
+  }