brzeszczot

brzeszczot.git
git clone git://git.lenczewski.org/brzeszczot.git
Log | Files | Refs

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 }