code wiki / (root) / nx_gif_animation_gate_t139.nx

nx_gif_animation_gate_t139.nx source

↩ module page · 153 lines · 13245 B

1// nx_gif_animation_gate_t139.nx -- Generates and hashes a 4x4 interlaced GIF image with a predefined color palette. 2import "nx_syscalls.nx" 3import "nx_gate_verdict.nx" 4import "nx_sha256.nx" 5import "nx_gif_decode_t139.nx" 6// append one 3-bit LZW code, LSB-first (GIF bit order); buf must be zeroed (OR-only) 7func gg_putcode(buf: *u8, bitpos: *i64, code: i64) -> i64 { 8 var i: i64=0 9 while i<3 { 10 let bit: i64=(code>>i)&1 11 let bp: i64=bitpos[0] 12 if bit==1 { let by: i64=bp/8; let bo: i64=bp%8; buf[by]=((buf[by] as i64)|(1<<bo)) as u8 } 13 bitpos[0]=bitpos[0]+1 14 i=i+1 15 } 16 return 0 17} 18 19// build a 4x4 GIF89a with a 4-entry GCT (red,green,blue,white) whose pixel-index 20// STORAGE sequence is pixseq[16]; interlaced sets descriptor bit 6. returns length. 21func gg_build_gif(out: *u8, pixseq: *u8, interlaced: i64) -> i64 { 22 out[0]=0x47 as u8; out[1]=0x49 as u8; out[2]=0x46 as u8 23 out[3]=0x38 as u8; out[4]=0x39 as u8; out[5]=0x61 as u8 24 out[6]=4 as u8; out[7]=0 as u8; out[8]=4 as u8; out[9]=0 as u8 25 out[10]=0x81 as u8; out[11]=0 as u8; out[12]=0 as u8 26 out[13]=255 as u8; out[14]=0 as u8; out[15]=0 as u8 27 out[16]=0 as u8; out[17]=255 as u8; out[18]=0 as u8 28 out[19]=0 as u8; out[20]=0 as u8; out[21]=255 as u8 29 out[22]=255 as u8; out[23]=255 as u8; out[24]=255 as u8 30 var o: i64=25 31 out[o]=0x2C as u8 32 out[o+1]=0 as u8; out[o+2]=0 as u8; out[o+3]=0 as u8; out[o+4]=0 as u8 33 out[o+5]=4 as u8; out[o+6]=0 as u8; out[o+7]=4 as u8; out[o+8]=0 as u8 34 if interlaced==1 { out[o+9]=0x40 as u8 } else { out[o+9]=0 as u8 } 35 o=o+10 36 out[o]=2 as u8; o=o+1 37 let lzbuf: *u8=sys_mmap(256) 38 let bitpos: *i64=sys_mmap(8) as *i64 39 bitpos[0]=0 40 var p: i64=0 41 while p<16 { gg_putcode(lzbuf,bitpos,4); gg_putcode(lzbuf,bitpos,pixseq[p] as i64); p=p+1 } 42 gg_putcode(lzbuf,bitpos,5) 43 let nbytes: i64=(bitpos[0]+7)/8 44 out[o]=nbytes as u8; o=o+1 45 var q: i64=0 46 while q<nbytes { out[o]=lzbuf[q]; o=o+1; q=q+1 } 47 out[o]=0 as u8; o=o+1 48 out[o]=0x3B as u8; o=o+1 49 return o 50} 51 52 53func gb_hash(raw: *u8, n: i64, expected: *u8) -> i64 { 54 let wn: i64=sha256_workspace_bytes(); let ws: *u8=gif_own(wn+64) 55 if ws==(0 as *u8) { return 0 } 56 let digest: *u8=((ws as i64)+wn) as *u8 57 var ok: i64=1 58 if sha256_init_workspace(ws,wn)!=0 { ok=0 } else { sha256_update(ws as *Sha256,raw,n); sha256_final(ws as *Sha256,digest) 59 let hex: *u8="0123456789abcdef";var i: i64=0;while i<32 { let v: i64=digest[i] as i64;if hex[v>>4]!=expected[i*2] || hex[v&15]!=expected[i*2+1] { ok=0 } i=i+1 } 60 } 61 if gif_release(ws,wn+64)!=0 { ok=0 } return ok 62} 63func gb_pages() -> i64 { 64 let buf: *u8=gif_own(512);if buf==(0 as *u8) { return 0-1 } 65 let fd: i64=sys_openat_rd("/proc/self/statm");if fd<0 { gif_release(buf,512);return 0-1 } 66 let n: i64=sys_read(fd,buf,511);let rc: i64=sys_close(fd);var value: i64=0;var i: i64=0 67 if n<=0 || rc!=0 { gif_release(buf,512);return 0-1 } 68 while i<n {let c: i64=buf[i] as i64;if c<48 || c>57 {break}value=value*10+c-48;i=i+1} 69 if gif_release(buf,512)!=0 {return 0-1}return value 70} 71func ga_expected(i: i64) -> *u8 { 72 if i==0 { return "0ded56809f61d65a9a4d343d10525372240cc9a98a4e49d284209e238697f1f2" } 73 if i==1 { return "d21eb13e117ec0956a87ce5cd90908e12632a3e3f2c5c4d6918c93143a5e29a2" } 74 if i==2 { return "90b2bdbba8c3f592c312dbbaa310bb27c876af74b2e66f8f762228ed5a976f2a" } 75 if i==3 { return "a80fc9e1df0246afa6b397bcbd2446c445db2084a43b5565a6bafd8c6393d101" } 76 if i==4 { return "2c46a66e6fcd532d0f5fdbcab7de389675b64341b8e3b7e77c8e7aee2072ce10" } 77 if i==5 { return "4d3ef2c0e2b55dac0ba3c2aa2dd74937473d9455848d3b373bfb2afd0878c03b" } 78 if i==6 { return "d52826bf8bd8f9653c0132ae06cb15299a5f09e5e5a4d8404a111ec7e4a28e1a" } 79 if i==7 { return "f7e5f4ef5dc5e8c4229048df3a7b83665905789fd764b90901d0b38830f353f9" } 80 if i==8 { return "97987ecdf546862abcb6ae1a8e13fe8dff1fc8b31a9e04d463f4216b6e825fb1" } 81 if i==9 { return "aa3bc62e68f002f084da15d701c81f5d52563164e226eb57a285b48b5b88d88b" } 82 if i==10 { return "67b1b79ce8ca40957d1b3c458fbcd1995d9c2dc6b6eaf04085ded917e6a798c1" } 83 if i==11 { return "ce8b45188857abfe3ee99bf1e2a9105b130671ce8ef6acd5eedcabfc233ed264" } 84 if i==12 { return "fe3dab0220824008f242d905ef6e461363a27994c676127be9df142bd07e6534" } 85 if i==13 { return "12de180db9edcd443a8f38ffe2f35a32ef69ce80bf968eb0a60f928e6189bc13" } 86 if i==14 { return "632e1a7c9d63bd8ca9ca8ad827b9533e75ed55cc0d4f69379adad18274247dfc" } 87 if i==15 { return "1a344c4cd14fb3f3c2db8810ca11f862727c3e441430ac52ff5e3d071fe891f7" } 88 if i==16 { return "251a2085c7c069b30362ea577c79940736eaad2f54c0fce03f8cda20de517ef8" } 89 if i==17 { return "55c472a245e976617cb3dcbb3e18b55e6f4a7aaf93d3fe3a1e46e64fa9b6c009" } 90 if i==18 { return "eabf25b076dd86d5e691bb9bbec43f2cc52b4eeadcb264b2c7d6f30611336bb2" } 91 if i==19 { return "8ebcbd5cc3ab5cd55dd792eaa897a3b07c8063f7ed9aac4f798ef9a3fb9f809c" } 92 if i==20 { return "5cadb23aa92ca56d5dbf4b3f1609583e07c23fed1d237a82ceadca15fafc0ed2" } 93 if i==21 { return "ab8f21ab682af3011888261f8e49f25cfd8a75ad973488fd739b64a7ddba4148" } 94 if i==22 { return "7200d810ea5d6e9d9ceb67344c08e85049cbe7553871b705c13ef45e193a7666" } 95 if i==23 { return "bc63c823e61e677c49d03517c20bbe76b5bcbcf61ea8f346abbbabf28fb5b70d" } 96 if i==24 { return "b28e97f50ee5434ebd7c8d8d1338320c5ebb063b4c3aa68af25174a507cc7db1" } 97 if i==25 { return "0fc365b7c0d39e8cca2e211d6e6091a3d2b4a943fde43f2a17937f0fe22f62c6" } 98 if i==26 { return "9f13beb1e157aee36772a6b3328ae19ffbe9cc9a3a5b06554308ea2175c6e8cd" } 99 if i==27 { return "226d18da05cfa17139b67aa54452d86785a328a89701444a98c7cb17e8370bc5" } 100 if i==28 { return "626ea16be88064b78131eeef96fa86c6045dcfcb51ae1f2a743a00c241c1f61f" } 101 if i==29 { return "98a6792b43a8ba5510bd3ff9d65523882fd4cee3cd2a8347746f820cfdf838e1" } 102 if i==30 { return "cea0d3f72d74bee2ef48637d9f005650451aca312391106420834f93439f3d8a" } 103 if i==31 { return "12be5de77b484a79bfd3fd6085f2fb1f2d5751e684d88112be1dd3ffe4e93f4a" } 104 if i==32 { return "05e54c519c42d53e3e1b0a310cd3bd4fd7ea99b86af94e57be19296ace25fdc9" } 105 if i==33 { return "aa6a0b59322e43c0b2c0e74b9aa7a0f980cfa2fb56f99553906ae2074fad42f2" } 106 if i==34 { return "094f3fcffae3363a901385887b1c364917276df8c881b7137c1e79d749a8f217" } 107 if i==35 { return "9f4fe23c9f861b1976960e668e6929c1b493a13a2e59cd823a1dda4b7fb0a9cd" } 108 return "invalid" 109} 110func main() -> i64 { 111 let ctr: *i64=sys_mmap(32) as *i64 112 let st: *i64=gif_own(GIF_ANIM_WORDS*8) as *i64; let info: *i64=gif_own(128) as *i64 113 let raw: *u8=gif_own(139); 114 raw[0]=71 as u8;raw[1]=73 as u8;raw[2]=70 as u8;raw[3]=56 as u8;raw[4]=57 as u8;raw[5]=97 as u8;raw[6]=2 as u8;raw[7]=0 as u8;raw[8]=2 as u8;raw[9]=0 as u8;raw[10]=129 as u8;raw[11]=0 as u8;raw[12]=0 as u8;raw[13]=0 as u8;raw[14]=0 as u8;raw[15]=0 as u8;raw[16]=255 as u8;raw[17]=0 as u8;raw[18]=0 as u8;raw[19]=0 as u8;raw[20]=255 as u8;raw[21]=0 as u8;raw[22]=0 as u8;raw[23]=0 as u8;raw[24]=255 as u8;raw[25]=33 as u8;raw[26]=255 as u8;raw[27]=11 as u8;raw[28]=78 as u8;raw[29]=69 as u8;raw[30]=84 as u8;raw[31]=83 as u8;raw[32]=67 as u8;raw[33]=65 as u8;raw[34]=80 as u8;raw[35]=69 as u8;raw[36]=50 as u8;raw[37]=46 as u8;raw[38]=48 as u8;raw[39]=3 as u8;raw[40]=1 as u8;raw[41]=3 as u8;raw[42]=0 as u8;raw[43]=0 as u8;raw[44]=33 as u8;raw[45]=249 as u8;raw[46]=4 as u8;raw[47]=5 as u8;raw[48]=2 as u8;raw[49]=0 as u8;raw[50]=0 as u8;raw[51]=0 as u8;raw[52]=44 as u8;raw[53]=0 as u8;raw[54]=0 as u8;raw[55]=0 as u8;raw[56]=0 as u8;raw[57]=2 as u8;raw[58]=0 as u8;raw[59]=2 as u8;raw[60]=0 as u8;raw[61]=0 as u8;raw[62]=2 as u8;raw[63]=4 as u8;raw[64]=12 as u8;raw[65]=195 as u8;raw[66]=48 as u8;raw[67]=5 as u8;raw[68]=0 as u8;raw[69]=33 as u8;raw[70]=249 as u8;raw[71]=4 as u8;raw[72]=13 as u8;raw[73]=3 as u8;raw[74]=0 as u8;raw[75]=0 as u8;raw[76]=0 as u8;raw[77]=44 as u8;raw[78]=0 as u8;raw[79]=0 as u8;raw[80]=0 as u8;raw[81]=0 as u8;raw[82]=1 as u8;raw[83]=0 as u8;raw[84]=1 as u8;raw[85]=0 as u8;raw[86]=0 as u8;raw[87]=2 as u8;raw[88]=2 as u8;raw[89]=84 as u8;raw[90]=1 as u8;raw[91]=0 as u8;raw[92]=33 as u8;raw[93]=249 as u8;raw[94]=4 as u8;raw[95]=9 as u8;raw[96]=4 as u8;raw[97]=0 as u8;raw[98]=0 as u8;raw[99]=0 as u8;raw[100]=44 as u8;raw[101]=1 as u8;raw[102]=0 as u8;raw[103]=1 as u8;raw[104]=0 as u8;raw[105]=1 as u8;raw[106]=0 as u8;raw[107]=1 as u8;raw[108]=0 as u8;raw[109]=0 as u8;raw[110]=2 as u8;raw[111]=2 as u8;raw[112]=92 as u8;raw[113]=1 as u8;raw[114]=0 as u8;raw[115]=33 as u8;raw[116]=249 as u8;raw[117]=4 as u8;raw[118]=5 as u8;raw[119]=5 as u8;raw[120]=0 as u8;raw[121]=0 as u8;raw[122]=0 as u8;raw[123]=44 as u8;raw[124]=0 as u8;raw[125]=0 as u8;raw[126]=0 as u8;raw[127]=0 as u8;raw[128]=1 as u8;raw[129]=0 as u8;raw[130]=1 as u8;raw[131]=0 as u8;raw[132]=0 as u8;raw[133]=2 as u8;raw[134]=2 as u8;raw[135]=68 as u8;raw[136]=1 as u8;raw[137]=0 as u8;raw[138]=59 as u8; 115 let expected: *u8=gif_own(64); 116 expected[0]=255 as u8;expected[1]=0 as u8;expected[2]=0 as u8;expected[3]=255 as u8;expected[4]=255 as u8;expected[5]=0 as u8;expected[6]=0 as u8;expected[7]=255 as u8;expected[8]=255 as u8;expected[9]=0 as u8;expected[10]=0 as u8;expected[11]=255 as u8;expected[12]=255 as u8;expected[13]=0 as u8;expected[14]=0 as u8;expected[15]=255 as u8;expected[16]=0 as u8;expected[17]=255 as u8;expected[18]=0 as u8;expected[19]=255 as u8;expected[20]=255 as u8;expected[21]=0 as u8;expected[22]=0 as u8;expected[23]=255 as u8;expected[24]=255 as u8;expected[25]=0 as u8;expected[26]=0 as u8;expected[27]=255 as u8;expected[28]=255 as u8;expected[29]=0 as u8;expected[30]=0 as u8;expected[31]=255 as u8;expected[32]=255 as u8;expected[33]=0 as u8;expected[34]=0 as u8;expected[35]=255 as u8;expected[36]=255 as u8;expected[37]=0 as u8;expected[38]=0 as u8;expected[39]=255 as u8;expected[40]=255 as u8;expected[41]=0 as u8;expected[42]=0 as u8;expected[43]=255 as u8;expected[44]=0 as u8;expected[45]=0 as u8;expected[46]=255 as u8;expected[47]=255 as u8;expected[48]=255 as u8;expected[49]=0 as u8;expected[50]=0 as u8;expected[51]=255 as u8;expected[52]=255 as u8;expected[53]=0 as u8;expected[54]=0 as u8;expected[55]=255 as u8;expected[56]=255 as u8;expected[57]=0 as u8;expected[58]=0 as u8;expected[59]=255 as u8;expected[60]=0 as u8;expected[61]=0 as u8;expected[62]=0 as u8;expected[63]=0 as u8; 117 var rc: i64=gif_anim_init(raw,139,st,0) 118 gv_check("animation initializes explicit transparent canvas",rc==1,ctr) 119 var i: i64=0; var good: i64=1; while i<4 { 120 rc=gif_anim_next(st,info); var ok: i64=1 121 if rc!=1 { ok=0 } else { let px: *u8=st[3] as *u8; var p: i64=0; while p<16 { if px[p]!=expected[i*16+p] { ok=0 } p=p+1 } if info[9]!=i+2 { ok=0 } } 122 if ok==0 { good=0 } gv_check("composited synthetic frame equals libvips including disposal",ok,ctr); i=i+1 123 } 124 gv_check("finite raw loop count3 and exact14cs cumulative duration",st[17]==3 && st[14]==14,ctr) 125 gv_check("trailer completes iteration",gif_anim_next(st,info)==GIF_DONE,ctr) 126 gv_check("completed iterator is stable",gif_anim_next(st,info)==GIF_DONE,ctr) 127 gv_check("close releases owned animation buffers",gif_anim_close(st)==0,ctr) 128 gv_check("close is idempotent with caller state alive",gif_anim_close(st)==0,ctr) 129 rc=gif_anim_init(raw,139-1,st,0);i=0;while i<4 && rc==1 { rc=gif_anim_next(st,info);i=i+1 } 130 gv_check("missing trailer refuses complete-animation acceptance",gif_anim_next(st,info)==GIF_BAD_FORMAT,ctr);gif_anim_close(st) 131 let wh: *i64=gif_own(16) as *i64; let bad: *u8=gif_convert_checked(raw,139,wh,info,2) 132 gv_check("unsupported channel count refuses before decode/write",bad==(0 as *u8) && info[15]==GIF_BAD_ARGUMENT && wh[0]==0 && wh[1]==0,ctr) 133 let before: i64=gb_pages();i=0;good=1;while i<100 { 134 rc=gif_anim_init(raw,139,st,0);if rc!=1 {good=0};var j: i64=0;while j<4 && rc==1{rc=gif_anim_next(st,info);j=j+1};if gif_anim_close(st)!=0{good=0};i=i+1 135 }let after: i64=gb_pages();gv_puts("animation pages before=");gv_num(before);gv_puts(" after=");gv_num(after);gv_puts("\n") 136 gv_check("100 four-frame caller cycles reclaim canvas restore and frame scratch",good==1 && before==after,ctr) 137 let lb: *i64=sys_mmap(16) as *i64;let original: *u8=sys_read_file("/tmp/strut-2d17175184e088f9.gif",lb) 138 good=0;if original!=(0 as *u8){good=gb_hash(original,lb[0],"2d17175184e088f93cff9f165644c93f0a9bbfb77757ae154d28e5602b747811")} 139 gv_check("original encoded identity pinned",good==1 && lb[0]==1339248,ctr) 140 if good==1 { 141 rc=gif_anim_init(original,lb[0],st,0);gv_check("original animation initializes",rc==1,ctr) 142 i=0;while i<36 { 143 rc=gif_anim_next(st,info);var ok: i64=0;if rc==1{ok=gb_hash(st[3] as *u8,st[7],ga_expected(i));if st[5]!=268 || st[6]!=402 || info[9]!=5 {ok=0}} 144 gv_puts("original frame=");gv_num(i);gv_puts(" ");gv_check("complete RGBA bytes and50ms agree with libvips",ok,ctr);i=i+1 145 } 146 gv_check("original36frames180cs infinite-loopmetadata",st[13]==36 && st[14]==180 && st[17]==0,ctr) 147 gv_check("original exact trailer and no extra frame",gif_anim_next(st,info)==GIF_DONE,ctr) 148 gv_check("original animation release succeeds",gif_anim_close(st)==0,ctr) 149 } 150 gif_release(raw,139);gif_release(expected,64);gif_release(info as *u8,128);gif_release(st as *u8,GIF_ANIM_WORDS*8);gif_release(wh as *u8,16) 151 gv_puts("GIF-ANIMATION-GATE ");gv_num(ctr[0]);gv_puts("/");gv_num(ctr[1]);gv_puts("\n") 152 if ctr[0]!=ctr[1] {return 1}return 0 153}