ani.zig (1748B) - Raw
1 //! https://en.wikipedia.org/wiki/Resource_Interchange_File_Format 2 //! https://www.moon-soft.com/program/format/windows/ani.htm 3 //! https://www.gdgsoft.com/anituner/help/aniformat.htm 4 //! https://www.lomont.org/software/aniexploit/ExploitANI.pdf 5 //! 6 //! RIFF( 'ACON' 7 //! [LIST( 'INFO' <info_data> )] 8 //! [<DISP_ck>] 9 //! anih( <ani_header> ) 10 //! [rate( <rate_info> )] 11 //! ['seq '( <sequence_info> )] 12 //! LIST( 'fram' icon( <icon_file> ) ... ) 13 //! ) 14 15 const std = @import("std"); 16 17 const AF_ICON: u32 = 1; 18 19 pub fn isAnimatedIcon(reader: anytype) bool { 20 const flags = getAniheaderFlags(reader) catch return false; 21 return flags & AF_ICON == AF_ICON; 22 } 23 24 fn getAniheaderFlags(reader: anytype) !u32 { 25 const riff_header = try reader.readBytesNoEof(4); 26 if (!std.mem.eql(u8, &riff_header, "RIFF")) return error.InvalidFormat; 27 28 _ = try reader.readInt(u32, .little); // size of RIFF chunk 29 30 const form_type = try reader.readBytesNoEof(4); 31 if (!std.mem.eql(u8, &form_type, "ACON")) return error.InvalidFormat; 32 33 while (true) { 34 const chunk_id = try reader.readBytesNoEof(4); 35 const chunk_len = try reader.readInt(u32, .little); 36 if (!std.mem.eql(u8, &chunk_id, "anih")) { 37 // TODO: Move file cursor instead of skipBytes 38 try reader.skipBytes(chunk_len, .{}); 39 continue; 40 } 41 42 const aniheader = try reader.readStruct(ANIHEADER); 43 return std.mem.nativeToLittle(u32, aniheader.flags); 44 } 45 } 46 47 /// From Microsoft Multimedia Data Standards Update April 15, 1994 48 const ANIHEADER = extern struct { 49 cbSizeof: u32, 50 cFrames: u32, 51 cSteps: u32, 52 cx: u32, 53 cy: u32, 54 cBitCount: u32, 55 cPlanes: u32, 56 jifRate: u32, 57 flags: u32, 58 };