mapc.c (2853B)
1 #include <stdint.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 6 enum { 7 PH_MAP_MAGIC = 0x50484d50, 8 PH_MAP_VERSION = 1, 9 PH_AREA_NAME_MAX = 64, 10 PH_MAP_LINE_MAX = 512, 11 }; 12 13 typedef struct { 14 uint32_t magic; 15 uint32_t version; 16 uint32_t width; 17 uint32_t height; 18 char name[PH_AREA_NAME_MAX]; 19 } PhMapHeader; 20 21 static void 22 ph_strip_newline(char *line) 23 { 24 size_t len = strlen(line); 25 26 while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) { 27 line[--len] = '\0'; 28 } 29 } 30 31 static int 32 ph_compile_map(const char *src_path, const char *dst_path) 33 { 34 FILE *src; 35 FILE *dst; 36 PhMapHeader header = { 37 .magic = PH_MAP_MAGIC, 38 .version = PH_MAP_VERSION, 39 }; 40 char line[PH_MAP_LINE_MAX]; 41 unsigned char *tiles = NULL; 42 size_t tile_cap = 0; 43 size_t tile_count = 0; 44 int in_tiles = 0; 45 46 src = fopen(src_path, "r"); 47 if (!src) { 48 perror(src_path); 49 return 1; 50 } 51 52 while (fgets(line, sizeof(line), src)) { 53 size_t len; 54 55 ph_strip_newline(line); 56 if (!in_tiles && strncmp(line, "name:", 5) == 0) { 57 const char *name = line + 5; 58 size_t name_len; 59 60 while (*name == ' ' || *name == '\t') { 61 ++name; 62 } 63 name_len = strlen(name); 64 if (name_len >= sizeof(header.name)) { 65 fprintf(stderr, "%s: map name too long\n", src_path); 66 free(tiles); 67 fclose(src); 68 return 1; 69 } 70 memcpy(header.name, name, name_len + 1); 71 continue; 72 } 73 if (!in_tiles && line[0] == '\0') { 74 in_tiles = 1; 75 continue; 76 } 77 if (line[0] == '\0') { 78 continue; 79 } 80 81 len = strlen(line); 82 if (header.width == 0) { 83 header.width = (uint32_t)len; 84 } else if (len != header.width) { 85 fprintf(stderr, "%s: inconsistent row width: got %zu, expected %u\n", 86 src_path, len, header.width); 87 free(tiles); 88 fclose(src); 89 return 1; 90 } 91 92 if (tile_count + len > tile_cap) { 93 size_t new_cap = tile_cap ? tile_cap * 2 : 256; 94 unsigned char *new_tiles; 95 96 while (new_cap < tile_count + len) { 97 new_cap *= 2; 98 } 99 new_tiles = realloc(tiles, new_cap); 100 if (!new_tiles) { 101 free(tiles); 102 fclose(src); 103 return 1; 104 } 105 tiles = new_tiles; 106 tile_cap = new_cap; 107 } 108 109 memcpy(tiles + tile_count, line, len); 110 tile_count += len; 111 ++header.height; 112 } 113 fclose(src); 114 115 if (header.width == 0 || header.height == 0 || header.name[0] == '\0') { 116 fprintf(stderr, "%s: missing name or tile data\n", src_path); 117 free(tiles); 118 return 1; 119 } 120 121 dst = fopen(dst_path, "wb"); 122 if (!dst) { 123 perror(dst_path); 124 free(tiles); 125 return 1; 126 } 127 128 if (fwrite(&header, sizeof(header), 1, dst) != 1 || 129 fwrite(tiles, 1, tile_count, dst) != tile_count) { 130 perror(dst_path); 131 free(tiles); 132 fclose(dst); 133 return 1; 134 } 135 136 free(tiles); 137 fclose(dst); 138 return 0; 139 } 140 141 int 142 main(int argc, char **argv) 143 { 144 if (argc != 3) { 145 fprintf(stderr, "usage: %s <map.txt> <map.phmap>\n", argv[0]); 146 return 1; 147 } 148 return ph_compile_map(argv[1], argv[2]); 149 }