A library for parsing Tiled maps.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

better error handling around base64 decoding

+35 -42
+35 -42
src/layer.zig
··· 142 142 const base64_data = try innerParseFromValue([]const u8, allocator, data, options); 143 143 const layer_size: usize = (layer.width orelse 0) * (layer.height orelse 0); 144 144 145 - layer.layer_data = parseBase64Data(allocator, base64_data, layer_size, layer.compression orelse .none); 145 + layer.layer_data = parseBase64Data(allocator, base64_data, layer_size, layer.compression orelse .none) catch 146 + return error.UnexpectedToken; 146 147 } 147 148 } 148 149 } ··· 334 335 switch (json_chunk.data) { 335 336 .csv => break :set_data json_chunk.data.csv, 336 337 .base64 => { 337 - const base64_data = parseBase64Data(arena, json_chunk.data.base64, json_chunk.width * json_chunk.height, compression); 338 + const base64_data = try parseBase64Data(arena, json_chunk.data.base64, json_chunk.width * json_chunk.height, compression); 338 339 339 340 break :set_data base64_data; 340 341 }, ··· 358 359 }; 359 360 360 361 // Decode base64 data (and optionally decompress) into a slice of u32 Global Tile Ids allocated on the heap, caller owns slice 361 - fn parseBase64Data(allocator: Allocator, base64_data: []const u8, size: usize, compression: Compression) []u32 { 362 - // var arena = std.heap.ArenaAllocator.init(allocator); 363 - // defer arena.deinit(); 364 - // const arena_allocator = arena.allocator(); 362 + fn parseBase64Data(allocator: Allocator, base64_data: []const u8, size: usize, compression: Compression) ![]u32 { 363 + const decoded_size = try base64_decoder.calcSizeForSlice(base64_data); 364 + const base64_decoded = try allocator.alloc(u8, decoded_size); 365 + defer allocator.free(base64_decoded); 365 366 366 - const decoded_size = base64_decoder.calcSizeForSlice(base64_data) catch @panic("Unable to decode base64 data"); 367 - var decoded = allocator.alloc(u8, decoded_size) catch @panic("OOM"); 368 - defer allocator.free(decoded); 367 + try base64_decoder.decode(base64_decoded, base64_data); 369 368 370 - base64_decoder.decode(decoded, base64_data) catch @panic("Unable to decode base64 data"); 369 + const decoded = if (compression != .none) 370 + try decompress(allocator, base64_decoded, compression) 371 + else 372 + base64_decoded; 373 + defer if (compression != .none) allocator.free(decoded); 371 374 372 - const data = allocator.alloc(u32, size) catch @panic("OOM"); 373 - 374 - const alignment = @alignOf(u32); 375 - 376 - if (compression != .none) 377 - decoded = decompress(allocator, decoded, compression); 375 + const stride = @sizeOf(u32); 376 + if (size * stride != decoded.len) 377 + return error.DataSizeMismatch; 378 378 379 - if (size * alignment != decoded.len) 380 - @panic("data size does not match Layer dimensions"); 379 + const data = try allocator.alloc(u32, size); 381 380 382 381 for (data, 0..) |*tile, i| { 383 - const tile_index = i * alignment; 384 - const end = tile_index + alignment; 385 - tile.* = std.mem.readInt(u32, decoded[tile_index..end][0..alignment], .little); 382 + const tile_index = i * stride; 383 + tile.* = std.mem.readInt(u32, decoded[tile_index..][0..stride], .little); 386 384 } 387 385 388 386 return data; 389 387 } 390 388 391 - // caller owns returned slice 392 - fn decompress(allocator: Allocator, compressed: []const u8, compression: Compression) []u8 { 389 + fn decompress(allocator: Allocator, compressed: []const u8, compression: Compression) ![]u8 { 393 390 var out: std.Io.Writer.Allocating = .init(allocator); 394 - defer out.deinit(); 391 + errdefer out.deinit(); 395 392 396 393 var compressed_reader: std.Io.Reader = .fixed(compressed); 397 394 398 - return switch (compression) { 399 - .gzip => { 400 - var decompresser: std.compress.flate.Decompress = .init(&compressed_reader, .gzip, &.{}); 401 - _ = decompresser.reader.streamRemaining(&out.writer) catch @panic("Unable to decompress gzip"); 402 - 403 - return out.toOwnedSlice() catch @panic("OOM"); 404 - }, 405 - .zlib => { 406 - var decompresser: std.compress.flate.Decompress = .init(&compressed_reader, .zlib, &.{}); 407 - _ = decompresser.reader.streamRemaining(&out.writer) catch @panic("Unable to decompress zlib"); 408 - 409 - return out.toOwnedSlice() catch @panic("OOM"); 395 + switch (compression) { 396 + .gzip, .zlib => { 397 + const format: std.compress.flate.Container = switch (compression) { 398 + .gzip => .gzip, 399 + .zlib => .zlib, 400 + else => unreachable, 401 + }; 402 + var decompresser: std.compress.flate.Decompress = .init(&compressed_reader, format, &.{}); 403 + _ = try decompresser.reader.streamRemaining(&out.writer); 410 404 }, 411 405 .zstd => { 412 406 var decompresser: std.compress.zstd.Decompress = .init(&compressed_reader, &.{}, .{}); 413 - 414 - _ = decompresser.reader.streamRemaining(&out.writer) catch @panic("Unable to decompress zstd"); 407 + _ = try decompresser.reader.streamRemaining(&out.writer); 408 + }, 409 + .none => unreachable, 410 + } 415 411 416 - return out.toOwnedSlice() catch @panic("OOM"); 417 - }, 418 - .none => return @constCast(compressed), 419 - }; 412 + return try out.toOwnedSlice(); 420 413 } 421 414 422 415 const tmz = @import("root.zig");