wad_reader.c (5183B)
1 #include "libriot/wad.h" 2 3 static b32 4 riot_wad_chunk_read(struct riot_wad_ctx *ctx, struct mem_stream *stream, struct riot_wad_chunk *chunk); 5 6 b32 7 riot_wad_read(struct riot_wad_ctx *ctx, struct mem_stream stream) { 8 assert(ctx); 9 10 char magic[2] = { 'R', 'W', }, buf[sizeof(magic)]; 11 if (!mem_stream_consume(&stream, buf, sizeof magic)) { 12 errlog("Failed to read WAD magic"); 13 return false; 14 } 15 16 if (memcmp(magic, buf, sizeof magic) != 0) { 17 errlog("Bad WAD magic value: %c%c", buf[0], buf[1]); 18 return false; 19 } 20 21 if (!riot_mem_stream_read_u8(&stream, &ctx->wad.major)) { 22 errlog("Failed to read WAD major version"); 23 return false; 24 } 25 26 if (!riot_mem_stream_read_u8(&stream, &ctx->wad.minor)) { 27 errlog("Failed to read WAD minor version"); 28 return false; 29 } 30 31 dbglog("WAD Version: %u.%u", ctx->wad.major, ctx->wad.minor); 32 33 switch (ctx->wad.major) { 34 case 1: 35 break; 36 37 case 2: { 38 u32 ecdsa_signature_length; 39 if (!riot_mem_stream_read_u32(&stream, &ecdsa_signature_length)) { 40 errlog("Failed to read WAD v2 signature length") 41 return false; 42 } 43 44 if (!mem_stream_skip(&stream, ecdsa_signature_length)) { 45 errlog("Failed to read WAD v2 signature (%u bytes)", ecdsa_signature_length); 46 return false; 47 } 48 49 u64 checksum; 50 if (!riot_mem_stream_read_u64(&stream, &checksum)) { 51 errlog("Failed to read WAD v2 signature checksum"); 52 return false; 53 } 54 55 dbglog("WAD v2 signature: length: %u, checksum: %lu", ecdsa_signature_length, checksum); 56 57 // TODO: check signature and checksum values 58 } break; 59 60 case 3: { 61 u32 ecdsa_signature_length = 256; 62 if (!mem_stream_skip(&stream, ecdsa_signature_length)) { 63 errlog("Failed to read WAD v3 signature (%u bytes)", ecdsa_signature_length); 64 return false; 65 } 66 67 u64 checksum; 68 if (!riot_mem_stream_read_u64(&stream, &checksum)) { 69 errlog("Failed to read WAD v3 signature checksum"); 70 return false; 71 } 72 73 dbglog("WAD v3 signature: length: %u, checksum: %lu", ecdsa_signature_length, checksum); 74 75 // TODO: check signature and checksum values 76 } break; 77 78 default: 79 unreachable("Unknown WAD major version: %u", ctx->wad.major); 80 break; 81 } 82 83 if (ctx->wad.major <= 2) { 84 u16 toc_offset; 85 if (!riot_mem_stream_read_u16(&stream, &toc_offset)) { 86 errlog("Failed to read WAD table of contents offset"); 87 return false; 88 } 89 90 u16 toc_entry_size; 91 if (!riot_mem_stream_read_u16(&stream, &toc_entry_size)) { 92 errlog("Failed to read WAD table of contents entry size"); 93 return false; 94 } 95 96 dbglog("WAD TOC: offset: %u, entry size: %u", toc_offset, toc_entry_size); 97 98 // TODO: handle table of contents 99 } 100 101 if (!riot_mem_stream_read_u32(&stream, &ctx->wad.chunk_count)) { 102 errlog("Failed to read WAD chunk count"); 103 return false; 104 } 105 106 dbglog("WAD Chunks: %u", ctx->wad.chunk_count); 107 108 riot_offptr_t chunk_offptr; 109 if (!riot_wad_ctx_pushn_chunk(ctx, ctx->wad.chunk_count, &chunk_offptr)) { 110 errlog("Failed to preallocate %u WAD chunks"); 111 return false; 112 } 113 114 (void) chunk_offptr; 115 116 for (u32 i = 0; i < ctx->wad.chunk_count; i++) { 117 struct riot_wad_chunk *chunk = (struct riot_wad_chunk *)ctx->chunk_pool.ptr + i; 118 if (!riot_wad_chunk_read(ctx, &stream, chunk)) { 119 errlog("Failed to read WAD chunk %u/%u", i + 1, ctx->wad.chunk_count); 120 return false; 121 } 122 } 123 124 dbglog("Read %u WAD chunks", ctx->wad.chunk_count); 125 dbglog("WAD chunk segment end: %lu", stream.cur, stream.len); 126 dbglog("WAD data segment start: %lu", ctx->wad.data_start); 127 dbglog("WAD ctx chunk pool size: %lu/%lu bytes", ctx->chunk_pool.len, ctx->chunk_pool.cap); 128 129 return true; 130 } 131 132 static b32 133 riot_wad_chunk_read(struct riot_wad_ctx *ctx, struct mem_stream *stream, struct riot_wad_chunk *chunk) { 134 assert(ctx); 135 assert(stream); 136 assert(chunk); 137 138 if (!riot_mem_stream_read_xxh64_u64(stream, &chunk->path_hash)) { 139 errlog("Failed to read WAD chunk path hash"); 140 return false; 141 } 142 143 if (!riot_mem_stream_read_u32(stream, &chunk->data_offset)) { 144 errlog("Failed to read WAD chunk data offset"); 145 return false; 146 } 147 148 if (chunk->data_offset < ctx->wad.data_start) 149 ctx->wad.data_start = chunk->data_offset; 150 151 if (!riot_mem_stream_read_u32(stream, &chunk->compressed_size)) { 152 errlog("Failed to read WAD chunk compressed data size"); 153 return false; 154 } 155 156 if (!riot_mem_stream_read_u32(stream, &chunk->decompressed_size)) { 157 errlog("Failed to read WAD chunk decompressed data size"); 158 return false; 159 } 160 161 u8 sub_chunk_count_and_compression_type; 162 if (!riot_mem_stream_read_u8(stream, &sub_chunk_count_and_compression_type)) { 163 errlog("Failed to read WAD chunk sub-chunk count and compression type byte"); 164 return false; 165 } 166 167 chunk->compression = (enum riot_wad_compression)sub_chunk_count_and_compression_type & 0xf; 168 chunk->sub_chunk_count = sub_chunk_count_and_compression_type >> 4; 169 170 if (!riot_mem_stream_read_b8(stream, &chunk->duplicated)) { 171 errlog("Failed to read WAD chunk duplication flag"); 172 return false; 173 } 174 175 if (!riot_mem_stream_read_u16(stream, &chunk->sub_chunk_start)) { 176 errlog("Failed to read WAD sub-chunk start"); 177 return false; 178 } 179 180 if (ctx->wad.major > 2) { 181 if (!riot_mem_stream_read_u64(stream, &chunk->checksum)) { 182 errlog("Failed to read WAD chunk checksum"); 183 return false; 184 } 185 } 186 187 return true; 188 }