From eccd92f8c05abb56ad0cc4e212456d6072b14a04 Mon Sep 17 00:00:00 2001 From: Deus Libri Date: Sat, 14 Apr 2018 22:05:37 +0200 Subject: [PATCH] Initial commit. This contains the needed sources, and some executables for testing. The build files are not yet up-to-date. --- README.md | 14 + ...recomp_w_preflate_msvc17_aka_vc140_x64.exe | Bin 0 -> 771584 bytes ...recomp_w_preflate_msvc17_aka_vc140_x86.exe | Bin 0 -> 703488 bytes contrib/preflate/LICENSE | 201 ++ contrib/preflate/Makefile | 63 + contrib/preflate/README.md | 143 + contrib/preflate/main.cpp | 178 + contrib/preflate/packARI/.gitignore | 31 + contrib/preflate/packARI/LICENSE | 165 + contrib/preflate/packARI/README.md | 8 + contrib/preflate/packARI/source/Makefile | 56 + contrib/preflate/packARI/source/app_icon.ico | Bin 0 -> 3262 bytes contrib/preflate/packARI/source/aricoder.cpp | 1044 ++++++ contrib/preflate/packARI/source/aricoder.h | 268 ++ contrib/preflate/packARI/source/bitops.cpp | 926 +++++ contrib/preflate/packARI/source/bitops.h | 168 + contrib/preflate/packARI/source/file_icon.ico | Bin 0 -> 3262 bytes contrib/preflate/packARI/source/icons.res | Bin 0 -> 6922 bytes contrib/preflate/packARI/source/packari.cpp | 1751 +++++++++ contrib/preflate/packARI/source/packaridll.h | 37 + contrib/preflate/packARI/source/packarilib.h | 41 + contrib/preflate/packARI/source/paritbl.h | 48 + contrib/preflate/preflate.h | 21 + contrib/preflate/preflate_block_decoder.cpp | 196 + contrib/preflate/preflate_block_decoder.h | 83 + contrib/preflate/preflate_block_reencoder.cpp | 188 + contrib/preflate/preflate_block_reencoder.h | 75 + contrib/preflate/preflate_block_trees.cpp | 65 + contrib/preflate/preflate_block_trees.h | 32 + contrib/preflate/preflate_checker.cpp | 264 ++ contrib/preflate/preflate_checker.h | 22 + .../preflate/preflate_complevel_estimator.cpp | 195 + .../preflate/preflate_complevel_estimator.h | 68 + contrib/preflate/preflate_constants.cpp | 87 + contrib/preflate/preflate_constants.h | 52 + contrib/preflate/preflate_decoder.cpp | 162 + contrib/preflate/preflate_decoder.h | 33 + contrib/preflate/preflate_dumper.cpp | 145 + contrib/preflate/preflate_dumper.h | 57 + contrib/preflate/preflate_hash_chain.cpp | 108 + contrib/preflate/preflate_hash_chain.h | 122 + contrib/preflate/preflate_info.cpp | 55 + contrib/preflate/preflate_info.h | 35 + contrib/preflate/preflate_input.h | 49 + .../preflate/preflate_parameter_estimator.cpp | 84 + .../preflate/preflate_parameter_estimator.h | 109 + contrib/preflate/preflate_parser_config.cpp | 34 + contrib/preflate/preflate_parser_config.h | 35 + contrib/preflate/preflate_predictor_state.cpp | 323 ++ contrib/preflate/preflate_predictor_state.h | 119 + contrib/preflate/preflate_reencoder.cpp | 106 + contrib/preflate/preflate_reencoder.h | 29 + .../preflate/preflate_statistical_codec.cpp | 789 ++++ contrib/preflate/preflate_statistical_codec.h | 90 + .../preflate/preflate_statistical_model.cpp | 91 + contrib/preflate/preflate_statistical_model.h | 52 + contrib/preflate/preflate_token.cpp | 43 + contrib/preflate/preflate_token.h | 84 + contrib/preflate/preflate_token_predictor.cpp | 447 +++ contrib/preflate/preflate_token_predictor.h | 72 + contrib/preflate/preflate_tree_predictor.cpp | 675 ++++ contrib/preflate/preflate_tree_predictor.h | 99 + contrib/preflate/preflate_unpack.cpp | 69 + contrib/preflate/preflate_unpack.h | 25 + contrib/preflate/support/arithmetic_coder.cpp | 212 ++ contrib/preflate/support/arithmetic_coder.h | 224 ++ contrib/preflate/support/array_helper.cpp | 23 + contrib/preflate/support/array_helper.h | 25 + contrib/preflate/support/bit_helper.cpp | 59 + contrib/preflate/support/bit_helper.h | 22 + contrib/preflate/support/bitstream.cpp | 120 + contrib/preflate/support/bitstream.h | 126 + contrib/preflate/support/const_division.cpp | 114 + contrib/preflate/support/const_division.h | 170 + contrib/preflate/support/filestream.cpp | 40 + contrib/preflate/support/filestream.h | 38 + contrib/preflate/support/huffman_decoder.cpp | 110 + contrib/preflate/support/huffman_decoder.h | 62 + contrib/preflate/support/huffman_encoder.cpp | 64 + contrib/preflate/support/huffman_encoder.h | 48 + contrib/preflate/support/huffman_helper.cpp | 74 + contrib/preflate/support/huffman_helper.h | 34 + contrib/preflate/support/memstream.cpp | 51 + contrib/preflate/support/memstream.h | 47 + .../preflate/support/outputcachestream.cpp | 29 + contrib/preflate/support/outputcachestream.h | 67 + contrib/preflate/support/stream.h | 45 + contrib/preflate/support/support_tests.cpp | 180 + contrib/preflate/support/support_tests.h | 20 + contrib/preflate/support/task_pool.cpp | 15 + contrib/preflate/support/task_pool.h | 48 + precomp.cpp | 3192 +++++------------ precomp.h | 22 +- 93 files changed, 13586 insertions(+), 2326 deletions(-) create mode 100644 bin/precomp_w_preflate_msvc17_aka_vc140_x64.exe create mode 100644 bin/precomp_w_preflate_msvc17_aka_vc140_x86.exe create mode 100644 contrib/preflate/LICENSE create mode 100644 contrib/preflate/Makefile create mode 100644 contrib/preflate/README.md create mode 100644 contrib/preflate/main.cpp create mode 100644 contrib/preflate/packARI/.gitignore create mode 100644 contrib/preflate/packARI/LICENSE create mode 100644 contrib/preflate/packARI/README.md create mode 100644 contrib/preflate/packARI/source/Makefile create mode 100644 contrib/preflate/packARI/source/app_icon.ico create mode 100644 contrib/preflate/packARI/source/aricoder.cpp create mode 100644 contrib/preflate/packARI/source/aricoder.h create mode 100644 contrib/preflate/packARI/source/bitops.cpp create mode 100644 contrib/preflate/packARI/source/bitops.h create mode 100644 contrib/preflate/packARI/source/file_icon.ico create mode 100644 contrib/preflate/packARI/source/icons.res create mode 100644 contrib/preflate/packARI/source/packari.cpp create mode 100644 contrib/preflate/packARI/source/packaridll.h create mode 100644 contrib/preflate/packARI/source/packarilib.h create mode 100644 contrib/preflate/packARI/source/paritbl.h create mode 100644 contrib/preflate/preflate.h create mode 100644 contrib/preflate/preflate_block_decoder.cpp create mode 100644 contrib/preflate/preflate_block_decoder.h create mode 100644 contrib/preflate/preflate_block_reencoder.cpp create mode 100644 contrib/preflate/preflate_block_reencoder.h create mode 100644 contrib/preflate/preflate_block_trees.cpp create mode 100644 contrib/preflate/preflate_block_trees.h create mode 100644 contrib/preflate/preflate_checker.cpp create mode 100644 contrib/preflate/preflate_checker.h create mode 100644 contrib/preflate/preflate_complevel_estimator.cpp create mode 100644 contrib/preflate/preflate_complevel_estimator.h create mode 100644 contrib/preflate/preflate_constants.cpp create mode 100644 contrib/preflate/preflate_constants.h create mode 100644 contrib/preflate/preflate_decoder.cpp create mode 100644 contrib/preflate/preflate_decoder.h create mode 100644 contrib/preflate/preflate_dumper.cpp create mode 100644 contrib/preflate/preflate_dumper.h create mode 100644 contrib/preflate/preflate_hash_chain.cpp create mode 100644 contrib/preflate/preflate_hash_chain.h create mode 100644 contrib/preflate/preflate_info.cpp create mode 100644 contrib/preflate/preflate_info.h create mode 100644 contrib/preflate/preflate_input.h create mode 100644 contrib/preflate/preflate_parameter_estimator.cpp create mode 100644 contrib/preflate/preflate_parameter_estimator.h create mode 100644 contrib/preflate/preflate_parser_config.cpp create mode 100644 contrib/preflate/preflate_parser_config.h create mode 100644 contrib/preflate/preflate_predictor_state.cpp create mode 100644 contrib/preflate/preflate_predictor_state.h create mode 100644 contrib/preflate/preflate_reencoder.cpp create mode 100644 contrib/preflate/preflate_reencoder.h create mode 100644 contrib/preflate/preflate_statistical_codec.cpp create mode 100644 contrib/preflate/preflate_statistical_codec.h create mode 100644 contrib/preflate/preflate_statistical_model.cpp create mode 100644 contrib/preflate/preflate_statistical_model.h create mode 100644 contrib/preflate/preflate_token.cpp create mode 100644 contrib/preflate/preflate_token.h create mode 100644 contrib/preflate/preflate_token_predictor.cpp create mode 100644 contrib/preflate/preflate_token_predictor.h create mode 100644 contrib/preflate/preflate_tree_predictor.cpp create mode 100644 contrib/preflate/preflate_tree_predictor.h create mode 100644 contrib/preflate/preflate_unpack.cpp create mode 100644 contrib/preflate/preflate_unpack.h create mode 100644 contrib/preflate/support/arithmetic_coder.cpp create mode 100644 contrib/preflate/support/arithmetic_coder.h create mode 100644 contrib/preflate/support/array_helper.cpp create mode 100644 contrib/preflate/support/array_helper.h create mode 100644 contrib/preflate/support/bit_helper.cpp create mode 100644 contrib/preflate/support/bit_helper.h create mode 100644 contrib/preflate/support/bitstream.cpp create mode 100644 contrib/preflate/support/bitstream.h create mode 100644 contrib/preflate/support/const_division.cpp create mode 100644 contrib/preflate/support/const_division.h create mode 100644 contrib/preflate/support/filestream.cpp create mode 100644 contrib/preflate/support/filestream.h create mode 100644 contrib/preflate/support/huffman_decoder.cpp create mode 100644 contrib/preflate/support/huffman_decoder.h create mode 100644 contrib/preflate/support/huffman_encoder.cpp create mode 100644 contrib/preflate/support/huffman_encoder.h create mode 100644 contrib/preflate/support/huffman_helper.cpp create mode 100644 contrib/preflate/support/huffman_helper.h create mode 100644 contrib/preflate/support/memstream.cpp create mode 100644 contrib/preflate/support/memstream.h create mode 100644 contrib/preflate/support/outputcachestream.cpp create mode 100644 contrib/preflate/support/outputcachestream.h create mode 100644 contrib/preflate/support/stream.h create mode 100644 contrib/preflate/support/support_tests.cpp create mode 100644 contrib/preflate/support/support_tests.h create mode 100644 contrib/preflate/support/task_pool.cpp create mode 100644 contrib/preflate/support/task_pool.h diff --git a/README.md b/README.md index 62b43a0..23822e1 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,20 @@ Precomp [![Packaging status](https://repology.org/badge/vertical-allrepos/precomp.svg)](https://repology.org/metapackage/precomp) +Fork note +--------- +This is an experimental fork of precomp, that uses the preflate library for +deflate stream recompression. +The bitstream format output by the preflate library is not stable yet, +so do not use this experimental tool for archiving. + +Also, the build system isn't up to date yet. I'll provide a CMake script +in the near future. Also, importing the preflate sources in a GUI, e.g. MSVC, +is pretty straight forward. + +For the time being, there are executables for testing. + + What is Precomp? ---------------- Precomp is a command line precompressor. You can use it to achieve better compression on some file-/streamtypes (works on files and streams that are compressed with zLib or the Deflate compression method, bZip2, GIF, JPG and MP3). Precomp tries to decompress the streams, and if they can be decompressed and "re-"compressed so that they are bit-to-bit-identical with the original stream, the decompressed stream can be used instead of the compressed one. diff --git a/bin/precomp_w_preflate_msvc17_aka_vc140_x64.exe b/bin/precomp_w_preflate_msvc17_aka_vc140_x64.exe new file mode 100644 index 0000000000000000000000000000000000000000..6f6cb157e97be9230267382572b519bb6e5a44b7 GIT binary patch literal 771584 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�q%| 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�vA{y^Q&g=M#R|Zryn> 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 literal 0 HcmV?d00001 diff --git a/bin/precomp_w_preflate_msvc17_aka_vc140_x86.exe b/bin/precomp_w_preflate_msvc17_aka_vc140_x86.exe new file mode 100644 index 0000000000000000000000000000000000000000..e81d19cd2187eaf4e218d15ddd12b2eecd21f4ca GIT binary patch literal 703488 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ȓXiLbb$(S@HceWSP2vQ4uW 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 z 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

7uUhQy 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�|vdOoDzp zx(l!FdgQ+>%KCKy;%?Md@K*!7aT}NtM)o3IDZH`i>HgUd{(%F}A>BY63sU4n|Mo2E z-AEiZPN-f24mKN{>nLK!k$&qRagM?9t@)4D&l`cU|(>+JLPV#g1|8 zuKt1xz_|qqDS=&Yv~-NW*}{O9kSlUbv`Coslv8~84MOB`+0pLN3gI^dS)%~^Y6!H(L%NNPt}1hCO- z%XARBs#V1^-HG6>r7kgj7cn%Yg^Eh_eo z)CUQdXHf#l?vuc9?;?gM@`)=9aQp-eK) znYfA9H&U_YDuMIRkOWam4MT)SA?Wgg zuYMdYpM)T8@)V}i+)}_AJSd;D;x@0+83gd0@2bSt#tnF4Q9A7|$B1PI+iSUAQ3KTK1-Y$C{ga^4uuTS}Q=V9gcS8d6R7}$587oII zdX}4u5frauE$BUVuOLi^4UL^_0axlPei#KpJ+2N9+(WCzphXJFOKzl)90-e^(OC1? zi7*)R2J$0}2KS|ELVFnfFe@pcgu1mD6ur;cdQYinj5Lgbb5(egj(Slm%?pVJFisz^ z`_LelD7%I_kYPAL(JYOa7|;M&w1Z?kaC!py&P%03y94 zFhjBJ9tsJ}J&nv`7+D9)tW_z|jdD1Lcv~5a&Fj!scPPWFw0Qd?#&(+_UJ7 zAnC5Bw*b9uz+1S+y^kLA-QDzfm{$gO$-^l3mnfHJ{k`s)^r`ZvWg}~L3@Ig)AzQ!_ zL}7p$hi=V#1WLj`@ugspe4Pahg z>3)VfF$a7f%9Tarp#YbA9fePq;cBbCJ3__VE8W!;RV<^(mJ9V&-cLtk-KJb1%yHcW z5hDdHK!^GALq%1jl4)9IK2{^>68Zo}SO+#$Vd2N94W~8gu;%PxBlh%xt8ydp#01N! zbnl~zw?D>hMd~arL)Nc;Hl$p2P2@4~=t{~EQcEL1S!T!q79X;^H{?&#b;rigQ zFz&5jkD&*v~liTZ@J;^(+YO&=1W+LXNo|MwZpMBD@zLGY7l$_kMu>?`c%~$Q? z?mIbM&p3>*aA0*L4HKN6MCAB=*2g%jt@<#JMAqK~=*I&(^qUg=^f~HB`WW>BWUI~b z^Y1)ltj)Ozzv>-Fdc&cw%p*A4-52{#xe#Ajw$N5T9(PF};m4|1l_ z_>~lj=u^US*kA$6;%`n_Lr=}(Yhee{4?uVk$t1VZY9U3a-A&ZsP%%ZI4DHr#%@)#Z z%ky?hecw7Vr4M^Uz$x!nTG?^d`9X17#?rhuA(2bz=u3;@WL)g}x$2Ty*sDm>m zD5e%AmW7sydQ`-N7tmC6yn*Juln~7e%y=m;=tzfQH|06q?~2*S?$#-zvH~%{ONM5K zX+`Dn>=7$c^NP*y{a$O&4Wjydf3Mf~pWhE%v!A`zv!3T!&wAGVvLzUboe_5t95x^f zAeYtwVp1b~t^~sYW=RlJ7~ywIFw(Kp=oEZhLkzfuA&@CQqY%jSS-k5^pOYY&K2H!# z9Xk!p5n^i^Na#O!*9o1FAPN1KU@#$LBZ6e#^oc-NWUEI~3&ASju3mmqcDLxN;_iv-E^RtW|&4e_TG zdCH;JW|`ZeLv*c<3>n9BR3fi{!a-US6r&$Sm<`?!@u%p_)$H>LGzddsj{ynNT%ONkW9ao;2$yN z<@bRpJ-{e3r3WR*lzuJ=v5fFmZat-6NRUhqOOQ;zl;9sR<#0cc=@b?#$@C5hlIc`g z*vOPSfpwf_B36kk%f|BVA5@eokksz7AC_ys)9|;CBZCnL$&>YBgEsLvE z?>Y&Rse>Sx22??fEz%0D1`--aElWb)uQY?1^ieTD=neWnBhrEkpi z0utD$_+4b0CErUDB;U(Y6Xe?kDJ-iag_2#EfK-kC;~fxB7)=6RV(XtY+f4mJJ?vS z>gGpp`)BA`z~?%hPW~_9bE^1%gU_B|6a2=x#xu!*nx4c?f;7ks2{OwvW!K@44AR<& z&^SM#@qR)R{+tjG{02%i#ZTxCKcT5j2{o<rBT>kW42Klqu!WBR!>)Bq*9035sS$f`LpMTh2B0T@^JvbS^y7n3&ix)rc z6GJ3OO$;R%WH9SE=jd%yVjHzU+34+wDtzrFqWPMv#zw{?Jb}!eesvW2)uHO@fE*7< zklEmpAhY2?2{IcVl3-vqG-j$as;EQ!6?Le;q7Kt5YS1)DkW9lRNTv}IB-2O<{t?qz zkSj2yvni)ExH~0CHQyzrXZ<=yf@C^Zf@GQ{K{CBtf=!uT@Qr%oAXgyM>nNvWdc6e6 zw2PFUOyea;rd=gSrZ-5COmCE6Ak)TH-U%pyOgl4*WO|JR$@E%D=#Q#0rBPKD;;+g= z{Z(05)2ghoL=*9Wmq3Xo;a!&~LxPkjlVFgEH<{w$8f2paJcX5-Ox+z4B(15kstZhA zKvjonIaJ5|(uA)nn<=L)W|Z&Kr?H|qpD|LO=gKs1H?$c)PT~|ZqIYTohciX{iA|L4 zJ%v%^OYpbCC`yA(cknxR2G=rpJu9}Q|Phz8Z#3=L+APJ>zH zqrof;qQN|Fh6XJ}r$M{%(V#sA(V)RKLxbk3)1VOx8pX71LJh?U@njga8QDldo^>qI{c?B9$$HTnSv(siT{JdVWGO73%~%jiwsXzUU@NK9VB6`V!8SFB1{>XGXt2rF zX|N&p(O?4~M1!4xW@xYrq0?Z;LeMB?Z-Y=nF}omyE*G<3Lg-R4J1c~Qn%Rj7;>BK$ zm)A(4WT{K@c9UhiwJ?fZrQmR{wuw;~#opE*g|oxv4d=);C8#oDe@{;idw~@5N-?{J zgc^$3UnF$7n4L&Mmx|f5BqWl<9%oQ;*d_I|3*wdOuW;DSB@JN)?EVJPVE?!o8th%` z^0LqEqrtv-5Dj+LK|`;4y{)Y%DeUU&G%^BBi35Wm8XP<{BL{~bIt>m;d~$H05=4U| znPzBY`e|f%X%utFL~0Gi97hqlT+G20p-aUaaS;-_=SVDw7l&%i@ZvyEmzTpo(zsI0 zF(ILbVxB!Fbh((LM?#m1Iiw^ccyXv1#EWCmW_WQVtMlUcmNc#ubI?nup_n6KLYIp< zJSKFhm}6!_f)~fqLA*HF_Va3N!W^yZ>^O!e8QGpTu0J{W_mc@SO->!?G&rH)qrr)W zAW=9I(F_gFW9T$EyWyk3S&twZ;#1)IvIq7v$%>U{YJKOk^!k;PEWca7`l@5b;(DN7 zAOA1$IZ5=tq0dREKgJiQoqh6fj_Z%{`JEfT{G3GlU3_mbrh3uTac)l6G-vF5n&wPi zkfz0562A4npd9B!p-zL-hdvsdRt%!SsmEq=oD-Ki4NhnJXmFY{hz93Do1wv3RGkLr zR(&)$=Nd$Vld{dw;FPXTgA=_z8k_+3HYSGl#hf1=AFv)8qz}$7>ohp)?4!Zi=pZ>b zUEPcvmoeF`)3_u+y(DsKJctJ8&iynR7idnt>tr}3?-ONuV^KJl?jpuhaABbt8eEppX>hSZ$WhD{3_=aXT-G3TxtMDmgf10x0fdmK$G9*O#EXk3&G6#V zi_VJ+GNf^(n5#5|&=%+r+5#OyTcAU-Ex=0N zTut@!YHaFUj@8+5kyf(f$}ORWVlL+rx?IdPUP70Ox$sL!u;YSo5Ie3I``HB*39dKm zytoQY8dr+BG)<_XnCsPqE*EnVo6x0Vu51$$ytv{W#EVPf&G6!ay3UKs?4)s}m}~EZ z8j86fPv~+nSLq2|D(2EXA;F7F`a!(JUTVE2m%ZfRUNH9#cxCy$aBe^FhBsxJqnMj`2w~W*Ll}1J5Qg14B$Ca&K|#E@ zd5Aa9SVZS(CZ=S9{wAo$aMK1q`LoL~Nu6(SE{HdXPmt{&?)${#1jngv8JY5=+b01Z zm`r973QK0WRr|02sxd4YY81`AZ6DSE6{%HxAZKoHNGQ3yjLD zpUkNc+=^5SkDuV-i6Sj0O3;Fnh_tE})k!#G5_#2erC7k*!x>G)UkG%in6I`T`S_+F zZ{>v)*xtU9!ej_xaNL4qv!9^XP$?gg?X5lbeZDgeb@8g;z9||h9E=-e#^STu`!@4U z`vx~D;;RTwd?aM35s9iYw?XM#omztvJSi4@R%4Dc3Yt)+i0ebtAEuUj?+@w3uUTj2 zukNg|A}<`M{{8^uv09A_}M37HDj-39le>gUn2xwjK1&1mMb zTIeeTWa(GyQPS-e^)Nmp1WBrIuMnjpZIHlnnZYW}1;;Z=rE0hDczcHXf8KTST zuTXmGKK=^j8u)BxZ2}Im&8Q6b7Dv5^2baq9Q9{9*o%c!zGuK-Fm&H;PAR7*i`Af)k z5?38-&`wY^HVgRLoO8I*nQ8Lvl6DTa@GI3`(-P+sjQS}ldwcJBv9f^sT5t?UoSqPO zffS~DT@RuS!B_n#7{beoODdRQLf=vH(V}@!s>4)TT{HMj*%lW9Lb2By+mB+6!87x+|&1p3>NYX zE=s$uyRo#^5SkX}CH5CZctw&?S6Of*QA@`u8;F~~Dq0*El+}m5EiQM;)YeK&{SX)O z(>2^<#Wi8`;9oRs5aL;WEA?^@I5{isInrbKQ-L&jwa_hyaFF_C`6jW1Yiv{XdsQ~EvNaD2KZS17X0fO%uCqWFIm#2Ge^{!hs?LH7pwc~B9LiErI@4EF zR$3QY>Ne#6V2(Ez&bT)JyU4<{xco9>;h5{RC&N+Et+FWMGB705838q*>9x1AYF`T@ z$4yittl9yWw!5(KJTA@f>qc<)^wrEOL>31YDcv5S z3ue6iW;HE3Aq`n))&A9hzK3{I$G`*K1X00TwcYpz7be3+7e!kDEOcAYWzl8>M4tJY z4xxBSAEyN`=C1+$8#NVOVb?NC26Os(d^l50LpP4S=U@ z&CZ!Sr(w3F~HKbGZY}SlmBnS%RqM&n zWhOMp`0lIL3v!`3_V!!xVOWFKqL1j`$b^f|<`|QjhTT`TtAi4`-7eB3@nkZ8hzRg% zq%YjJIU*wysV&-xuV30tr~%rK)4mfaHR<{E11chKKAoS`B%k6%88d1-fF|?lEkNpL zGN-hH_UMGHj5jN0*Vm}fv_~139*vnGe!Mot>Ktd##{CKv_USE$t9p;cY*EZ@hQ(V% zFIOC+kF(t<4UdxuhVkC(Y2-_`iC6rM7{X3aG>%W>YST>ZrnXEuuaY)<`$0V<2{oDA zIP~=sk}r~wXRsg?-2Vkxj?Yxp> z$m9iF{CVL_G}M$@Rdym;tsqq0s@xv=5y}FtBE)wzukys0c(C$<=;Pp02;8-N%HqP; z3BQC8Rk$`=yC#R<35>%`Q%rU(NA>p%Vu>_(&vWB!_P0qR@Tv8h%2Z91veZ*%JS$Rb z6s_!PF+W0YT&S}e{jh9fu0YmaM37?@nAvO8^y>GA!P`6(aOxrRt7XyR+7j_orbS!T z)P4BmX%z$bimPVib+}qcJctC`C^HaLaBc6&E>Or}0N(+4znk>@f}XgMMqHa4E&a*@ z{Y=vDHQi5Kg93a$kvgpp?kEVFeweDJ*C&3eX}GY8c8xjH%J6DVvf%Ii7Wk-QGd(eFAt|IJ_~7R&M0t+RIkKR$AuPV$GhNO zF)X}ZNx|#NpZT2_Sz)=->vLLYPc8O!Yb>xJTONMw%hf0ob`aq{_JwMU5s>yn>}Ag; zLTZc%DYbP|M;L%`-FVMpBR`gl6f=Z>_#`cqaWp|HW4tGZpT|SqG{$&O#}F#fQbu0F zYzkv;(*3o4&}WbenyoA;dKZdr(~Ngt=5gNn+0&4T+Mc8!g^qi#6DH&;!&C6fzsm4o zK4^pwit|Cl=AU*wq(e5v$ZWC&Q>_T+HbrGhd87RBbyO+d6pA-Njfw{<6nDEC69-6h zwufd3sWBp?)YegIHabAF4B=mSpfY`)B28{(@+A-I6Wpe-oC!ZL0KI}$CKd_15yknT za8wQa_=OgxD0x?9Waks>6<{InX3m&iPMq(+gE+HJ0_P@_XCmXG;75`aWnL9u5`M|B zWxnQz~O6zShH)$VP}6P)Iw?fF+cRjEDnyj zS%$Owt4fk2??6f_O|c;!MrP2Eb-QCA~^PqNF&Vtrvnv}gFfXG+jDU58UpQkt%S z;AS`N0|a3{7Z=?9AKiGquOCxwVx1%;^z!d5tB_r26nkPVWLUg$LeUY-RK%fz%UpjD z-J-*Z2NS}%rLJQPx8m_WV{_rJFrhWAk}n~v&FeJ0;LB1&a*R0C+_6i#3mZwuCldu zTnMwTa3r&-3$-s+W7cCjS>35dSy3nx%B@^O#8V-pqbWtY*&dS$jGrWvfgjC=OHV0 zCxq8OG*#&sbr!$q%ye3Q+nPv`4Y}PmS)h#+arxbf@DYxxhLp|p@f_aFD3#%i!asp$ z{wQC;y}?*CAph6<{)P!HPfWDzI%6&g;2b&qq5 zvCgIrH|jB3A;w@S&aVub;#^`-!<-RGc}BZIJ&bQhQK$?llyd+?#}_I1yEst9#fG}p z_;z~#SV-9uQZ5FH!I@^j7to8wm`_7kCR{?t%ci|A z1z2zdMnwu3-UhY`ECHXl*UbS04eDT~QRGz82!pxc9mIxS+&l0T(hd{SwiLn+HabIf zP5-{MW=d-{QgmZosMF{iXQaF>X*l-IKB+2va+?d@2P`CuKo3$KZ@{;tg&=QYE>2xl zUoqSiGC`YtBa)G3VB?+6i^2>egwUMQbQ)2c?=&LGhNKbXyqKJO!VYK!BaO(eq9LZj z!6u|21QG~c!21sr-x7KeimqELwQoX7sCYL&Q0~nIH$Hgd(X~IyOL&P{GWjXKRYvGFV!faV5 zi1{Qo(Pc%#!{4OEHt$AfJ&OB!hrACRm_;a)4-mpyQ3+n$IAW~W^iy5sNLxQ8jNTiBNXj7 zAd9$0Z!Z_Zp?AVTR8#DHRDZyhjPx||qOXgNHFFePPtU+iMwG;xY9TE2#_j<&r&LePr@dG2hiYeI{WQ3%;8PmbOF!G;d5Z1c%4=` z+)Ak6DApe%C**{pR~q)2C#DlBW0;|@KY{V<_z}L%Ah<2-_x6HZbgnv8naW#c71!A1 zm65~Jk;37YS);MW74w3)lFPL$R$rCRP(K4M3NpgBA`ISqL4}!Os5C_OLtMbH0=woK zT<9Fuzd_xPTY-RCf%~`A{gn}~f^J0`U2;$w(^5nlooU0=%F49S6sIx`mmz|9qs3%h z%gjI6OS&;r3*ngWf(i}Pf)hTX5H(YeD>5G+{#o5m>JxoTZzdtKWA$jocAXlLgRkY7 z92Y#c7|+ttzLvJ2bVazM$}^)pv6Njzo!^+z7$6K(Cm9P4qM}PRwMwFez3d&EzVuS!bcD1rqxh*;;1Xsf`q^D1UseW|* zlQlq3Q&T%ZD`_ceY8*7KRkwn4_(D=fin??dXH!sQ@rVwZkaLbOIjt7wV$78BDz=?* z_|k=uQyEe9&^kRsP&MpSZ#STNsvKfu-c_Pq!5`)$hj7guaeO77{R3=X;uUV#51^)X za*Y|--)O(uu_`*m9_?7&54#bd2x!Jp>2ZASsfz%pYsM^ZeBQ4Ohv3x9Kfr`4fG+Lf z?4Y)_Hqk`Z?`dM3nr4!Wqt%Rw>KJRn0o3AYo%qw;Y589(CHntBDbYeH&RYep+} zBP`kNWDC3ut3?C*N7$p)%!%q)rnfbyA-%(qUdI}!y@O{NOh{j}VX-L3WSM(3A~&5o z((46Z47CPznd7p@yxvS^lQhR}Pr@F@#SruT{H~xYHw250ZN-dIY7J@$^U%~9*6FwQ zx1Y*0WpD=PE*6zZ8oq`;p08(NL5=VYJ$0Xb>ezmmnc|F;YZ4xlYA_#0$9b`8Oh{>A z71r^t;VI}pzX~HQC|!OZtYdXDhc8PUtF(~ZiKJ~_$AYD%*6<_7>i`y}eu)YW)oG>D z4zHe=U4V;Hzr;*#-9V7}s!@<(Qo}_YnEJ%CMU+Of& zgAcFKFjC8>vJO_$Mx*o8pSZn6VQ*_SZ{Lf`lW9Vw2D`&*r(P@A+7xy`CF+K1XQ(p% z3>dT^YAHBq>#FAUR0p{X?USnW zI$(X(8KI7f(@Pd=g~Cubzvk<>&s(;(Gj5*AHI!wmy*kROPMGLyop3-M%Ca@IJ2;|v z-G|~8=gC7(`SyYA<|I#2nK?DxsFt}GflQ84nEoXUCCAvbylHa{EQSp*N=3DwQdiYD zezUkz_tDlx5nx2~(9gnl;xg$`{Wv@9D-lCk47Q14U@p7}0{jZ~L;EBpU`b-w;$7=t8DeqZNvFrfQNph@%p4Cm;?!`(v`QluT=h6sBt!W@2^# z@2Ak9c#A?hN*t<>bgjZ*RNQA#w6qTq40EizkwyDjp<>hmzPp(}0BH|w%A5+EFvng| z5L<9aZsq*I^jZQSedQ_ zE2`6B5FOKu&eaxuq!fXXQbmQKU*jf-=I$HpKqJgA^hAy5CVSAFtI#)=qOKzq5X+5H zBW9w^>SH9{D2z8!=)XETFCtTW7Iihh&JZiuwoqFarJ4#u>f-TG_X7~=!N9FG#My8D zDAkl{9jBe@Le-)3D|xiWuulj|L&C6Hh%I65QweBS!CtaJn(+^JN1t z7!2E)RFiibgW7p8>O%vUP=j@|6Cg7K?T8V3IZbGkrEj&*mwj<0`+DjRaUqeOY7s|V zq^zeq>9agzCJO2cXx#%K=7Sr-c2EvgDc0o(P!XGzOICOm&6HHJH^)J9V5jLtQe_ z**@X4I=B;hwS&7md(M~{fGqXL_0CjZdBf6fbN$aF&gqBPmYLVjM0=HgUoxOcYyiW& zLn+y`M)oRobK;4WIO_1#RW&z8gl`@7cW{gZ$mcGHN}V#csr1BPS-#W#0q28>4)6d-t9>`lV_U1 zcI%Na=p~>Xi$|lQw_}JV`oD%)G+l?>m)VYS9v{*E9iq+0CYPe}y3lR-qF=yvYQ3u% zi~1?30!MirhcEDkpbS9ynT2U1{6lOMV|?^C4Ht1&riuX>>QHnp#1IXj$y;CGQt~*q z@2OauvN+T5wOo#XoEQ$J#c=`@L!z{va!z9PXbd04kbS1VnPIi+twdz~rupl)X67G6 zlV~n@5E+(}g5k0q*OqI{VQi-^wcU%XL7}>qjSh~A>_L~W#)>Ts}t1JmsNuQaATueG+Pj#94^&f))(FX`|j**Q< ztlG{xuENj~&Apb24|vW*t&h42Q@DqH{yhTyQDb%qsKotMCZh1}c~NDWL{rg?D< z0i(N5q%x>!$P6n-!|-j_Kd3-S)K`I;6b-97ipB+rAO&QX3jLmi^$35Nf0o;Q`6pH@ znjV&N&aKDHj9r6%9T$FE8m>)1F-0qbvC(H{XZk6J=eMN>^+H{I$ty3v{IYuF{C^MB z9XOfv)zY>lK=ilESLaC4n zB`4IWxWpcVP;5&Z!I=mES(TXE5An7tQokvI`i;k&Xp>R`{W>QdgCfet7gB7)3eK4eSS|{VuI#tQfEu-zDBxjLMT1k++xr!!9{1RfV@rjU0;3J_ zeKzy3ddy%UU7W<)fx5?jOz)XWRE|nG5S7TOSnSd;N0I?1;{}t^GDRr{Kc8cu;fox= zgd9rMNvE)r!~nfvR(Ow`6)xFqk_O_f2%+NXr|^viH4L&;4vURLvamcH3zL9;!Web0 zjEWfO4WVZ8^|Ue1%APi6bi>8OuR6M4KqtHLc*;A-koK_nuh@gS69=GFbTTy7^T#NX zYl-(Dof?*~pVk5kSs5Fz+G67hJS*F;X^p*yZ2(2BF(m!6G&12A$G1vdYdvGDRixKm zt&WcE=bT>c9S|727DXL6R>s1jt^&$HgttuE%YMJGCo03SvV(3*hkUkVZz(>7;{F-p ziP`O89sIU3cmrgik(`5(kV4V04k_yB4naoZ&3Rj-pj4ORsPH(x^wjN2+-;wMz7+bT zOsB_QOUXSk8=>{2)Km5Yn0x-TS^BlW_Zf%Y55p3}ZbMy5KmFg$_qsUDyEV0)Z(GxL zkQwR6yygSh#x-XnP_!73VQAIpl}NsMd(}7& zI&Catc#0gt=&_vb8~U$L2HIEj@6|WzksNfePI+PssA+Wz*wpXqX*m6Q3PiED&l7W; z)GuJoHEFpi&!l29y!U%3lXqj1|6Km^XvNmX6Vm`32DemG5L|-b5vm>Ya`wS4Y!5^~ zWjPS^iL4k`dad@sE5CWNyBA}Hq|B-{aDu^Jk1k3d!MmMjJiaOP5BRd$r+7w)*Qj3- z^aT{5pI>0$t~7(SGNNPxcU>MvMQ_9>2f=^;H_EFRa%8 zZvD)ncwAT2TOn#IjIvf)F#A$C=@eED#nNIA^;+!4R_l{SM6Zd$2X!Y~@*-5_t&qBK zsHfLK;sD$B4SK??WGkGh7VKq7NxIE`o5voVnSo86sTOswRpYlPRV>OIomd_#vIr^9RoDXyoIP`6@xM9*rb)S z_&NzvAGLo;A7yBB{rbQVS?w&&QYVXR;{95=9tv6hCklZoG^ipKs^|;pvq=c*P}7gQ zQlqWf7pPtSR3Dl)hG?l;e{j2IWq5z6AA9k2Vt#epj|J1esE&Q=0X0-?eJ~;ixv*2N zV$T59&O3;;a{zq<_d2vB!U%)Fh~f9j)X=05dn;#4tOtp`8b3>N_E323L?;3Io`4n7 zwQCG7z5H^^+*a8&zWy&H*FMEC$ur!bV%w?3Im)26Puc@&cNo-2XRI1o*C~IMNwJxn z9WXdH+S@o|>!O@fjCjGidzf>wQALz;ZW=HbtcIy%;QK(>V1Q-qc1e581+P$B8OD5e z5Z1qdm!!c)`vA2}#Uv3{-0>sQ5yt%wSj@z>0dvw|?t&P{#qtpbqztR_*ad;b?oe)( z7-0}w6TsqjLJFCUGpM~(Ed95{k4_F=BMr_mBsb20F zfBq_?QW??-i^jGV<1`~@jCL8kQ-&q$^F}J(&Lrw9cfxnSHQFzLS^~Ylh)QJxsyJ^v zZv#?dSQ-=`{CxNqeh+^~ZnOASh}eYw=wSH*>DzvXKEg9J>>a_$W>>ByORS8dcVLE4 zsu62&DPr@>PT!PiMrKZ|dQlt0Icgq_2QEs1vz==U_x7?Jgt*4A=Pf`E$;uOMZ*cd) zG4Z4*W9bOxv_156`Du4Iumo>jOE3p5k{DlS1ITV+P)f1b4G^uxG(4vBjP}}7@tCm4 zX|J`$Jy+0fcuwe)PjA{Bw;b2}Ms?zEOe}vpNAtIjg}=!r{AN86(@#92x{F6=qj-cH z#G|Vs9z7bCjZ~g_D7+`$)Kq12ym%Tmcf%7?5}SMTz2F$;a4N$W12qKyHZgE>cf3`G z$KjW9SBA%nQ1n^Dd+Jb*VeoRAs=B!q9$!y{3QV)0H>(pEu5IQ@XMBH4p+7XppWIA>FL z;r{?As;0tC!gno)SK5>KneN8^Oy*C9mP|amvCfz?N8{S`6vrTJRdEdR*nVoB2o|>_8a0_LPYD5@<|e zSs1B31`q8hevsv@vS$*pfT3E_<|`hpFMrk$Wxj}5B7!vhf_%7kHvnxMLS#Ak8Ckne zTO!}J6qFaOw}|!+Mk~)j2W=C!;(iA|B!njdQJ(CPFtT?Lv)9qW>Hl@iZNOn3gcPP8 z+cXDyP24>g(;dek>+Q}cdSvfInaSS4%Is20nG9PS^iDb7RDuKbiktH$*(Jn!f>`?n zR%JLNgD}c`(GhUMoPzcebTvh+v#a%qp8kVuS7&Ig=!evqGjl>S)xI#5U92GvYgI^( zS`VbQSVxhv+l-iCdXDt9`|+#x(^l|NuT8`Qm$diQQlFRG-s`m=kwm06B0~#7;QFKX zaBVUG^xH$ULF73_PlQ@gmn`Q%crnU2tL8@Woq`qExtg|B5<&e{tA!$V{;K~fAQS`8 z8ygp{R6x>ltu4fM7eXy8VX#1~M*h#Uzj-PncEPxGgL2HqD51wGKqSQ7MMH5jNTJ9Qbs0`t-%&LV_U_nFu1;aHtTC-|(FhyGU6lvLyT?(*lFvNtp zEB&lC5BZpFgPmaA)2fvt4y#r@a18@r^#;DE2cpi&P)7_5t1`bkINCKXHmn*z#Qgeh zVW*Q0+d5$5YSKtkZcBBDF>DBSQ|6i+JG&(vwx8tIv~qQ4-9=&DFtM;+rR8%rVSAmD z@liI+1@mfkhNNnn1(V}@>dkMq22Oo1><-z6T_cnVJvw`2MR);lL$rUefbD}!$Yw*Y zQnVZ&%a@jDJ>CX5rOv%AL^Ll*PJZ%w#KMI&+d|xhVvFEd35N*L zg8v;g4WEC*bIKH5_d;1Jnr12r6*v$+ufp6Ex&-H;^}1G4-~RzT<$TQ)ROHoNQjNY| z!TT^l>0L8I?>ogqya^fTMDCWkCVNkb=Uk#|m%T3(xodUyDFi?50#d+P=z<4Ou{&Lb z{C#vif1l0g?>j5``{8o@WR>?HU+Iz zhHJ9t{83lxR#=Wq$<;?;Ex(n^p0z9W0@_Y?tznc==I!Nd^R5eLBIU7CcELr@rmA4K zC|SDcgxJrhg9nC{t?egF=7erCBVz4G9m{R4mww?W(IAInezdeaJNJ6_huD*6{==SB zWo^H^^6sg%cXcecVC##T5}h0u{%{9d$K>nyh)%wqkEmoN<;f6RL}DoiGFm(myU)}0 z5wr)QGKqG~JqvTbpa^5g$ozQBiIfj;0u_UaN?TMxg{{T;>dovq*JZI9!X8&P+o=~4 zS&kY!F)4VxjleJoxKd96X#|nd>#^>bn0_h|2MDpwWRHArENItR3ie~gy)3HDa7DrK z=2lfs(NjNvz$tp@@)UAnX-ats%8P~=+G9OyC8K2lSUVX*}D=Gyba=PtBk z_NmXjg>!F*ylU$4J_~Jg7r-)*fikLV`Y~r1Qq?N;LaRz=p20cF=$v4(4+WL3^?&!6 zlS?B)6kC_%SrMU%tyA)1K4Oxs5n;GU4W4*J!ZQq)^{C0uKqkj$Ax;6*Md%)@&PIYU zc&_Y~6FE6?cQ9WcOLcnf`Emt%!6CNKLUkHp>h$`VGhR}#>&Lc0rXNRQnRXy5@K=ns ziF{aW>503|A=S>*Q#e+`YC65%Q5%8z^$QX9UMSbMY@+fURXB6Y=uob*nLg*r<7`(s zs^X+KN}u#jEESWwG{|^hv4|r#F_HZz8_8B+)UV=L(0=W27$susJFbC;skTvZcw4;< z-f>>o~-|m=!_H<1VzgF=(QTz@Rzx~8-Z}Hnx z{JtuFc_7)-b*1>ViQg*myHET+A$|{u-x~3IO#If0-{ay}6Th*j+B{uP3AkSTo)y0r z#BYQ6-5`FKi(iw#H;7+F{8kJ99pbk{{7y!?w&^RJj$~mTW>+HGQujA#=)5ye@|l@2 zA<=_^9^I;RRrGLmV!Y*i&H1k!HDX&o&TLu`*2xksRMu-I0m*g4DV5)eP};Q3!L z4T>rQ&(G@y17^s?_-OiJvH8e>lLu;A9kriDc>Vb~xLlzMA+hIAgdNCjodmpP#@xsx z;4TdrlXy_A7;BF_|JC^#$5+bK88b1TF6BiOagjo+Dv&qXTj1Sr{yPLuIRBksZv^S+ zFbZNk|6SPUQ++XI{0W&NxfXAdO#UQUkR%gDLRec0?hlGZ5Hw`(2&N)EBDKTfO-Rem z#Dim3jH#O-5*$qpf`+M4f~z1^>_3HQGPM?@wlz{~T53#y_BukFc$)CEj9uYP_{_%A z@7tGuF(of1|6*KTgn7%(&uh!o>crA~43NJ^Yms=cd>=NKi4=&8@rz1*P*`S6l{yWH z@XF~va8zW>Ze+|Ekuk9%W1@W-Ls6MACOu)f& z{BE3$r!6bCj*e4?BLm|nXE|!uWH~OZv3>4(As$tg;<{aS6XG1l>yMNkflj|&8E^R( z%@>kOE5%_K+rV$!1qWALbEH$eYKmX`3!>$(Ekgyf#!;;>*Bu9yy6$?Y^skZrUnzA| zTlD#z#I~0lnHC>Qw>x0^ci(&Li=8%GdX(7E3+eP8D`viy@-^x`R9Yj2ahhC!TDat#ZY@JkYZ{OC(C^6&ZRBihk_I>83=g)#O$~Z5HR{|lNc4|bv(zA zWnNU3WzPF01V0CGZaKs@fMlvA(w=4Av&@+XL12&Vdh63rV3ul#&w9zCOtxS3KIPQ7 zhMic-^M(24z&!`t{pR&A;vIB4ZvY)UyFMZ4E$mS*o{Q>Fn|J;~-UqVGM?cRp*Bv7J z-thP?%Y6Aicz%^-K64CDz?b2-=u(#X^M)*Q)~8wKJ9i_}ku3AKpCRJjEc4Gl0>=%% z{qXx0e!oCVwT=tQ>MkIHNI!oGk7{uE$^hVCtDQDoIdPB@KJ^IthC!#x-^Wl((fH#{ zljBqz(`|m&5bwBTv>Dg0`xa@icRSKUv18&ZIvyv_(Me-+d7@qXT5!H8R%-+Oe2qgR zapjFOnE23&H-p(^@|D?-q%uE_P@F1nPS+!+xkrzOP1d(TCrroEa}9B0szlsd_bk2D zanWFF_dc=~14qP>X3!T5Tr2PT< zx2gv#zo*SNmzBA%J#C(B_%t6l*e-LeIdeC>_mrKax9JOdpEgg4DiqJjW#xK-W_*Dd zNXCaI$$>zbzXY1Q)tI|sSTtQRcZ;%!$4T?VBj!oSiJfkgjLCbDvOVUEz2cmeFw$D827js5Mx$9}D9eFsQMQNyC9#7Y9qK(}sexJdwY*)O$s3454 zAtrTXePWe%HLmI`sYch^{pfl96sa%#0>UqyK=@gP+r8mfO-Ze{YPY$0OO&zPhfZ>P zi5^z~^fWK}J{>=#G5#swKTZ76#Bb-vk3$a_chPB*evW+IslWQz)gt;dM$c#TFVFeT zz>;6BRr{wmK3)%5wROR-d5y_cgIpBJy-jk3escSAI;jPdVY;~6!%w52r|{|Ch)hvD zyg{k_Kd`Kk7^Z3O0V+}M2hH9(O(y7+Rr>{+57Hm?p%Qx{u_JsEwiQZM>G;@2Sm z8{;1W{$Ap1#7_&t-(l54bbMwHUQa{UOuqj5gZ}Chwh+`-ky@vJfZBz#{xp$)l~sE) zfB;^LgI^zRM6ZaI6Vp$Ui%D{emn7&F*hFs5@YB$JMmO;p(8Q-(V^*x^!0O{4yf*L- zppq&w?FpuopZSlR2+DsAaa3aVECgnRS3IHbt;qkz_|E`;s*lGw#+<{L`_A}v#r!9~ zT~=+a9-j)wYi{uCU5%-40QD>1gXR;YxjcX-=~W~D0|?;t`ry~Ljp!APkV<)(Bu|lK zS1(Dw{=Y%y=r*D2e_s=y_nY`^)qT9CQ`B9u`a4+3GT4VqQ=DMB4Z|}k0Qz6zB_y-s z&PG&5vVLj!4iUF9;xa^}GVzD{K-7PYBZ&Hs5l%5enlA$Rp?rlj#y9*% z_^2OHzaBt_2HD41;Lj)iFyf!Ucv6=~)+d`9Su*dJ9`X(B=j}felaPDVc`e0AUk2f3R zGkv3ozn=INLHMA*_V@5R62FA_kNNST094T9bbRUquS0@g6TPnx2BGoZSBV@G{2CGb zdLEe&l+qGN{?Bh9Nj)Vo`6Th@Cn~HmJr?D`>s!IEo4v1)2ceI6UnO!u@axjx*Sqys zZv`@P2jmH%JcTaEv+^ge=5=|%0{XnIaV%Q!-meiW?m@&#^TndTEdP!1X}?bseu+ArWhNfX`@wlNI2TB77zW_{0mJApt%{;nOp~r$$h|CctN)z%d2*EEYbO zkmKI8PZK^`fKRQUbJ*(xJzE9Nt^l9j!so33pMJt;qt^#{p$MM`bsw)`7Yze>SY6kn z-j=Z=pprt`-(z)NE6*`{?Pg2>MQMKnoA}(^#3$D400pNeDC$~SyFWq zpO3sgzF4n%eSEQ=3h=2G+AIw4i57ZU8sH;sVordM%**isKGH^00(_*6-V)$5M^Nq* z;3IRcWq?m7fpY;m_gX-A;d3Iu$0B?V1^6_GRO}4!kv6(5z(?A|a{)fGggg-7BklO! z03S_I&JOSyCb(yKeV}J)qr(DxWVz}U;3La?YsLdiuXdjo&sz5z2=Wo1D2cxalCop^42h?Zczc~Vjf~ZeZO zeGs`wkm0~NpJaBB%w-I)gkD7EF+?Z|ir_37|8+K`=5ho_Txx*A1_f~IQ97y!(U){ zj5pks{(^hNLw;qBd;xg5#A_hlj~Gb#g#+YD-{7tZQ2xjVfIo!z-JSschmG-l{8_(T zO}vT3d(?{;6n^O-!e3>$-5c&oKjhAS&@W%n1JX`E1FE#sPZ-JYBqF6Cl8+t-ye~7T zCxg0r>A@b|Rq3F|O5WmLHO)_2Oi?allxa^P%4v+LkY3j`=JunEqLctBRzjOfM(N81X-Xxs0)K?4_^QV)%;jZ+J?(DZv z6F^TX_rv(oYuzQUW7mYYTG@zr#f-OrbUSHsF6>4gB83pWYPz z0e5yFKJD=>;?E*}kEZxF?yYYG*a<7}b-d!wyaxU4@f^JQrG#AmlJvNvrPZDBKnYal*{=co4r{}}P_X^fBj z;Q01BSdg9>e5FB&w%%*?RiN@JsTiLFl^gw3MEYOzCq~G(4w!oWGtNN9IrEK3KPp=X z7DU!_jR^Z}e#4GdN7-^u*SE2!0NZ--66fi93@h+z6n@34$Kdkevf#$U4S?$oXMtH7Y5u8kMDRwQ${EGb+pBUWYpgcgyQW#Rm62T+26%%1F2(xIJ(! zw;7dTaEsw~g3boGd*SYY>j!6mtNI_%f_nsRDcnT3-f&mLDd5My=r@hZG06S`=*$6p z2i!2YYvA68-&1fc0iVWmA6yL_|CYZapY8sQ^t@$MZord&Tk$;gwoz#ZzXrsM!?QOW z{|>`nJc08Qc%IO8)*J6TfIA3y8{uYv_IS8__+P^N+jv&M4TIlFJPn|81KbF>iEwwq zEr+`w?h&}>;I_hb1HK84e+_v52DCPSPY&Q>Jc~dp3vL?RLf{=lcm>>eypMnz1h*e} z_rq@&o(u4t1veSa3U?TOwQ#KgpTyIE=V?6ocQfDpI~WlO+Y) z7gLltI4j&@xD9aLKYPbCr33Iz#-@3_{_x48cs!yvTUo5kQ+g=(D0%o@26!Q!cPWdM zTxBkxJY@xZ?!so>9?AmcHvIO2>#5wL%)$Et!DBu!bAdG%?}-Qx47+{dJlnk43+CNB zcj%&pa{w<|m@zwd-t0RU%vB~Vm^*iI6Yrt;0xs^Mn>~N--~|hsgbIdBM=0Zw-o-0M zC>uW*rfh&40l(|7NfYp$v**OkUa(-%U9-tfQ66a=mYX|!Mcl%<%i6F} zzdP-B&7W(F%UhIdo44@pxLa&3QcQC#la#dB@QzNK@M;_P`;O%_yq=WL|NtE<@y?p~BT z&z5};<8ki|w*cW_pwbO)1>6F7royutN4%EYpePgb6y?g45amLYL2=(?Qg*D02bQ9| z+qulJFlk+jBR33XuQE(zx(>bhl_5Vy?0c?oTp8F zKEMCd+gfgXaNvg@j_tSjXq(ZM71blIseL&0r7PnHzxrCt%#Pa*P2Ks};~91}V|-QL z4moQQY8Jj2_4HkBEO*=;ozi*5=IO^)-Fx5ji$BepVXNKV<%!H!zJKOH*QS5=-!SXZ zfu%R9>enY88h?4qy8oP*bN}S22_OBOcJlqcvtD|4?W*j5ukUf|Yl%I7dg)}l*It<3 zYQe@0_w+h+bzh!Lu`u0&vj*RZuxAJnt`SR=I-roOcvVBjt`~jz*fA;dZv=2%y z|MKDr&)IW>z8hNS`Oj0I?$CNvuR67C@%_C^?-|~+!ze@Y>lvT)eoZ zqgr(s_I|sXl*cQ!yc&0O&en@pZrn1a_Qa-9+ctgN@Y<{ox~g5a|Ld{u-?}y7wW25b zE_iUTK@xuYf?$~&_=BHZI zyeU^cy(j8a0XeQ9GGOZtb^(T_a+aEC7UkMG<%rJoMHZq>T`9-B3E&Db<0_rlb&rB_^q6?=&`m3Dc3?wx<@w=0+abhK>mrXQ9b zp7q~1>bsnb{qg&sI)AvO{^gBx&gR{JcB%>x;1Scpky~A;6ykt^nRlyw~CRANZYy-#d6ejOW*Q zp9**^!gc}XS9U9-c45%>-L*RY}?zMQ| zgs^FN{|Imlo?qjA1H#t9Q74n(*BVb==P?oRb9lZ290TBGfM3Rwm&ZH=oM=4nMA%L6 z+l=R(cz+7;7KCjD%)2VdBMa|8Ae?!46n@;G8;K|N&;jmsIP$H9{}=EdhG!_^FunXd zpB;WT!1cv@H@N-q!`VOO4Zt1Y@)5QM?o+r&;Ld^8aQH8S+Y5LoaC7jay!!w@2LE|* zE#Rn&o^bC1-iWXvfDgir1emH#HNr39 zNqeNNj|0y0h)cW}JXhiUY2fg}<(Ki^9dI8!$G|@m@EdsM!(D=-o#LF2vJb8;!v2fr z8pNZW5Pue)tMQxy{~d7rtRl-iMZBBf{)_jm z@ZS%38yxNE6#RO_kNI8)w+?PQ-dP@*uF1gZ3iue@4+!(%{UJPW!TT7%EF&x*Yw`X8 z+!KJmz|)E65`>Z0Uf`|5^Elq$1e^+(wrT?W9N>ERXTh<4Auj6;+Tv-r8xVd0&mZCc zFx>NSMR0Gxk0;3ALilrdZh*TJ?t8dGgfkAy8Eubwb`a0O@J|6e4~}_t4)3es|384w zfM*HbnV*Z`w-fIJ0q4W9-lUxU;77Y9-*Py9t713el)-gIcsbtN<9Q3h-o%r1Z$cRB zs!X_k@Y~IJaL>S>bx{VMGw@`7adeObnEk$Gcpkz#>nR7|p76UJj`lN~{&@Zj|6lMN z0QV(mFU6B(b0gdXz+w4h{l+qW2!6GsjpsLbXZ+jXXn&#f2mCgk$p{}0zf3%N%HRd~ zox}SQgtM%%{Qm?$*2_t7tdHB_83+HT@nl)O7x0(x9|+hA+zxo}gJ%L<1sv(;Bkb>R zUGN@`a1);U@$3qB0FHS>eLo6+mYr(2Z{hxh_qljF;aI=8;mUxg;Qa=`v*1|oQHE>a zD97h`kA*9P!x;%>8*n-RUXSNjc+#$N;J*-0(xtx*@Zaz}i04~ytVh_s6#yom$AR|` zyqoY0hr17c45MAlfj{l*BlvFtd;$JX0Nw_;430Ly^4tRcd-2{2?iu(o|HfJJbKzL-$HV^)IOf$>JXZsUBZn|0QZXynDt|{Wz=IO%3G+mH%qcyg_2_{u5o`+TX^K);|Zg;xA<`7o2w&xl>GOfoj=|%$MSCH({bB!Ml5;n z%r}ESTEFVhS69~^|N5SB?;JW?S@5|dLY2haKPkV>!TImB+;VB_JAD>B@z#*T zyFWOZa&gD2KP;%}WuNwK>Ss}hk4;HF@XD(_kK8ao`DR@HxG$^P&946VowILW*Jang zGoF0({m;x>J}h~zB($5cFns1)M@$v*?pAO9W96b-+l+e2@%30GR z`5xor3+DVYWZGRP&W@Wu|IXP9I@R=?TQEks^Yo98Ml85*OGwAEv&MCqyUf2<9N9M4 z>VEgClO-RiD+}Li__p)cci!IPtC%w@KYw8E=tGw$&weX?|G0Ms*pwZczwi0Mp}||e z9r@*>HOcqvI`G2fvxh&=anBptaAaZcw8Fbzt1g-KRbCInu>W)pOPo2n<;%NQMtwbS zNx1dp!J#)=EUiAeKhCtf>pR(*|1MY**Wyst|HIxpMOm_}?ZRc-wrzFUw$)|Zwr$(C zZM(}>7rJa${oQ-7^`G(Wb8#-t#ktt)8RN~!K*o&cnImT8%!quWJ@-(52JU5BH*I{4 zk|=GiuBmKg6rHD0!ymSZ?wfXZYqeEJA3p0# zUiL|x&mS6CS=96M;5MQT;U6sa$s(q9MX4CTk5g5GE+fmsu zExU@bVRY{?7maGvpTr6@>B?KMC1u+;Q%rV+nF1Dr?rcW`BBCb)Rq6TGF-!s7-H@Q! zL=9rms9pNCGQc=H*BqI%MuS_ktyMQ*lu34Lc%D^g;S7~%4O9*WnZ?HjcNT04?trWY z02(0Kn~dVowqHYC@5zDP0+SiDkO14W^t1J9(~EFt1A1}cM~LA5;>~m8mYGf9I{q|T zkG~dK`{SN#ovo`_E5?x~M3|ig{MW=cFcWQPK*X;c<5=?=gXbS#mii*IR%mYfPIwlwr8FMpquhzUwKsBSUfN1~x1_&@>V+I(oF%2rwQiBXz8HwDxdWV#1s*a`z$U#J` zjY)J4%txGDy-u#(AHc{pSIPL)G{?{e=FH-xg(@HoNForgDgCg!cS{hs(pOojp+h-p zW?yMe!$}DW1l35x4!|e}$lQ3Pt;?8XE7#F+J;JfF`r6?WSj>UboGu^W)=uQK;&WOFT-35cO=^al%>hz~kP!a?v}YgW%k^%Skz|8o0mQ z?;Lx?Pb|E#hXuH)w$(x9+^>aw3{FF79Iy+FU@(P#vqQg?*QsU*)R<;q#r$!fE z_s$b1Umvtr3>DM>X(i!0h~8@n@J`RIM#9Ub=$e0+Mv&n@xfO-{YCMFe(& z$7i@Hchz$mmzGJT1%87nPa_(CZH5e+tU-{|x%v)gbuT*2w`Ls$H{c|MqA=-e%G%>;7kEusG)}AKHe(jm6;<$s zyX8ccxZMw1Y@KI1D$%_?wr!I<@L^v=f->RvcJEe5j1U zaBviYX>z8(<;p&NukI@TlLpfG!yNv)_rz)0rEra#DX10L0Lni#8Rg#74GdORmE330 z<@O|0eO~30X;(ZKai$EABcf>)J5yNVPdf4E*7Cs4?|gKt2aLsR;>E4#^OT%V*pRr& z!6At)e$Qi48}lI^x|gODi+9DEV8<7cQ$=*|c1_;qN6(!ZY=86-UmdM=?{%TP&y~XR z1xAqhG{p0@lg!yYqfVNC6Fn02aQ)C~wlv+p5lve z_#jFA)Bo8m1^{gqgMc-9M1eNTAi>WDCczrKqCtYufu#E(_?4qUtkUFRAM|dn`4gMvLbz@ zJt3En)g#7BJ0hTHa-$M6e4=>7w4uoydZ6!$%5bdE#B#f<(+2jWpj*JZQy&SGa9TxSI=$6yKSRby;iN@ntlN%NOb_cbn-aDl|6fea+jy>(5OCwFj*aKa40XuzP zbcWs2vATVY2A*R&^QHq1X`(B&oPvwP4Z4#^=9079X1I@Bi<3zs zCAGdn|Eb>MN{R77w~y&#*k?3HJI3=EWb!UNr130)3ku2Iy^tsk%S;_RHTr+*^RO(5VHzzm$Mq=a;s`o z-?LI@1()JJikJM7PmjV0=f38S5`k98g^5OeXpuTg{Fx5$8>P0Uh^?+Qef4)gY}UP2 z`={N@+4}vpV#fpRM(!iawa;TF)3%?WupWmTl4Mu#1c#TZIR)qX_j(tH`}8M2!Y)oD z*ecJuwatHBw;_LwF3i8@SfzfJgQ>d#t_*4&}T!*JwYBp90+Z1`gbk@dRBX zs)^nt2|(T#Qcpg-CPzO_f5|=S>A0<_v3IP(g}<+J9`J5-J=kwY<~Hsu5I$`Elw#jp zg|S?@GAUnfS-o2HZ=hWQDKeO2p2?fHusiypgGI7{@TogYo|HA@L$y94!H+RIrK&dY z#+^J^5b&cv`2?}AtX5_+cR2R$ z_xxQ318aCR_;;x&-96YC^T^rQ^K8F}jVHm#fZzKAHWQD8g&Ac8_QI(L9M$3Z&986z zD^Dc`8I~vnb77!|!a6L4z)--Iw%%pQtyPO#X4jovRRlxz zTs2JjSBByflw5>Y`{ydbu|Ch8>e5kDAqWR>WJHJKySLR18Ggx7H%QoH>k8@{?IC z!C1$FDuR)^aWM}F-dd(St+5!4X47v_a{!?Y<{a|$FyGHp_pddALsNh9%!h^;H|=t5 zY0AaU@=-9mh9DgNI&f82gk8PhH|te+&VQ!99?DG>r(z(|lvB&uf3%hGO@w$D^)BUK z!svUqmYvIGrEVpT9>z$?&GV%q#}xbM@FEZZN{GEjcsda;<55S+ROc%rZi&NX{PC0@ zZZYeE0$(;!wFmCo6Qnl?wqTd1+lr2Jq|sJ>&%J{x9eg}6zw75?4o5%fX({eHSO5<@ zIciq#NI43kFP+!6_K;>P9QXC(-ACT!5}SQpRffDBj)EVwW#p=^s4xr$2di$w-*?57 zGu~~1`X1jV5%`Jhn@LF~L{DpcVrLvxI6C?OD%ubmMUdQZB$@xygXLuW(s404; zGLRkld8hcb{WiVyID_BIhRU&sVOAcW<;!T`4|FrOeh2sn_epl0!y5TLZT>H1S<SFxnGPsVX>-)4Eit2L?Ag9 z8Qmq_;H&+By=*p3)k=^Ms2Q>jxL=er#fTxEtxkKR@Y8Du31vN1RHBHO9KVQ6GS&fYGNrESLK}5A5*%BB4C#?E{5SZGtp$inJzcixo4GBeUh~ zJ{$tR%Q|F(HjUvfUdxvgL$=Gf8c_B5dxv-^cmD2WQY+?@$PI9=mD>3O?VKY%fPSCl zSwGWJNub&C*lZMVVoK3WLI&*Dd1V~g`H2+?ZT zybV5XoR-9!D&UvbO?k|~I3?+~o7{kbZvW~3b(DHMdP;pBa~^qOeIUZtfEU-p^+R#b`aKN2^QrOy0jaxsOg(-&`$Gg+iWmIk zf{c2}w-^9rLJi6so^fgT9O%u04?2b6O=N&t2HAoTtH zO;CWHS16DMo|XU6$6$zfYV`KR66$yAFZPMXl+esX=|oES;h&DxoGZw2r`3%s8bLpP zg&_x;ac~`|obU@Fshbnii#G#jKW7={Q5+2(r_C0wPtGE9cpf=|R%ZPW#BOf%g*H!| z?&QC_w&YT3-9ToJfC@5%=%@x}wOA>1SpOW9n;<&)@PH2NtFR{y#ZnjQka1;7|Ik$| zq9wUK$c9bWj-GF@;(1xIGUP zGXqP+?L#66Sfjfyisu^OnNW9BPm~@Kb$dWIDL5hesEB4Fyw3;b&LmR88(=j8tn`-R zf3Wb_#ayQP7U<75lBk2`MC{}uaR;{yCq&-Dj6e=Hp9g1hZs#;o*{4&IGUp#cqE~i= zS+^jn3-Cr}IB(^$r!RuGS{p@E41bbJk?>PnOv(i?1>P4Rt&=R z76oDyp@^`Q)=3N8V#vW%ZLvn|r%@>RYSTw(F393>!IDrbfw9F3ZZm?bCMYMmDe6!5 zrQ#{I6X%wv+Tq;PgpCu_Q_Ftm#m>&9MCgR(8f@8QoJ!LNLQh;3lSvjV z5x;O(cIE-TXNsmug3o?z>ZaXU^!q4w8kLDcdCkHWcB5e;5qTF60+QB0Dn-FK_ z4_=R2c=iprZX@S(+37=ZEj6g#WCAS%^Ug<%#TDYovf2p-NAruNQ6yq3h3v&H5i|Y3 zd-MywQc_wY`5=@jP`^bq-yJ}45PP@#rf8!S#%z9w5nM9V@PdUno_#<3ZRdl`W@4|Uif%jt@TzEj3~WM zud66^c;2JuOFx?3lw3?m(q>c%gDr!-Wrv?m$Mi^=ftynfZV^O!IeXZtd$A8)oeCEn z%)!9v3d)>2NMK8ju7uD`aF2$$mc?6ZhNyF2AFESB~W(i)_&6d}dcG@{}Tm^Gie=OsN6>g`ahc%KV05xz9?`0Xly35_h*E zv#NxcAc2W;4`lqvykShCZM1tEj>+@eHVi-k#W{9p#NP@fPn?k_u;%(w=6xD~)Hd{W zvkVoq{6_-7CC#oAr>2Q#!7<{~AG-yId5{?tI$I84?cjbuSXTllmw-C-5#;4(oi*W| zAR>vPJ7>#@kV=KHPN{hyPE-p!9DVi}NTr~F?w~vcj z0QxE&{Z&#@it&(Rr&ZuA(CcL*L|+?Xz2eqGmPV}{=@=6;0kvylW*ezZQ@zy^ED>G{ zIHn@(y9mhZ zK==#X3(6N5m2uZZZ~X>q23f|| zj5{8E^58xo!4i-6*vZdR;FsOc9B$aR)@;8ZL&EIX<}f%9y7=bP<~Oc(H{(SC@~ zdNqq{oZQSDvSvMt%JkoTMidsmGO!(GlavIG1tktt zsG;?Ai5PglAUNk)vWe=B2dQW}V+CR4!ajNvl%I3O;b^Xu3&E&LrsbujI8>&4fp9R; z`Oq~CNbpy}FGt<5>SCMT8-h_V4d8f|Ql zba<7>BlP$f_2KbkXwsy#`oG%P!#7~KKfS5v%+7N+@FjuzpFCS8{I)pm$uXk77LIRw z{n@@Zqv548Ot(I^Gjis&STB=Y^wLRK8-v@`Y(fLkgBTIw*CNOCdk5#*c*<4m3|${? zm$9ob?_LR1Q#H4ID}rr$#Zc@_jq7eOA&jU7aa$@a4)V<_W_b?>$~LJHqS*^^95ae{ zbo>~7*r(nlFh5M2AC+S3tDAdb11xiQ<3cXpPlt`;?}@0&N1i0R7cc>k*}_iUDa;E5 zQ5y$Ip;aPS?a+QT4PIo-Wl89vg$MO{a?S)O!ayP6y1!a^RI(8pEx8uK^<*3}Jc@=%BH0%jmPLR~apB7g>IVmlBmk}e(V(G>`Mut?fT@bN51=HgEAC0SS$!~|%e1wVYG zbt-bu)RE@YS4`J}=667z&)_)^3FFRU0a2G&i&gHb9xc zaC?8Na*WhLFUbQgtX?VRZRJaf=n`iF3AlQy3r|y^O|;WXPXiyZJCS1;I^amrc$q7` zxGe=VoB|kH8Fe*~+{#t@Tt0bNZAUO6hoPFWfBvAxmct*z>5EszvCxr2tyP;x1fq~{oun9)3x zII~#Qz~yDkV3U>FSgEtw_{Fu#irbsXDy4qj5|dBPvhnV~J(0@Wo%1Nir^O7w2d4ul()Xc z1_N?OCt96GnaT=(_J9hr*yT~vDKJuo`y zefb9Wht+(+#|W;#t3=|?>%n)&lfjUS6LU$ptD~W~D`|-Eqi`VfBjTC+y()f-J+P?G zyt6sdJOP}M(wPMHQX^e~ntbJ*8t63c@*uQ=a=LZ6PB`GW&Z1ezE^2{`F8}EJX5mna z=1ZyY2L0cQJtraK;^nL0;$QVHQk*XxQ+9|fahWG0@vHQ1MQsGgTE;W2gm1@2H+ub1~hFEMB1J**BZaC*UmC+EDam_`I+m$G zIzBeJ*)=<{-5nrtIR&RXIj!D@z9h0rz6{Ibd@pk^eFth5evAIL{zm>Zc)S0hb1Tl+ z^Dx>=@L=s&y8O7zxvY(~KK~<0c-~!IXSGXla1||wU?&}+XNP$cX&MFU-=0JG%RV9O$W1N4 z&Fw=r)7PO7)OQu8-1>Qm-C7ZI(PArA(!y0s$*@6T+7Kg~&L|bR&WLA6pL8zpi_}97 zhv=a{fap7HCUpilC^f_65lyd%8x3msA}_1FByVn3IVS=VJ7>o>9fR*;9m5ia61!%~ zH2bxtB#PzNB1%6qJF;wdIr5=>9TuS{9ad!PG%g6I5^l}I7kmtjK0L{807Rt?4g_EU zDBw_8CZLUx8`$2jBQUAotBd~)+wY~oJ<@cIT6z3sYHUIGEMLc!rydnz%(}5(L4$Li z+JF@AT(O^HW}mZaKOU50!Sl_Ot=m1gO}g;DAVc$?AP?H#TPI_Md2n>qbn8ih6@^}u zcR!%(RQBTmqJ{0FxVqVZnIXRO!3oZntvfup>EpUo8u4ySN|-P!aO7utlW`^~hFmny zAdNV_*rwu#d#5kH&TlYsd2n>qbQws2p_*b>1JM~b6Q;d`ohi@W%8qJ*s$lF1(67_h zFp_aa@CQd!$6BCpI(b-wnIQD|V3SUOu4>0k;{+8bH2?f{z)q0;?IW>2e+CXyeB6o*irlFYzJ%EyGMyv4D?i~>=idL=Z)RFn zS8{rs`IV{sp|I7^DcKtC5%*1I^xn=*$9*^jCX;?gcQm}Mw|0)>f$k3Jxi2>NF|LR-oZ*ywoy5wC==}&aub@TlvH!MqZ>^MM!*Qx zenH|K{)>Wm;HU+<2u(3OIQ+D#v<$D5Ek=CkZn$&{Y7gD;+VkwLed#1fDrWY=XMQXlB*u#K|;m<&`{8C>xh4F4>KQpI8BhIAKj1MfSu5|0CoK{kllJ zYTO;B3v+w_tc0wxw=`i&ee~NF%3u|GVwsT#y7w+8K~`pVS5iiz>D>@lFV%AQ;=Qrr znV9Y9Nha6B$qVtRR_!p75Q2sfPG3ede+{a2?aAJC$87{HW@wLEyYvWfMWa9+QgK)L z#U>s)BKCEt?nbY#h>OIBLDTN4=osjac|Ux<3qoJ_lq>$U%UotP(iojfkvG_=%RL|o zQ4xUxou!YOi>hxBSRDnBmq@N;<=w#g9lkT#$qU*e?fn4`WJiUBNEFYj`r+>(h$&5v z3(Qi*5*_CLx!Nc|k|3nDG-hW%_b$GJT7owT?kgcvuL7V_weVIb9NJ1oH~Ss=s%bS_ z;F)JFA+Y?K#$B0vD^z*vY-zkCFyku2X@)I;+kjJh!#i9p%F>6>#??%Upf@RJkzl92 zMuvP$lnmG3&f|e}+S9{!I#yKuvA?aRsq8_Uf)Ox=wU6q+h|L|uqCgnET(|U@gC@IR z-)PxTS1jT9dl?1vL^>Hw&taR`Ar;aO4LJoKS!?g8Pw6Xry=|QMu;WO%PE^Mk`a@RW zK9ACGe1hpsQSv0rq>fA-FV%Yw*o<%H-%I`J~bJ!AqOLOtbxmq-_yPJIr8(RDA5W> z>D+O!e{-i~C7)F@%koHdhx9T`^_=$sF8l^Fwz<$J7aeB3RN-D^uPOu-0qcRq<95yF z{A>PBY@tX9Vg6PF@y^I0H`q3e?Tzz6woQcoa->AmzNPE`0Zj zK{#Pp6(L-U?^ncm!t3xFfqJ;&_M*$hPA^eskq={l9|j@liF`mXp`Ejt0#(m1pB0y7 zToBl8e}*kS(;CV8?bL05YQLBC;suherarmHS7&m==gap2(1fUn0O8JRP1abJ84HMt zH=PX)R|J;fqSw{qZ@i&5TDXpI0!e*2ARTsfupN$Hm{S{z%=&F{qL!-`zH-n-?NN?_ zpg*N2kErca3F%HQuyK?PPkAb7WM_AdP+lpe_Bd~)G!i2fMd#zVT ztsL;}G2G*|QGg^tNa|{=xE7|ifZ6?;Tb>-;=!IJD4Y%quz9TV?bcwW#3XdT=q@*!p z8qSLkX3-o}ee=}(W%;qKiO^8>pzd%VzI=%z)?xK#_GUlB2Qh9Wrt~Z|z3w^T z0587s@#=fLj$$vy074sA69ww`YB_vPD5G!ZQ;OyZHk!NSg|IX6b7(V3skf9|oK{9Z zo~vUxLkT4HzF>~5f2A{M$0-TeC@`Pu4D-?^c>=koI7JB(3f>ZXY|QLJYn!F*|s4L{ie2Q{a)cF7<+vjl)b_RsKUg%`ia0l)wCT2WIQh==0~M6|`3lL!x$x zyb&=cGc7{cf&Aun+K>fN5nrHtrUw}ex^50U10Kf8CS!jYbDr{xEhw*CngpE^g@yh} z=97VUrgfj+Y{mw7DNru?6iF&23Y%V^>GVaQk_Mltkz;=K?%(4-?9H5Zg8Qj5)_#6F z$=yOZI;=#5AODDQJl!ZpS2^f^q zaeW%m%&1Y*Z+Z$743@k($^un8EjCA_Jcp%(uL)~TSlsw-`9_=E^)PYnIe4|y(n!rU z8{3XbX7rzlo8_RRL9_wkP`>wYFo~Klkigm)h}ZtoJcY z9cmN;(LXY{cHne-u|jXC+U1Y0p4g5_W(i!0AEnnFFL~u1p5vycL9hem*qZ*b3xGVg zQhfHdH;S6l`wm%6`}jc0B965=#_x+aE^-Ewv;g*$eL%!e4K`e#fB9qgCaFvP;iWGg zg^0}%;+|1JyiP7cyIJYPB%=P(uC0KB3u6qNq_$pSr$&%_t$;s0ko((GG)Q=H$H{YI zJ*1oSk%zy>PdrNy;3;SU4CIW(@460U(j4EbyX>wI{aI_gclT4Cmx#JyK$UR@Dd?p) zHAal7yuyQb^^i)e_=B7nxczp5Q4&oB*4R{fPIFS?gNta?x_9n5DsvW?;}<|ro?t51 zhlkP9kva(XIL3}8WGU1ktZe9watS~|~NSDj!N%C0&r z2BabVfTSbyYYzl@b*&UqP?Uiic?AWknArTu4u;?(WY$Av}d+%$^e)}E;< zKzs-mOS7Gby%R$mytsE$K1IRl5zdBpHlhnv9>H>yjLe~ugj0VmcbVdvL->@<`F&qr z=2kR}$oi}9*Nxvta)=o@T5;;-q2YElt$GGN3!n7j5DfP+1Xvn+00SfWswR|;r4boR zd2iRDd^+{8`vF~c`}9Me^74fJTimlkP=q=J($JOQgY9JiCFg!4DYMsGpS7?DCR7J%0sGL+efJ|SYSOsb#4Pzbgw@v^aEMDJ zxex&@$07slmlrJDn{Bfry!9m_tmiRBskvF53VnepVuNr4ZAnR@Y-DZXf#&J0M;=s+ z7Cd}D>q4KmG=NO8Q217n!z!d%p0DeGpJf!*l_lbC=($WCqQFA2Pl-Z>)&I%?RID2^s3H{hiMy<(I%bI>L^) z{KAufl{TlpUMxCtej)b3QL<4S1B4rGCgD`k5$GahMTredH0?f z^Lu{wS94#A@6AV1qIQzMl^+HYrm1;Uw!E;PUJMU#*@B44&l*NJ4Is?>EHPtDNym3V zG_N$2&ceJo+vKSRhun0Ksvp^)I~|$WCAnfyETVR-*_{ zZ&Ts0@{OH8_m0l0sCC2c5ZGFI6-tzonSP{eXC@jF(8%@oba^N z#-6}ckgsI{GB;4r&i6HoLx=>GYJiI-%cy%6722L}I?$-vjo3fYBfyWl@MLPb)p#6w zH4{=0{xQw@l%5E?TtQ;p^2SAcuFNmc3H8g@hqfHG3NtfftTf>y|3qp;bKA2EoY3_v z2A9VVYOb^p$7pd8cW_y>;_`|Tfe8$YBNfa$7d!}i8;Q(5;Za#k+H#gO_$O(>>)!op z7|O$^SsHE>-PZVMmzGu?F%4!W9Z|y}3!j-!T3I+I=S&+B)V!XITNNS<13ieovrfN! zf$9aTfoxqf%I5NzZLi*GNHJg5xQq6jqKSLnP-s+CAAa2ZkE9QCm*h&wZDU&2!*jtu zuSER|lhzjTl6%m6DI1GK$ph#qc>`u2NIs_Z2fB7mD#I`%rmKPBOp?4#z^nkqql(Qw&VScYL#9;<=85t<_> zrKlpqF3u8A>U?w0%Auo11Bf1_7l36~o7}DLfj;LpGmSsC^1lk}t$L6Cn1l=TyOCs; zMWM~@=OWkG(Va^Alp>R*th6W<@{=NI+l#F7+WN?V<}It^L5sW2aFXZ*y4mvNUEvzx z;HpEc&EA*>HwCN35qzE(t+E`BhQM5R-?CWn{OCO$LIZF6)vCMyCRGonVdnkW;kRiu zMwImsOjAvURhBEDc-$u)x$h%s-QjY}!K0%}V~?Fy?%Jh;41g8;Jpjw5X43WN%-EZ8 zd`iETH~OmkoK6+vxelkpl@xcs3#Hxog`Yy@v0?nc!qzdWa#zE4B3gv+@T1aFm1(3I zGw{O^V$~5)fdtA0-Hm(~Vha0>Ef>$S-{$hGe2R3IqUw@ts1D)dAP$R28$hbK-5|Qg z%j7H3UihQpNXHv1x|h7Zr+v!z5Vm>?VH$!x*3$$R&|{g%qC!V+uKms@uNvnld&=eP zi^HT)StmVW-EXa#@V&4Sv-YZS3^OpgoI%%x(V+S)WiyCn4eBcq*oaI`cZnUl5n4Zb zr}!o-)aU1*vF}Uz#xofKNXij>JcN;Oj19a|&fxCQHIco5aog)z@sMTn(nhPC|$XAl2K}D4iu-?VFptnAkb%k%*cv)_#1n|-yq)%F?FaT*R5vN z6kfMu#Fl5btAOHDGZ|d}7?S%WfaMdlc8%NOmcFM3KU(KzcSJUc5_Ff7lvss6`oUZy z;1b-eu6G`-!!A3=bW>ub3c)u|3a&I^+u1Js~7Dvj01SAU^6r*5Y+yp+@2{{K<1p3V`&+z3k)Vi494O_&r zx#0^ItJ3DRNiDIPCSNU4VNb&KFgEYjfn%(7*lCcHbrXd-H_3Ck49onsPBCoNo<;%C;Ad@eL^o3intml13xvw>LgVKUMn~mJSQ;`G4Xe zj~AQaP&p~z4rE~B@&x27-;giZsUe>=zhcCWoaV8l9BBww1~U4%UYMM$k00DSY19+9 z7CQ7KE5`T$;`Zye$j&xfxyny>QZxX8c*K(QwwcsnSzGzCd9>occsY@-4$ zSir6<*=2!{Et7??4ipj;lqoXynTN7LfSSLbV?=}>y21~=90ZgWJ;Wu)_!X1qo=g%Nz4laz3g?|{U}9eD2P zQNl*s9rgptv%YT?yVIs0Z9^g9wN4=`&v;*EtqMVH8r~6{qm=%wOC&$~8}c*5JUzqc zI>xBAX?!5Y3rI)_)Ekl_27LPp^!Z_F4>t&oNr>~sclK`ra~vZ~Ueq2D-HK{%*#sh4 zv<1^JiUx971a>MK z6AOngXqvyhIF!8#=zN_z+T+khFeJNi#-Ssvgiuc&H9{-loC#=FDFRqo|5B~exM!X( z3FYQNM&-DCV+@FyVk4<#&_2NrS)q?xK{V_nEmEw&@q(nX712l*m}pI}GZ9&gDBXg1 z4V686E1CF&C-hcjn9Q>k>2oo+_Qu=HIIy57`MpKn9FRUbls<2+Cg4(EKa4UQ!tVB0 zR>!aI*};JxwG}^_V4`t@oe}O`D_KQJM&-sI zI5#t(bmBGxb$&rBMN;dio)?#*mlg9=WLokMjN#Lk7i?Tco@OJ;S?sh4F*6URYMNre zL-e1^Q0Fgo*f9I4{r-uB3Kyq;UJL#gHuGtSbR#Zt+k`ZPyHK{i8SOip?B_6(*@ZTQ zxlwkwR*~gYkQFLhj18Sl4e^*tqZp4~X0(PY?7|r%-Y7a^Vz$cUCN z2Aw0gB2S5p$Azz?hkMSXNmIOauG|m=Q%uBcvDzXR-dh%YS^oU!5dj{G9*1I(PA@pA zP4(MW_~6eTcgDMLCETk&qfP?0U=4BsttXE7c1o&AepPNn_Sf(apkM-QsMOt#TMV0@ z#i1@-=w21wW3o`ugDd;I8YG>b)_=A5x<29>ycB_q!f*e%2uaPyhWCarZapq3|87it zRc~hEP;fPU8vz!EortQJrdnFWIh`95%p@}ZogT2e@bd7(+dfjM=hdGp@r--@ii`lQ zzPW|vR&c;@MU4V{F~?Bu0kYt9+ydeP%0LXowWYkDf_wVaVnM1&c3Wv&8tzw`mERh< z!e7HbzzCgVp70?*Zow4TNQsBzHy>-N!{_U4vRP2+6is~jMdTvACXnQwaaU2)g(K+b ztIA`}>o$MG+undrJR-JVg@(in++JNEJ>dPNnmI)5X&ZWxZhd8I!Sv9SzgOFke7mav zEq)lCAp2|h2ar0|-jn!&j{7|-6aI%$j&vYxD{b_pox<_#fRwGBkn1;_OLNB8YKwSe zyfoM#i~^YkrVb^z$6iW#vCaCp;q-?a%g-w;>Y%-(Dg@{1f+ZeSKPGB&=`oF!2j%g0 z-^*Z^HJ4Q8_&a-C&+zwUE1BvpwaNnR0QqrUqG|qtdKc6$xGOyI@0NfWM#ffm7K?54Qb(xyz|HN5DSVtX-p}2&oe`L=98M(7k3RG~*cvz~tt#u?r zz#c0~HOuZQO-OfR6Ykxo^$NmSWLyJilq=|S#(mS}%jh!m)CN51O(e5aZNQ1r zIpPl=^XHO(pDGrGEa!DQ=H6<`7 z-i>RtsUyD+JB7SZb#{~}xERp)>ENdqycCXQ0txg{+ki|fGX!ND6OH_jd2cz*Dts4s zI|XYHvKz}c?7IZpL6{}-j-5J2iTyDl^@`;mEAyARFCq8QI(&DLSprz-zgh~^c&s@j z^wfKqcQAA-KP}U*d|135oPvXN(G=m-GR0j2T776B5lbwORG=l#Vv}XK?#a!XK|ST^ z;&(&n8*Tw_8K#QtIdE`N7TO0AOX#^I9g}ybY5K`~Fxc^bKZ{E@XvgMx7Fq}b)3VXR z+S)5ve-(5WR)g=I$qi23-VM1#;w^9XvoO1J+1&hLaIdvg;eCC>?bAF~%E^?=P+4AJ*4qWs#)hF&YPh8LP<9Eh)LoE48AeKa6h_7nr?c`oURc9fy4%Z2>rZYQP zljS4hU-~&p4vmD7cFX8MHAt}KblNZY6W4CDQv(y6XbQ>~3F0Iqw0s>wg$?1dH#sRK z9~`Di$zBJ2_$A8D5?izT0yG_FI&Baz8=1_U{+J|m!H8QVKi?F@O=B;CI5oX3e(#2j zKh3z4thoD;j~I8?3S)uXoW0*RUS(HG{pNHu)#Q^7)*N zkGs?7}5q{}1{ zXjAsVnNY#TED3LxAvUH6igw28c?~1nc63)Q-6e%@IZf((=N>>SUB4FQZ}4^t)*+<# zR|W)Po>fO+CLAeGBJL^sIcmd($|?%!NhdApXT*7MfYB$j&(T_M@qlYIfuaCB<#ym* z2o@re6+170MHx^^oJ^(Zjcjtn%@fI^GeJF@SL8zS+qG`ACa8@TciL^u&Yy;#KaPKf z+#KZbA$u#r=kWm|GZL@vb!#1%sP&63WQGb#I_FMthjh^t;nc9jpX)`3@m_cN-hkMC zs3Q?cudL3@dq|fROiWdxB`xDqXCgpxwS*-Phd7^(bZZm!!+tmV z3G5emK@WHdjd!S@CUIcL!NJkjWZC_?OiEMi7)&nn-RTNfSkA( z*un4*E5#Rjy?9gZ{5;Ya=|;{Lxo!a~&ZP|sugvUe)TiKrgplyE1x$QY>=hNr&u;>` z4-<@MkvfHdBj*>ArM@4L6gQZJpnfSfOLD`0lm%ml-xTu=w1=oXAe_7h?T(zTkIcz}H2}j357@x0Y2&5QM+n9Xv)j+U^)(l7G@oh>sB+#Q z-e?pB@Fgti;#8(pfUg2-1tRqXGm;E?!>Bmv^f-LhZ~K*kZDu;%WcK%)XC8)#^<0f) z_rp)+!;sk0oYGbVIZ1Ao*J-bZy|^eU@TOUhFqVyx1J{lEYV_Vg?~aJYmo6z7PJo$G zQlbPywUToXV$;1_)5svhawsV~LK$~LS-8-R5BLYuI3(ns^cF~&V3pZLN(~e$SdC(y zB+Qe5r7s7w!rj~DSsm(wSWb#5&m; z7Q3OijRipfjYhqG^~9Z7$rn8pzVzI>*^ihWL0SaYn07kc*>H0`$QAo4!YM?Vfo4{& z1>$2)?`r+qR{{XP-k-aq-_8>V|8=+Y+uy`rage{_f5JayLH{ET_8;-zyXgK4f0u{& zk2vIi#DBYc_!kI%AOF<<^%wq?_*dHRfd9H$0Kl$B0HE%-{lVYuWcV%sAphI!e%l}X z-QGB8!GFc=!2cco-EKXg|C#=G`}qO?XZqhf7(V`8@89+O%}4(8f2RM<%MS8?*7G;N zI&}enIkn&RJNyH{e;on%^ZEn;`hMHr_|s0ieu4j=-?fnd0D`dq!0vDRgFn~t|33el zr~F?$|CI^x@6TrV9sbRi;V-`bng2I$gui(IXa3*(0si9upZS05K=79i|C#@{9{hjl z@t^sB>$0o)Z(aVC|NHQVAA;8Z;`*oD-v+?{+rNnBZ(o7z9_qh?{|$ex1^R7&%Ky>l zj|P8u{(X*wf{KQQj*fwe^*a#|2p9we6cp??z<=Yn50QTX@-IOB2cZ80F#iX@{vQDM ze+l^iOZ;}2^8XZw|Br$6Uk>E|a-jT!|7rzL|G|H?0%-r>9|itV;J;P@^ndV=0{3jEh800M!*V8$yB z;Ag6(EGr=*$j8IQ!N$VO$UsL+Lrq0VK~6?W^8c~-9q?5D-~V@**+hy;k%|-zX`+Fq zq^X5Mp=e4&cW7y9NRxIN3MoaBb}E|EFdEWS(H{QidGq@GeEf6!)aUd0e%5{Wc=o#I zzTf9{&hwn}8t#4HdyVVYuV+-ZZk^h-4Gj%y)v8%jU%y5Tdc{;%w|aGY`&3(--ovIh z(dnIddNZHi@26V=aF+n?9Kc-!xSs&G7T^{Gc^vdpC31WmJjubuL3bkjt^@Zr0JzVA z-P3^%asLLu&f_^8m1R7~?weruPO$qe(85KDlU#WPbqxbUo}8kZX06(0d?i(_nspkR zE30Vh*KO3KRW+R&Mhz`mT36SrXWFzyYx+vh2F;q=wCiAOVrkW;ZAV*<+-Ck3eh%M_ zaE3pL{+;H3;&Kd#)cYuNLso0SoP8`tBp z4jz2tVEwaGxEA#Q;DD?ydG!DPSJ^IP)B?*3>+Ap5{J;L$IhJ4M4>+)xvujw(d}H#D z=%U|>$B+2Td}I3HhnzBhn9R;sY%9kK*CI}gBV^R*w~lZ5jOzg$=%=duRNKUda;uNCJy^u_w2 zhrc=)FZLw*LOxlJr0G`f6ZKq!z~Ya-S)I_sUmd?im&NT@iX{9NpR2N4Sr;;5#cWCA zTRG0`T4oFKkIc`oSy8vD`RZFf!xn%8{Zv&~m36@Z&#~uW|3}sZ=(GGHZdHw=%CUkD zY_jL2*=4@b<&pz(WxiF-IjsM3Rf!(rQ!&3)#ra#h@Uvo$ertZ=Gitn|ZsnS%(~{#` zd=XogU$j-}vTMHf^ffn?$1n4NUBlYScEP{0-Kume$BOZ-80X)r3l6xJT`!GqWxKex za(;hnj-bmx4<(Pm|6508yO6<|#SlJJH3lo|GCigXAAY1JEAmAjKf)KfKNDxzfgbd6 zF!`(W>;J#S7e0a~4z$b%$rBa+`<5b$AZ`p;P z6@C7Z96_(5ZdG>KH4^glAN;6j7w3PgU6xN4+n-{YiMd|>(Iv}@F58U!`gM~8r7?BY|_BAVWY-o=1nY`HnX&9-lAnI z>((}H+O})op`+~#`Ww2^MiSpUF`mOY=t2kALJ$3*PxOU8B=+;E1(+`tWLytjT#vq> zgZ|J5`hy+Vg)P_x@EFhG9Q1GKp*;PDF=2oCAN39B4@WcFY#U%B zNYCMU$Pd2I^`FYhCVeO?J4Lufk8vK?U;q5|d7Ot{#r_~yydM4iay>mpzc`P6&|lAw zWo0-IzaYcTFETyG_2?hhvFm^Fm(D}4Vt??r;`Qi{@fk{W;f~i=nvjz{$X+?pXfp*^ zno)eHP5{XJ$R7r%0KYo8N}9?%el;z9qng?(a`LJ=wdyspY+T=t?O-`jhm0fLlBbOgq9H8c2|bk`9+*hu_@> zPn^3-=Nb?o8_;?DhBkgf8nK5S&dsB9kntPd_&xWY;6gI`gdWa8u2>Iv414GkdXT4* zZUX7zM~o0x_yT+A6Ee;rPOIrWY5{)27ubUgJ)G-JfIZk{`KerQ@D2XM##E{U{%up*PjV_w0i&c!N`Y`V1gy z33k!01N_04<(t(5iwC%YFUvP%_`~7>`_kq^@I~CfAL9@*@(BKz7r+;NgFkWt8C>BH zY6N^y_jnF<40$Tm2>4@Mea}AlqE5jd;~p}`4fw+!@C6sx!x({#zQG@37JO0n@KI7X zB*P!*Ag{15ZN3Lz)E(oC`bRv#4RHWp_{R96j$jM*56<8Ve;HrYKkTFa5r^;D2VabH z#uvUK9*8yi1z((Fd{O`4hWdw1@W=IxFLI4|pl0C*?87JYgKIJWfiqjrSiaeO5B|tI zs|S{E*h8PtLu^<*uza)m9=4EoRuA8^&+^UYd+(G>9)LgUgyoyn16vQiXCM4g ze=Ogu9@u&SKT(@3-;hxchzD{G{-{@$Z&nY82kHR!!3loDH^{Joek8FYS=#!I>ktdr z2PeqzjpYL|gnh&td4SC7QDUEbNBmJYlK7L%#v`u9Ikw&+j*!`SM8D8O{84YHDadR* z!Y2B{^>_~B1u`2?@B@6o8-BxH<@F!uq^;l3leYe%Pw+-AP=AOi>JRzAd<1*ojk?9T ziuphuz?aRp&_k}+ehlLPe8C&_jy{n`)GF!`H3PnEzJxvW2|b*{e9H0-`>+Ln;0LP* z@W;H3xdeW|SF9gw{bu>TN*qy#=m)jM>Vf4O&%uB6&E{jo1@_>hB#z`e{DBUu2bOQt z7`9@8GH~1s(tR7$wK1t$8en19i77siIU&I)3Wc9$} z0l&cw@yEDh^}yl*E^NM)tm7nuH;V`O;~Mx4-&j4ccz{3nf*bs2^}yl*zrmN~Tf&2U zW$^%i@MZaC^}ym$G2RmU;9Fjgh&A}aUp8MuuDE`~Pt-P>Zy_T#;13_cjqSH2aVHt^ z1b^_VSa0wRGHgitA#UJ{x&eQTW5{ejj(GumQTO1FoI*xzfJ#H0GTTq1 zKk&zM$T#>_%m?BCUyyfjf?dgT z#1eerBjN#W@CSU6TgDf4gm|F-;Ul=Qzn8!lwj^~(j}Zsh11H#rZ}0~;ByptkEZ*Gdd}sN_+yXuL#@1u- zVfltVj05N)Hmn|4zL6u?1ApitW~hgX_7Dfi&;c*_1K%*uuzW*CJ+So~*GXG{(FgJc z-w+4Lh(B8oD#jaqvwA>05G(L!`z_>~)dOszU+~A+VEJbCfOsIr;DY+W*g(D^qaF|s z_yN9%DdHxvPco}V*vDh&BVN#l%<2jH@Dskk9>xe{HXgtc{z_ZF!57!SZ%O<~hL5Zs z-~)Jq3*rYEc2R2>NAMf`k#FP(G8+%j0Vl)_=c;=B0oSm6SM&#dfG?XbP(OGM^@Dh# ze&8pY@8A>qLH%PqVvYqjY3n!afj9aAw~G0IZ9E6w=o{k)^@DMMdV)XT3vRH7=MYEK zKk5NKf}6Dc3+%y;ga_%uAJ}B|!19fpf;adh{;VFLhjUFx2fV?btp|t;_(KopzO{bC z9{PkH>Ja{bBdZ6NZ}bV?ILFo##D(P>^#|V2L*7|EfIspFU%s_}fj!uO9{hj|9TpGp z2Va(N$moy71J}VfmT!q3J;&k!{_wl1^&9-bNs>qEm(>G{2Yh4e1@a9UyjeV;2fi%d zl76TjSUkW5*H^WFsTgl?gUsp?`M`6q3;r1QklB6`^8)yyHo+e;fz0;9m>0kw#3%;m(@JCHTX8U2-L|@YOFW?Ki62D2eVm=TD z@MV85fG@6<5|OTEAfrKB6CRgFn!bMfat0po75p)OvUsB=kPmQ!|B~y7H|!%v zh(GEN;}7!@`T%dtji^`D55^D9VLk;`+<-jd}xb=pi;3f2aqRZ;Ti4hAqSmHG;T+zcl;sLE8Eazkk>MqnsnlH_Hc$ z2lz`{f1wAyEZ?jiSUkWVd|AF(J+OGd9&A))AN-}Q-|!Q;fj#so@tdA&LXR;op_ZlY zKd67?6!wt^_)~HHhi}r>U+AIk!5=x5^h1x~59S5%Mg4$3#yw=VpT@iZd(!NKKjweb z67(QfeEk7@F*afEr}iJzAACYTlKm$=hCird!~y(~zpB<>@C7%<7kY>X>L2@Z^v(WW z0$;=!@j$G=2mGbk2Vaa6jB(6^@Cori--rYJM&6O{pW1&=|LC)-^&kADt-mbanEx;i zz@M#0;K=fg+#rtN&(>4a1FN^H?6Z7VwSG(TM!Cm&`&0W5;?MRQhy%+9TMxir+WHIr zY`=k=uzFzY0r<2167tRJfvpFyC(SI3%IiPNH|ALI27k65ATHpKagO=#TkAi|H|ibs zz@M!L@E`G)W}oF7;~zZ0A9h(iz;E=;);r`8xk5e=7nX0-2zY}(c(8haeQ=WGk*;C& zz~TY^;EOq3GH;U%`z#*NleYeYn?#SeBj1q0o5kaM_Q4`Nf_@e&7k*)uDjQlaas1>#!gkRt< zZT$y--3v!T$aM$ExhJd}AzQ9DqOkX7wP+ z8^z`-or90)2VB{HkmZ}r_u$X|9)};`kLOsvSv{a1a0f7cFvbygRu8a+IskvflI{0c zJ+Sov{1JbaZ&nX%J@}q|@W;Hz^3Cc2@qje?kdI0-)4*U^Y$ncTn z1Nnmg$QSYmnbkA$5BrEWn{Oeb)>%H#x778QbP<2V4csvP*mz*^N4+8b$UmNgT~?13 z*IU#CWHugAqv#X$!qyAO;KAw%e8HRLyYl)EUvND*p?(n?)D3K)e!&-gfiLC=^n=*4 z`564AuD{ebd_q4MTNU#GTi^@ctln@9>XEHS;0xZchZrG_Y(Ivap>JvX2bOOM57Mo? z{$`R4jd&%*}va4q}+XI2j^--s=EgMY>S z2g^6?fj9KndW5*Je6#fuxkfx$J-{CNgdY5WjB8jt@ErKEd_!jQ8F=A3@MZay=+Sd5 z9^fQ({iXiEQIbcBAL0+6Sv+t~+WrH2;EVYOIbrp{;(@-v7qR%({-I*Lkz2^n0T1{N zzNmZf$GC@#eozmX7jWJ0T7RiO#2owtoO$*oU6PKFO>eVITU^)=$KVt#_z*$ZR~IX3+;*uaHN` zte#QF;EQ}CZ<6?vj2MGIxWhMT`v>T;^$v47WHuf!4!{NZLoHw&KxX3^eteVDSKdY3nEa249wMRu3#5=$p;gl6?fpY(7Igz#n|!H+*IFz~TY^()JJV zo6Yy&B;i54Sv=4u__BOMMm?~2RE)R8KJ~%s5w`Id{#Lbq!cXKD{4wq!v;8pU1@LG4 zHA&n_Mm(VdUf_#sz#qAR%*G??5k4SJ7~`k|$e54VdJ4X5zXy(x;Vbw<2b>UhoWr<> z%=Yu>5By;l`9|Lr^C96*deYWU@I@?jXt4=a~1!7XZc3`VH|)z zTMvgr~~kY4a7}ipJZGE9R{=pG(ge^Q~^9||`v10oX)Dify`35$ihgh+{$G~6O{sH`@ z*@q8ozC!&XH?WHsV?Kl5()J(V1m37cj6dWQJdhj7_@jQ%C+ZDcQGd9G)dR~nVhrBk z&*o#qh2jcbuVRuABhb61JuxAq?_-xzP; z4Q^~bLR?@U&#`>7e6VjKo z`DXRN;sO5P278!ySUs?KfInMrkZ)EGEFQ3r=fEGag$y6TAGro!#0~s04k5GsDCPz5 zMcx0NzrUr~2VeLN{@;520en&0;E$Lk(|Rd}C}OUf|ExBlrXU*k@z@#W(K7rHpd_8Z7Is|UmbbpSoo z0?Rk62gCz)0RGbU58ty7{-{6H7~;U{0Xaur;it6y2ROh_i7(W$dSL5;p<#S{cUS6& zD=+!pO}gakQQ`Y9*i-+hmj5*zzkC(xe?1;NE`2|%93S7-O2smh!oiW#lGm&dq|m_wGL^d|348@yk~wrLW(-efR#upIogx zE|0#oR!$M|;PQe9d@VWodR7YB_AZJZ<8|sc7b;cn6uvR;n6hz;zAtn=CtRwgXVS8u z!ApFHjO2@BzJ6WI_W~mNsfhd%kpERYDBPGkXgZRBrmA0lpBRs+XrzLsQO@rHP0gIY z613!T{>z}R{gHg9lC1r2#zC3#FM})wvKshr)&RcRP6k;FWHlhG0a*>mYCu*4|E(Ip zckll4+M(njr1Brh!B6GjCw=ge+SltOC-CIgr@uacgume{z79a*PapL1ZW)yEHz~ej z8{au^L})~?B-jw_2z?0dgg}CTu#^x@_@nfVsIT8*Zy#NkM#v{1n9M%JpE+duvizfN zj0oSW`DnT(jgU`3?b%hRKO=fdTKz`T`7}a4f$0h=>D$pMcY=TrO-Li;6L7szxjlDk z1%zlq8UgjI>FC7ih4&{o@&XM(HI9Lx4yQUtOVC1K&1uhRBWT325Hu9j=ZqA1bNo4D z1XDRP1wn!dG^YCtMhM(EJp{cuT{!lF#M zbB73rbNg{!gcF5RxHGuH!qMEZLLZ?g*H~!EZNhCVwBdFTwiY($YI1djb%nLKDnfOx z9G5HPixv2)d}XmdzqYuBSetLjZzZ-Bx8<9QoAOQg^~COcFL8j_mp@$`Lcbw4UhFC! zz#qyVEOz4e5<7}J@zeMx#hK!B{9EE&{#E`Zaf$d1{R-H7aS{KS_@VeNf3tWSe>Xoy zoWwsOJ}8doFXgWkM~T<)7l;@0L-|6nfHzyTL=?tbE84(Y!3!59hz{^lc!xwgczZn0k+8zvek>dOn{ zO%}}(P2>5A#_>k+JVZvk2BKynGhRDUM_x;wl}JaV$1~*B6e;o4M2aFFURIX8evG+X zm4M$K!EZ~M5Kx;P34I8o33CXsgfs#Uy!QMvdeG4%VBLV7mINn)J7ESPny`tmg|Ll~ zMvxsZ*m`V6Dp-rV6Gjn22|ts+d8D_WkVe2!+1_uhm#^AC{(nV#s2e>(9YP}l zYNr#SAHkOZU(*OUzNLrX$ulK1C)g2C+oK2}gfs$rW)l(hQD_V@Vbx;f8QA3Zz&o6-Z8*$3(D~Kje$DlM+R98WHs>fHGtoql|dE* zSq;c)Kvn~?8j#h1tOjH?Agcjc4ajOhRs*sckk!E7uLkH(cG>&?e_;&%?DzNo?DzHm z?DzBk?Dz5i>F?kF)8DKAr@uGmYCu*4vKo-p zfUE}o_!^Mi10cHx;`e+H#Gic+!;kj=XW#Siqy7Kc_elI`|9|#96+hblKm8tzKimI* z`aK?hw*UY1dr1Cl|NrUtsQlUf%kF{sYwv;ir^jD*56@qF56?e6{<3?J{@Qzx{^{|T z-9z=)-b3|IkH73brhoo@OtKuxa`;cJ0oiN%fBb9uvY5(ZDysom4ajOhRs*sckk!EV zY9O$q6K(_e)lvC9;mYsBR(>C}^81jL-v_MfeX^?FANt<=BHw#o;J3c6{G+cQ{@&M% z{^-{W{_K7K_iE>lK9Aqs_&Y$0{P-sTzoYYSfDZBaH=;W6lHs?5wV{?mE=FZW3Lj!qmca}FoJDgAbL zT@I&=j*9yt$n^)%?|2X6a0K+j^^m*lrpL*2)y%Il-tWSm0P{C|@8jUa8BLf$SW19g z8C&SNB*K~Ub2q4cO87)Tf7lan3LH6h1OXw9;GW>fQ6+ylTpo{4hg|s~U+GZz&Y}1_ z52e5OQ2vh})nvziIsz)PLlyy91pc!TP?a6B2*@HJi-0TwvIxi`@Slr-n(UB8Ko$X6 z1Y{AAML-q-Sp;MekVQZi0a*lO5s*bd7J+|#1k}HC;MRekJ#c@+&+0<&@1j4Ne90oT zp_^Ja5~|UMnkNu$5jxWcnyb@?m>&=h(1(}j(hV1b=)=j4=|)rLzdPxs5sXMzK*%T9 zk#01BL;7h10qNV}!_TCjMi5XROn+&)?!I!pEYfo)ofqYL(WD2Re0(UHZd^5@n^EoP zCK9Gk&;HcG^#AMp7f|$&{}O^8ApK z>DUnjgfs$&bnFNMLK*?}ARurm=%Zc`f!5X-ZfOSBg=3ndu#uC1@AJ|QEG4=$Eza{Co z6R?h_5nd2}%Y4rCo#=Y#-YC}_O?I&tct^lGPUZ$AO!{}TbZ|K1$%M~;8+|55Jvdx+JKJL&%@ckE-CK6HPS zdz!-k>67|T9n5}x(q?nOZyEn5C_nhyfax2Nz8%4xARt5&(g^tk4qbKde$!8ky*(iNN9fAp=3Bj7siO`4OPMAbk zNWk2AhVYzVNQMx*g@h~u{+_pkGj#l!edBW&@E5)!r|k(&gh2#C(3a4i(2>CWrpsl=za#>GW)1#G-xDaF^9Y*==>*gyUjOJx2qR$Z7*?pk zAL;u?$0eEm(+qdY6Q@v&z>b&IdaG>M^j6iqok;;P)%M%PL;35Q|HpBx4AsNoV{V>Fe z$)godj-sVRm8nS;X+*1r9j$5tP8yx2N~r1riYX2*9XvYN=lk%{zOQF+4$sTU$;&G! zC{~EF8b099VqZ;FU9-Brp;04C8@oR4fr99?e7vA9NB=bGpAx}{{-G7nKP7rBAZ`55 z<8tJT=znT8r`B=eOf_^Oo3vIF@Y#Hc4T*KwhX-E|_Hn$*AIhry0gdn7sQJA&Zoc!j z$9GSo27k{Xsd{Z49h50bla(VY!^-7Xx!k@}UbUo`mw|!d?>uV%&I2{1M3CdiODYL< zj#}a<$*JC4 zmim^Y+rf1nUCW=Bb9t3{&jZRwX2gXkS|mLTuYGjsD9wYlUm5N5bsB%DB-cJQbmrBY zwVvF+Gu9>XYU%0OSHuG%{dLlI_>G$O-t+U*vtD7&L%G#+{1rxy?4a@CwVKkRGe+au z4c8pg^S-_NwF%>WHeI^UZ|`_juE*!uYM1>It8M+TBe9i#WPGRVXOnN)y-(SF&;LgA z$wTwHW~yDkJ-EZAUArxFOxtpDT?8)KXY@R>jwY7wuV;KBVZiE@hch*{9!c7e#A~E9 zPkuyvj_N6sM=Ei1X9P6U>N$GQuG${QI#_rgSZaTJio*C?+!UkBk!G6Lis#Rc8(%l^ zfWp@MN26L?O)A=SR&i>}_Z*GIJCq~zBh?F%)qH1JbQr6&%70Wicj(B%QWrlzPY-{? z8}WXy6Hr*Qav!dG&d8Q2TLG>Vg^b4t>h2eaEw##ZBFk z8CMp1^}PCVkVky4i!O<6Cvj3X-?dD>YQHtFd-lp39mbxxwB=*z^((%Q#&rIaGp?n> zJfA&TN$xi%TF7;IP@CUkM9*qF&(2W0(|){spPlx+hMJlxsdJ1}&o)RLJuqQ*fRXZ5 z??X}dJua%h&mA6lHm7m@$gF+)cVwTg(IH{5P;GzHc0-RG+~a>Z%}AW|>_EcNHL7-jWmR-JYneGV)$%yHP7T`i@oG;pRI{B~$(W`ZDF^4P!ag z;x;JG?6O?r#pTUPb4S18*7=gIFlN|5&$k&qUV`z~{xu&e_>G%laP>>R`IY%@({5^> z?|#Q8An(xo_rv*S|=4v;38dTf+raRx-eVUy8@nZM9{&_w-iWiTw3Qis4urR?Rqn6k^CHite1M9n^ z`>qU9J(PiFflPS6?1kr#D8y0ZGTq`R@^ano%K4ydkO ze0iB#>a_<4i*L`Umv>9$>g6kQI^Dhc@?FB6(c{E7>t4`H6%H{y^rj$aUqF!KLH$BE zrFntA8fE9&DR>W6;cAs_@LDn^*7Mz!GCz;5nf`iH?^cU`epxNMpIEMUdIG=Xk5+*}Z6YqqS>nO3cX($+@#K;~gKBC0ZK3I&vf| z{qQ-<tk*9U@b8QSmk+Z_icG}0$GzfD-rN~GY}k`1hc1oI`vr{o95^M`&#Fzao0(A)Wkr>-Hip_I z)(&~`io;Hg?-%&Y(#x;(ZHZa(fpn`)lfwcP1&4Qz_z+m{8G zOiXnu@||gL(!RY}?jU*R;1^v&JRi-qa85sE*zXoMOm~G{vic%%k@2?l9GjzRC!=k8 zmL}I*vOS{O#fU{Z%AE5|Cvw z^QSL=D0sR&7Y6&~Cib(73UwYlNLyX6rm?QZ%|IKIwf4pxw)=hdDs(HH z(Lgz4;3%7{-kW2?xp$+&^y{79-opKJirL-*lReL~Z1-D;wWIvwmFMg-aXR~0*EOrL zL&(R`L0)&?1lu+{=wxC&$w0YwD>H4mS1GPN5*9i24b1flwki&B|58%;@M!wyFEhfk zu62mcIRC*qOq{G3zGiB_l(;rt+jsPc6t}Au6IuW4heYLh8L^tq!-_|!`SjDb&hsHJIiRO6)BllR|8<$i8^zU2D!&qbLjeldd2Zt<%-Do4f7vI*U_&&06F zOI^iQ%^l3@OboJ8++Psr^g7GW#aiqzEhv82$llo>GBgScE}u_4|9(+uc7Av5h`lPt ziw>L#j9x$AJ~`B3m@!|`-=@|HTV1Q!>gtU;MLPTNWBP@peF*L^%<$}4_oR(*c&TyZ z`t9low@N%75Gj!V@x}T!cNnI zJ`YLs^SWK?7ILz+vg`9HHcoHjVwIC#L}_nqao#p;!e^7^82_z()4AiWhVloeI`D4q zP*!}Bo}mywW0Bl!J!knO7ajE_?Jj9tpS?=0pt!&4sQ0y$U6#)tZKiQr;XNm6R(ET! zYi#+Y`n1JKdcE#XtC8=}%O<O4bJ23sKA$@^eP7cQ|G8a4#^!#o33#;h!#MvriGD+#2Kn;(T8(aHQ!++r)?QCr z-LWIRcbR**9DC$`HG7-ay(6PW9p=~fUNk1($0#G)sm4a#ZoTWe_6VLF-u=_aT;~jB z!`{mdy7k<8C$d-MniCFtUnn@f>225bn2D%Mm*yAjCl1oEGb`-YsrJGJo%@V_+0Td9 zqJPJf$pe+I9~`hS?VW4#&bEE;R-e)5T1cu(QJcGNd9Fr7<~;Kr95;8%pqAlJhVef( z9_rRLVEEW(dqxNhS`{1||2F@5X58JJtrPDJO=w@}m-FRebDyLK@@muW+jKWA)-byN ze87fHPd!TApWVOPtmw+TXOF_HcRe{Wbj;%yNjjfTU%vEdga4{8F$(?5nrPPgU@+~* z$4)0Uyq_F9^qtcqPRT5B`YY28p)a%sI=ozAuUxv>Jmd9;m5bh9D06<}K5S~vz}AOv zsL%g&v(3GZw^Ck@&s`9ekaxM>>pKs6w7z{q)i1l)JLdX<8^u?J@fO$Qws>Z>xEOuO zH?Z)^uv#XUHNOl$*>J_W6Cq|dPj$1?KYf0{!1RypS03Lax^iq~kyhG{y}dG`PA;KL zojvnXOXch&#V+SNkDYU&)|IqOi$lDNb`g8SgFcO2+O(7TvYL$^EnnAhTg0w@qgK6o zTz}$&r&FRb_k?VS(6L#!G5EuJlYqoX9r>Wu-IJ}>&b(Bz#Tao@u_+9My(MaRUafO+*e0%>E>-=zw^sOM{aYO-B!QG zT(t?;=0s=RjahZrXval4@15_*ZP_(r>XX}fQtf{a+b-Uex`4>b7Rc~F0Zx^SL;Hl9q zuD{oUeWUAVCy#K_J*@D?HOXpS_@Vt_xhdj&!y`9`yB&SjG7>L;aJ+m{k`|m%-uZlQ zqV~X5o=cj)$ZdUlgkOV0HreZo8|^9MTs8;3&jTfENkBEw%W!A8!dM=V^L;a?RM*&XZg+v=tkh8V;|iApqlX`?VOTggDWCtf$8=sc*=oy`q^Exu1%hIwdpF;Y0KR0N7b3m_# zhtwO{$sagXyl>0qd8&rB_T3WB%Jyj!KJ~JBY29(l`EO0zc`scfo@d)E{Mn%8jr+NG z*>9!zPBm{wuR4b_Uv7Jvx9rROq^1r&HP-gy1vY$|?DS%MZnK_eEd}py^?%rP-kY7j;M~5UE!rIz{A~E82mSYj^l`ja^J$rXy>_0;4s&lleAN7mXz}8}s~es* zihJ*}bi{!BqPA9p+KQEzY%d(wqOQ`hIcj6KwN2boV0Yx$oKN!28h5MFz4zo>HZ|2evUbiYqaJ5Vr#6jsN=xH@zP#1j-q&z=#M|IDX3nc3qK3VCY5YLGre81j zknGosFL^$Eav*m^-^I%5tsf;$%W>e0PN|oY_1G$J-jV?$Ej`{}uP?X3cg>M)M-*=y z;~uphw||eTvXbta-V>XIbrSDiRbFS+%nKHLcchs&7RNahii3Jc;0Ku$oVfXE;8+MyU70CD3{=7?_1Vc zZhte*)b;4~HBTO$dY`axV^aw=|E$fD%tyV9K=<}s%)76LinSRPG z+Mqpt*uo&af|eJXTF30_7N*s;(3Wo`6emv!&%dYhX6TU5gCBK^?AZThJq3|}7mtot zcV1j@Dl?{ah>iWM>%&Zsk4u<8WybaA=S~D%uRXY0+{S|Yb*h&LgLm}E9+ROHuO75( z=*ILzZBB)71z%#;Jy@-4qGBCwJMdCj+Z-I3?BFK_?uggwuSq+)Q#D9e%eLVNh>@KdB0SU&&Bu;QnZYCuI|xf zwX(}$#jz)92KtsRc{Flss|}-8ZdSiFuX*t8q%HZ^9@SZOIcJ{ofu80eaWjrQOtMg1 zdbDDmgUXDKynSx7N+8GsoV!|D^P4qKo*-?9)2_kpo8g?MVCV`F>iM z*V(7lxkH^tD){Go(C9F7k&@c$cH@lB^c%82##iX z=+)a_nm8cggmLEKm8+AEY}IJQOWH6(exA}P)tvY^l}9Gc0%pt|G`gqOF^}524tQI1 zm~z{GDfiZRg~-cBDaF?`&Bn*gp098qv2N7S`&)~WuC|z}cy^Np=Y7ivodwuvqmH>YqWT}`&U+dXfq zeTN$>v$tG2G4{&!(vO|TJo0ThF6Yx8pLq^9-IKDq$XQHm!LR*bXSJRq?x@W;+edzU z`-VLGovA9CnrBsw<_sL2*uW@YcETa=tI8KW?ne#JeXrg)=WOJ@tjPMOvv=$toY0|0 z)BS3~gGYw8OFQhp=UI~2XwA`t1N;MbRVT$=Ui0{xW1IDtgZ9eZGS!`UTTgs%q>A>6 zQSCz2#`<=g=IgfOzIvw0a^bJz-06P){h_>o#i_;bYaC4N?7naDwd>b67j3+> zJjCWk`U&T}SA8!f`@GziGSJ61QQ?kLymgNoYUVfhRx{{n&F}ukUT&Iuo_q1}9X@&e zt;Q`bb{LZyoZ*qMFvVM3t3kl!=)R-xTAx=9TA8fk$gj`SJJes^wAsnS?NZ~9s5CO) z@3w4cg0Eb9cG>pCtW2vWIU5!X$&IbOc2xSlrz2mPPWIirjyHCBwROr0F;CR3Z6_%D z%$Da2)LD77yXbDxwCdC2%wts#7}zYkym;+{YpH58ZWkX^xs_LM&XvnoUtYc2Y4n|h zcXe-y#|cyQF1$HpIwW9UP=WqI$DnyiZiQtUzJcBf?apa&RfaC{+EDh+Gj@!JU)dEs z|IDt@)$UHsR=fPXx16|N8-7Cib{|uZEO))P-Nrcf>NqawR_rC;?m5@pZrkOlc(=aM z?nO*WtZQ!ahLeu*nX@bt%N`v$^2+es;q)-qgyohd`!{bpoMkP4AzNX2zubY1jdOgC zCU{S4dcvc7(y-A6JhK4v75i0ETOU_lywOcQ&%lCLya?mJrh%1xb8AnLxrOWTQT`|8 zW(JjZ9pJWojq}K+q#p1bdwOw3u zj5Vj0243+fwqMpXHoJf8#KP)^k%`&z;?M|@LFC}IoEZIm79VcKSZAy$3>r49%-`Se zs=aOA1vm8#D??2-EsWB=w>{p$C^aU?<7H97wxW`(hsSfpCO1#Udkq^FyR(Z!)RO?e z^Npqiejd}t$}iT)%&k~OQMrk>q0QJl2kVkk!xZD61@;?X>gQ#dY*zAilU4eG`G(<> zmnufLtPz#+Q9X3g;RZ3e!R_OVZ6=lkm-!YsrP`k~m^modto@5%XZc5-Azjj)E#}_p zXLxFbZWwowda~U%<0A1}Uzy&fK+zA866vd`)BFzSo|cHd)C zuy?<0*7GQBvBezac>l9bCcCm+bsv8WacF$kD`<2x+u%3WCQb)yD;rFb(>80>!!_kq zU#CS0!Ctw6?jgli4+~4aeEFPy^jcQM2antVn*xs0T%s=qhjUao$D(h^=#TJDM zTRDj*Qw%~w$J>Y18ts-mq;pVFq?>P>(T)~dxh{zH zT)HgL_0pZvlX@qLO9vLGZ(s2yC*oSHV#=d~hKqKrv&!|GO)mhP^9z1qP#W}Q@wra%8j_A2qJ&xHU+jNuP70-d`^{-!`-8 z^K?OsU&`uux6koW${lxw+RSQVXtJ-BqVCH&W)962t%4>x1s3dg@ymKW%|UEEa#(y& z#)s_QmkSCt-qQ;J`Pre1_C{!TKd{JHWqowunb2hW`F!JH4z+Cj6|Hn_Pc%|jpY7uu z*(s!748MQyhqRua8A74W$-0rorNa}{x3Ax+8*%$VKaRmCXDhdCPtVmCgI#ZQD{!vS z=R?SV>Dd-5JIBne$Zs2_+%&g(7jFkK*S&KHNea`jFDJ(Xwo>Fi`ZF|-y z(=f5EZFqc0V3x_DF&Vn=Iu$y!8}d15+HEht#FHUzrO#cJTfcR(nUbU&8@EwA>P49C z`4-DfKI1KD4maJmH9z#~IG#i5U`6E}w-qwdpU5qm5ijqoH(OoDB}wB_yCrI?W?xtB zUtFME>-{LD8_Qj*ZLp}OGSsnyq3Pzp+V{^o*4-3Tr;dB=#sgI9lmijSVtAR&DEmvMkXnw`-aSJW( z9TUF?OB=*2+1{|&>Witxkh8{~y?WMcFrC7skfnWMo+hc%X&rL+3Ij&O{Am3i@ja#dcWx+GC5{{ zp?McOjX@JTbt^RMykKGNelJJ&>ED9qGjMWB#{mbgE4#i+TiCbl&g4Ebs^4`<4Y}ra zw@uLyBiFpa-p}R?+A=q8*pu*~rAG{lv`TX9*tvQA5 z6NWzglH>Ov$*1}KX=?Jtrrm9x-#5~Dx@p6JXYQpQMa}NsfAnnLl_$Hb!ybqTe>)0YkdwMv!k zSG>+J-~4vb$`5ax%P!rShu3#shegYr}gc+r4Jl% z{`kuFACFxTZA#NBTA9&n?~ZdzPDY(MJN?vI6|I-&yC_b&FlTJ%%(N@DF7ggpgzt^8 zTRQer&@%H*O_x7vR5M~*$91bl_1m?w{^M6G@&zZOQcl0y5V9w8osCY!`VYYyBNGEm zRtL%JthGw+zNX~T%tiBCSuX4`LUFNL!SE%S3&w;A)<0d)>Furga@|DpP8lbP*NmDc z8l-+yP-kDE@b=A1q07(ro9(h~#S08!}cFB z%oiVZ8-6o2vgI?3|D+Tjubs+g7HB8#eZItV)xg%dFPb;-8*zJmw#}iF`x_O{RB{dr zIFdgqn_d9ue*I|DE8iP;^7DdP3>v99pij+#QAJxVKYY-Ps@`e$yYYF`)6V#u-o9t@ z1f|XwE(Vyc+%qfCLQ7xQcFVz!bM><})XFSsxM|{&PWw(7?N*xRcs9EE-j4c<&kU*7 z&L=T`E+?y5ADc0&o{mtRJ^01l4i8q%^_nyH(w(;X`!km~y9KpqWc&EO=A6ERg6`Qp zyP@{Z<>=@a=I=H-t%^F~R^QU>?uLQRv$_SmIsIB``8B)kGsk{P({B}()q9cgLG!2x z{gVyNW{yd$Z!|-*bjh+EPDO9mRv*;Cc!%vEtJ+Hs%-{I-O7$t3zPr!u&`6!7 zSfFs+J#=_<;N?QY8V5^bk_PwG&1-)t{o(8}A%gtr8O_v>2RZp=sA+7P7&rQ~hurDL zIZ4qyy97kO{&b~m>2vQsAp>r{Z!v6TGi>bBX8Tw%)?)nmzi>)E+p}5jt@i@UkzF75_p^;&cSU^q{W0s&HG;!5Cfpy^I%8--pV;30%Iw}0 zMK*|CFmIw>>ta1Qk=?tLjt$q>dsNqCb^odM3-Yt~wivqa+_S+4+Vy{MX}DvbkbPxO zYhLqgSI__ETnFVd%^y7sT)bG+=-Gy=OI_Z_iS7>=(RPqk+wDt~#dTYZD^#0vOewML zwy{U-3bx39nscm1x5mx(zV6+m}BF$5$8m-EyJ+<^~k2I&)rk6i+(|ql{ zx4w-SZs=^*CU{s>#Ht6zFJJZYt116FJH-8==cUCXat}O7S6SDqd5*aS@Z(H zygaMNmLmr&sek>w#~R-aa*Fflf=sIDX#KCZ?;_@bgo8 zJy*E+a{kEMT}&5^dS_qszFDw~{qj03T}|U|K3Q}9Xu|tbk5syDTv+pky6488V-(x3 zbx93vXniYU+3HqJn||qI+V9Zn4Mn-177iP)-LgP0D8{IC1Xz^})5T z2NZ0Kt5#CI&ix)cf`vL6W3qPzsmC8m-#C;Ta;nX`m@fho-PI4QqpejI8@h~}*KAoq#oRsL!P9?gNOnE6sN3k6}o=UJGIg6vENWW;HG@8(e z~ALf#`KuBV@l2G{0XwJLXSNO^-11BE!{k(BqDSo`9A4W0F~%YIi*@8uOR!K>G3o| zTavGmeI0sCce*K=k-VQ;#50W0o#ax|r(2bj=*!ZT^f-1zMMtp(J)T0KJKB`blYP21 zM9G_AO7d=M5$`z!2a=zXK79~YX*i({$?M4eNO~MX=t%NyvTs0-=`KE{rX;6Ot4>%< z=uPsc^8CAytVR6A<@p~^vK5_Ar~cuu2caIxo2caygamt%@6vhrGni15oV&p<+r3i%Hrxiy`?Se}0$k{gm7OD*ipB{-7&ob(aT5d<2y${Wh_KZ|5r zl5@-RA3$<5l2fTgJuM+Pllbd3pJA44s!4<&RV`4Q=(zo7&} zl2@1Ke+J3zNzN(Hzdy-MNIpcZDq$g^C&}+gANj0m{GTk(zb9Q&pRV6ZEsr1~bRziy z=_4O*gjyu8EYJTmlG~Detvvs}B%6_(NG;+SM(9rRYtl#ls~Z0o%Jc6{*O=1vd#FXc z=MWr7en$Gp|8PPblGm5#KZN9tB;P5||2UGHl6-_(b;4poZ<0TMXZ#a{f9Dgrkz7Lh$Y)jKKchVVUUW?Z zx_%e6h}UdFSCXHQKJq_|P@Ckn<@ujUatD%cmFIsf$rdChQ>#W;MCe8GN76_Bs~Z2O z%kw{yt}&+Tw^NJj#e~izKO}wRe+a>VyIsV&d7)0F3P^yRs{>hkqChVon^ZFyx* zEqShzp1e@Yso7@UqM&i1N!co@^aAUSC_YfzNNOj8uV55P;8dgijtcF1ROy~zHM;Rvo$e1NkLljYum7|p*K5;nVe8QS>$GQ} ze|q$<2L02ge>Le}E&69b{|xD0ZTe?N|Cl~&(GTlOn>;{&tWVZ2`qt$1;+!M_19oVpxijyb0VryZv=$CWdZGm#_aY~~#2+{2zra@a`P2d(Uq?H=uzDE41JD`Z41{bk6pBe)X; zgfs$_1wYflSJhwHg}<8^_9D)Pk z6v33Rjo?ivBeLk9$_QFgHS-wB7_rM2$u*}ggC-@!b^fOVLqW7;VhvsA%-x9@Q6^8 zu$nNKkV9xgI7A30yeD8rnoa0RI7w(g*h=ssJRs;2RucLXt`S-h5($$DuL){|MTB02 z3j_Q3{GeT{`dcrWm9YP1f5yDKuXMzqf(BUd`mQ%Z&T32dasl7t&6>3{h+k)Bz zY7?lPNbN*wOQY8OzufZ86^_MkR{+6-#VsWqo|7qz>n^`q90+9%XLq1J#} z18Ub&yO!D^)DEHc7PYsiZAWc8YLlr=rgl2D)2aPP?MG^{>rSbN2#4f?JR1`s4b%wvz#5lh~Q4pB=jLz5&{X>7dsIe5k?dA z34;hWgsB8MLKlJwVHBY{p&y|oVG@B)J%|aN3C9V>gw2GJgnI;99RwPJY8(SW9n#ej zv=CU+9MeY7h+`pWD5%dFDe$JbXpCSgXQm)XFoAsQFBljNh;TT!AJ;`VQ8k8`%YjIVC>a^A73i)CMzA9f?tk174t|8XuTk>0pZN+W*=HjM&6Mj9h zJKswjAok@?7l-gC@yCl@#RK?5`Gdty{9a;5aVLHn|D-rme2#xhoXfw;za%aZzu|x4 zzZVzrpNSue@A5Z`xAAxLW5h}PBjSVNc>YrUN^z8U4S#`nF+Y?q6bpE>MN33sytSeY zycN7~QG)0IFNJqVw1c-tv|Y4`cTZHvd&+wxddK@LdMkRx%i>)V<%w?cGDH`7CwRw1 zokb43p1f|NLA+t2fug>=K;C50EYUQcpJ*I!6wgCs#A_gGCNkr-6LsXZD8iNeGe19gJ~lH z-@PLHUdFFu?OXrEBIULq^fKFAA9cuU)NRL`JVi9g$Tir0D*?& zB(W1av1HjX!I&hLZP~Gmoe0}WOcIb~>B_o^{&DY>|AYYMPidej^|TCSTK*Uw?RZKH zE(DrF+IrfQrZhth&2;kmc;L>XOoqp_el2~IGAWtgcki{XwvMkX%k3w$=vV)$T;yE%D&((J+*Gn&Z!2QbX1wO5OO!@DW z`A$*uyNq%~gXH7apy{-#{-y9U_U}|C{`CgIY0ZH&{&$LJpE5CgSox^(OmiTOfB5v~ z%B;Ul_|N4(`aj#gH^0j`xqjvHU#Id;29<7xsqkY49sZtrM?d_`!bi&p?R@vR2=iP&O4XHzYWCzIUkHKct3IHFulyKH1dTKQ=NxHd-33EeZV9p|OeKfxK_HI_Aa%O_(l| zYD2PVqBb;ESyWxzI))j2HCH0TtQ#YJ_lj;bFAWaT9Wh$RT-Iw_YvqyB@O}|VS%3dT zrLR^B{)vRuytGF)P4o?mMy?q^#!z|pP^r@TX4RH!`_;d}njBM-+U-MqqxV)-*fcR* zmfmf_V@vX79eG!&zZ8aIc}K^q+go|)q11ZKHP_^8^6Gf0zpODE9h3IHU1Jk+eZz5F zCgxl`t*z_#jh8Cr(rAAvuTJdVU8>fq(FuLITsbl}n)mm~&AEJ2ZkKIvwrZ#*Mk^)R zwrjYgaUB_}?9UY?WAbN3qgWZJccc_JG&a>zrB)srZM|orTC;(crm?)gGFGj&^$(T$ z?+wFIDOD$iWrP$CP3$gNywpSsyDzB+uL=+;3LE>ewtUmYc z?kkTjX&smC*MAWUJeaR+R zf8VG^E#DR9Ol53fqQ5i{I=57Qjq^g`UCRf`gM*qAqqWvNA0Jb1gPyvLW1}(dNBZ`Q zYmW>?-@P(04w83SF{ZBdS#?|Rj?FFRW8~Gi59C`)Bebr(UJ4iO-MhD4l43=>v@RC) z8qEm#g&BZ{85sPaNv}8=tdvUmqMLg*4=iq%gu1jG8C5rHWJ0r9Q6wpvi(?bJ zum)7}wcWRFtA_q+IcQTz!W&1Peh!v3=?3NJ2@Ml$(H^++fw59`^y*qef19&QeKm#g zex`KY?_pjiYn+saRW2&+&i95@Wlu>y45km4wLmbXOMMlecs02ut{>taF4ff6{NB;A zy+Ov3ygX21HCU2Y<1qD)jcX3E0$GSL?=0r%du2>>Z6t4N3(>^Xj%%QdDGv|Rmx<9Z z9c4y&bdNk#-pwLZrt_>3`CB^nE$mpiZ%H1Z-rmylF0CE8l7@0uSu1b8ZtJ@0Doq-V z#Xx?ekuC|7V4{{(W!bX!j`r)93m2=0k#}4xjhfYk@_p(&!_S3s@G zM|AbU;c$qiS{g3(%MVdRmdWap#&L9aZOE%a9S9Ca)-L)ie3h29{;BS(yEmy0Hr|-< zE0opmbTI1F3{xB{Ib)U9#=*gBM{0w4R;gWE86MEzjoFoDH+OHieZ5|@?72C@y{glc zV|iAvjrI4j1c$j&5=WM8%q?2^4ue&wFwJwGw z`y|rrwo#&77fUt{OSDMY5*hXj(z!ltC~S<&_gRSNx&+C=l~vk4^nuDUZ)dB3?n)b@`fI*a`n)24=QmPf}m zZMh)zjTGB7p_4}S0qt69HFT2GvuP^sI#@7Lsf^r2^ncdYb`!nP_NdaQ@!zws+`h0J zx>sGC@7hn>4Q*{%#!@0NQCA$bY@4<#nks|ZH?jQ+>$)CIX^K?tEonw9T3B98|3Uzd zl&d3sH7(#+90>AiY4?b(QTc`q`NHKpvTS0sqEewwI^4^LDh&EVJsyTq_4B0d#B%!G+Bz0N&-!xI{iIBJ!?QK=60 zY0ViKUsztEOYWNiqEq-T(U9yD%tAj$#vTySLpn)~tdnACU`W@@5Kj%- z-dt~6SZ2YDoBnVmAr_Y8W23sJtBoa}wQnymRwvZum++~_ZMD`{skMy_w!tiWr^K1v z{5U}$6(u{sJYQMjQpIDi@UA#LeUW#H zwXvTw4Bk}Tb*r`K&`nk9A&>p>;l6$@fYq_`DcegkwEKFL>R463s_47v+NJ1nutg!R z`}l$KSXkI}tye|c^7dEdo7cQy{nos@ySqW1>?_g{_pvVJJgKfgW9`ct@J!Z4o;sfC z9jmxs+0t{}NqZCQ=-JYv6>@S9Ai62|s7_SIOS`S#;p)TXZ}+G+zHIJT;#p-E>Lz*W zZccmEMT4wX`IRh?HFo(s!u7m=tWud6=kgUV5WeeSfkTEbFW6VzKiWUUw#II~rjyy| z`Wp6*)rpY?re%%jwd>TrN&AGcll#($zBDqfg|2*(_>uBH^)2kuwNcXT?aAV%>L1tk zBOK+Fbrp}-(E471JGP3>aCFyB>l8b56tFw&DL$mT+ADM3$UQ6Pb9Gnf=6ToHaJ6n5U9aEUnjJ2m z&4`K65s6Mq5+4OV9ZC33T$_6~QNb2$a2Zp58N2FjZj?KKc@%vd*0eA^qAaiX5sAJ( z{1(N--zgrHNj%5c`BuflKXhe7_bEPJx*_D9FWHctQ0`DZc4%F;Sv2D+lWFTw_O^@E zmY*g1XV+)Pl@I*m`s~Cr>$4wTwIMqq*!hF?*|}G5$Xb;<{$YLA@wDjv=lbl3^0@ND z;y?7IuI!-lQ~OnxY%+QdCVE!Nz7w+h5%u8`$!e6JdfUeAUFt*2{Ts7m|1B3=8MnIy-Ai%@ssG#f$L> z|Ilbj2WS-&m$l{GUsiMisT+~ulX_E-8O3##EBERwpi~~cx5NqA`mI}U-MT8jmHURc zu@|||!{gS}h zS6Gu$-f3<9r}FQr=n%1i2WRT<<~z5n(P9=m9ZxDw%ih3O8{&z97H}Okh|6?c(KbBT zc7={_wS{GCqXX1<@XrQ;2RZw7S~R+Q>iAvDD%xiE?nt=8LnN5vvV+=z(y)#=bm8Tm zFsLc2m|Tw+Eo*OI{;KOa#++V;FO+p*x*Es(|HwVrH;=<$hgrZyLlN1ph^*@fzfaC-9q3n9bqX+=AbxPDB3%TI`vIw%ab<>E$%o zzp%e9uMthWFkKZLmbws zzPO569BtN;nolxMJ=bVp$9+1Gi+W@ymbQ=g56WD(qdOcDvR@19hd;s40;k0fdA*`9 z@YrL@@c3_#*kxnKabggIw{^s2y+=fLTU94kt5_$)l73fP9Eei&jd?gu?1fQ_; zCZ0Q#+!mnxqQ{krfx70>J{=GG*;hPqMR&L`n6CqV!`R?pkk^0L@UBsr7Lwe9$iQ#G zCo46%mgK`a;2*wkq;L6>e3y#5?$l#=-IS=POJga&VOY|5wlF+$SKkOL7&5o9l-p_; zrmY>`s!LnSYx5fxmV*t$wY$Qi7tDYs(5A~_euJKVkG1JBrS`NsdWVlBeS>#h+xEu0 z_KlbOYSn=^29;A*h(*3`=rB-$G2%;x0xCS}Se)NL52C=}g(?3G4_-Sd{6?Jw$7feV za=fjXx_Q$IEk|hG3yoS)qIK9;OglulZ>63`^{CLJ)4od2x+Qv$d1KzartSI_OZ0U7 z#(d4zElcw4vCy`CNLNS`Sd=Cgi)vfXnynJjrD9yn7d2YO>&tSohR?!(dH|@s5VtrA z$Kml1QSq^{j_KWnc|JNdo|w%#`k0(7il?ypGM_!v7KJ67*CKX}?I}rG49+mVd(tl7 zUaIUGlj9c+l=Nc6;&_2}>O3E~E9@>}G^epw*nZ?UEbH*`zHj(0`QtTjjQ=JJWO(S$ zbM?3^CDzLHk-o_VSN3YeU7qj0g4tamUUl)?8wJOCtboxyPkX+N!(Kgx)ru7!DOZ`f zHO^nXOPQY3g`J2wVQoNUknR%0QXVISc4O_io~OMbh%|v(?N1h%=e00h#_!ubI(ScY zWY=|X)Gl_iZ{gx)7dv`o@jhVFP4=XzcC8|A%8Yu+*M=qeo#MQ+yJty$vkEtBsacZWqEgQ-H!sOIP}MD>O)BX5Qn+Ei_vOBfnuqzUcZD(!*sV?syk#uytt}7~C~7POzxUcU1buHHp{i zfX43n`}D|Laof|iAs)6DIu_mo*i9S+36qyiU9$9IR6HeT^kT5+g_vqd56*(Ode*$Y zz69j?$UQncG&AyU*{J1Y>PZgsa|;g-xXVal`G&Dk4_o!;4SGq7%_4Vh>^s8UrtT~3 znMwU!n!L?@!MtpX(@*}Y>ax`5%ev%+TdH6$@iI^HM>aR<%x80>p61)FY$CA3J<&hnKM-vqf;pwdo55umx zxBxD%zl;GHyGB>N=sGqY@s%%C*5f}e+L}gsr$jHR=zW^o!do9Kgj%+ERwoyQ7i#ow zRVny7yfMPtap9FXw&d-ScWbick63bTc|KG;@xYOb=NnfJezM#^@Iw#vL&4q@z|1q)%fx>i`Oe!Gn<6<`8KTmthSEX zLLF*qF6iwBK|MsQakHjPh0siIo3(dzEYvO6Ev0yLwkp)8SZkNI8FE1DvC-} zhHK?X3$!SoM9=#HMHxw5z9?A^CMEHl;<}Ugw%u{E{J5^4M4E*){^aT`Tr}(M@t9}2 zO=^!9*)Ro*ru#TAWSnfl*R-vNO4bu!B8gY$wryb!5(s{cWx%yehv10urZz1{S|K>X zju&DPDIhaDht()oGhX!315oW=!<`=@^{xk-;r!0c-D@Ww>gx3%#5mb4I<^V~ERD$v z2jRrhESd7oNN8va@;Anl<9LWEi?w8ggJBGUz~97hi-MjWf4Xdj_!iHI2>ofy$kgU% zM7(n`skd#aZ|V)QVailW8oImIY*%xpTR=N49KoP`VfXbb^ekn<3wq-q*65YtSkP%< zENDrf&{~(FQP%6mCpBkUk~KZG{)C6l;Zeu{Pwm62CW~|;sA)>PG;UwM!U?9fv)Dxu z;eI|wV*LQ@7LLqybjNxn{hHSFR_mn(T&rVzJ8!qPl6oyRxg>_IW_-=cP7rk8rPq%A z0)?5`_OO2Y)kjb7c!hLQjQ0P!wxugDYnoqPb!)Hi)kUX=h*KbPb>6H|>esrZ@qr=BvsQj}Sfi(dca_7{M@Rm#2lQ3lsBwm+nB&b{t~G7< z4QET#C%sTqrf+#$t&MfO^`BW$t`4A~wY9!A3}7qn9ah}h>m76KZcxwmaB|@hjSqBvjfs~NJ;Q0-5-y(MFu*5HWY7^ph4a9Y z0wZl%x`C<0Y7rhkWlQfU57hJ!W9h~c4;QngYqc=+lq%~q?25us4)E*iVZ1QKsS+1X zu0Q!T`bY0qhBry*=-z90X`PE&bK&XxbX*g{{Yl(tPwD=4-FHY}*i31K;T5Si^iBDMbT&X@2$YkDjZ#lkWnQVD=#Z?c(RBqg^tF05P5AP1f zDG-)G%^K8PF5OJln{CGG8XK;&;Zmx$Mr*OIt04xu^kz!DX85lSN_xL?a^KR3*YA() zeM5f%D>%ybRa?fwt2vWbWz8sixUO@xJ2o`5DPDJ5GrRs;$fnW4Tnpv zB^A^3Ib6ThYhr22C4>&EzEZ03+SrZxH2mSlPHps?xUm<{Lcimdp6k2h*qymZeV>_z zoUOVc>VjV1?{(LoOH7Wj`e`rdYOSxg4}@iqKBVnBJ52Vg3f%Cvu-4l6D43(g=u`D| za$gJGULBK+=%u%~l=kV+$=%2yi*~bHZ8ifiOQ%wv=6@8pq9AB4);p>X^9^4@sMZI*E(Y6 zOmT8}PJW}dJ}&8&ZZbq0YOeFF3s*Ppn{>h89>>p`>C_z+&a%QPsEd>?r>aW_Kka6` zU98sQQC$v<;T5wmTX=@7qYBM!7CB98V3^inj{CllO>%?vYjPhm=~Qf-T5oUY=|-8h z9-XZW>;2{sbd8q;ouBhkgwKAi#mw``n3XoY)nJn(+(>J(Oljt-#Jx`d*%pqu;}3RR zD0>Q*z|KLheAjB@tClVezrnC~ne{l7SDD-8)9{ji{kniTQ*Htpc_+D!K;OWB_4RrY z_rNC~GQ{0{DXiX8PY>*k0QIq9y^gUe`|+V>1xE+<)l$a|T^qOKl{f%P61T-kgx}Wc z$w1tx#rwf}zgd(T^rQH$5;C^)egwZe+1*#!Reyn3mp`^)dXWLmoKuE}@?6C3g`yhYc=$^vdPOS7R=rD;93%;! zTx@v_hdIF|Mc4RrcEy_m7W2A)!ff{&s0NObEcg4A6_y((rNxb$t9o7L_3M$|@U#KK zy1sZJbA^i{6{j6j?$7KAweC;Ze6N!C*$ltP<7GkZWcz!6V8D${TE^ok@~>%Ar2O%QW!It>fY+rmk6;bwphrD9euwvC0?`NJ}) z>lP13^rK0=<;?oOJ=|kx^<-@>jp~O~L#9aA6p`}Ylh!`JALN|@g=zF#vA&@r#J_I) z*3E6}vdpA-ATBFb36OZnm_TKBn&U9>&nbxR4I&N*cv2b>&r@*D{`z~lMLYrP}n4z{c+#G&vA6 zE?2H{U^2juenVXy)lCzlS|BmLQN6q(mPk`)q2Dm+OqyR2yM$?pp&jVkUngzM*Q!tW zlO(%8o{rXkmLz>)cUK$JyH4SEu(~$riZK|T;Oewf|A*(m;=Mlnlu1439=b4dW%yPd zTI>mz;VBDCwY@#=PZTEcB0Ux!-RL?KH_}$`m#a)aom;BKa_S44C=Ds^jPMN+cK)2; zV`1#|bM`FFXA4jBPY9o<{Cs7(Vk$9==NA5hCUbpxC%>&vQ)sULb7DC00kfC&r0#r*g_e-NT~0JCQ^D3=7|<{0-j!G#WQCm6h^A_k?5}PGrfg*~7vg zE69TmJ)~5g^P&sh?~8BcUfG~`k}u(1Wu?2{+_+x{MR!;^rQZ&((*5FTr0?63|BU&m zMRchxSB?gD;)LEa5}Hf0y9?viQrAC_%tLhmDz`MB~2)OSz#n`?KM>N~1& zPPSMhu|`jqxV(&q_34@h@$ zoN3=D8E#WbzftuUONNi{X4&Oypu_KpX1X}RCyTVkr|Ew6`5WR%)3AK{v}EtpSTq{b zOGFP}qqd@~r{#+U>Zd3A{g7lc&W-pP`$ZZv@1y(SQPE>Rm*CW=J@N-J*hm&}Nnbpr zeDv?oG<~=~87Ji4U$DQX7<7A(oyx_YX9}_C`k&PLutM!ECeP!tD1*366LYaR?^r`v zFTRH?TZd-5ZZH<(N#D@Pykm}GYa^dxf0~F9;^A@m8F`+VV?D|rl6+#Ik*s1|JSf>m zBxlJmIw;C}WtY*?iF4rNk0{@}hYF#c(OQeE_i z#BVg9XUz!f1C>hXI4pi2TkK8w8QaH|8};)o3+81zm(I%$D1S!zTgsPq%*#fUA5#7s z<;#}M%X*aGuKXG0e^lPGd|vjj^4}<5cHO+}t;+vNdF6_E+1r#qqx>!97rtso(eeJyL>o?BJmfbWjt0{j? zIa{s2r>K0F@~P&dc7RoUNIctx~>M`JnQbl;5;=UUpRZxN^%n*{Hlz`GE3a z3jJlgcgYMXx-h{2}GXl%H1a+Mu%X)5_Q0JTKd!{DAUTm7iAL zx^bSSh~y|ARenl&e)qhrQ+ZtZ-zgteKCZlVTi3P=*PZ{;4d3bR{L-b%9&7#h=U>E_ zu3vTcmi@h5dKz`N4#Gypd-+Pu-FnOd($+sd-ljLl^*pjs)t;(;;sx0?PZ>-EzlnaWUoIj#Iat)=^xy!`Re$(t=kvuShoh6 z4;SjFJT$d#GjyL+9rrQqkyn3^O#ADpbm3m;ktucELC4WT9hHw3>ei|5v8i=bWsgs- z3p$QXsoNZMJTbK{&^bQ4{{oNkuPN?qbE6&c^EBIKy zD&ZgAiPDmT&5Twt}eJU_9N3@`{+-9hGTRAFrCRA<(4jxbskx%M1Hsp!F7%7~V!GnIU(g@qn?7+b0Sz`>{8RC| zP^5;2_5Y<;Z>ZCDO+$+uXb&xov|P)^XP`YM+EhL~pPYdw>xeur6vTdPd~yb!PUE@N zApLQ@z&DvJ4QICCJ&k?g{X1wfJ~54~RJQwf-wZO3oBq)M8EEG(o3tJI@H{yK&v*l# z^MCr({XA6Q!8e^V@EkLqZyEgSL`Ldwk0)e)UaB4puPh>gI12gc9drxiqA(QbLgTFh2O#D7{3YlsSem`My&R!Awd6B`Z3^p3u)OPl+kDo#hv^!1K zSOb~#pZPrheKYi5yiR+=47A4*+MyX}vsX>Z{lE;g9Y)JMKRN^LPSK`*g6I1)@Ek1g zaIU@RXHM;xqsH^639st~ezQTn$Nsx#kUjtUll$=S3_P6$9^&JBGw_TX&)XAT?*q0X zqvOF-`{9W3{@ye)@PBOv87C56_tD`Qc=A`D?4xhYz|)iP$gB|8oWWoGv(xtxI(%}# zcz@2|M-Bdl!AA`KiNU`xc&d5qzAi$1fL%vU!>;)&qaQ9a*lzGfgPRTBW$+$@XKEMY z+4cVE{Y766B|3aO_szg_tiYqc+?*Xb1&^A;xMZ)1{eQ8+1qQD-xY6L928Rv4&EP?U zpD_54!7m$p(%^RuK4b8LRZ(wlaJj)QgSQ(TGI*cC2MvDI;1PqrZ}16&-!b^K!PeJC zeU}()H`rG+8`t$J7=NAgHu3ajqTlMTJL0`8ze&N)z zdQ8SH<3azx3_OQKOZt@YenAlZ|4|VAe=O+wk4P5#w4()?elMn`xDHaVL>u`D@pM`p z;Nu@(SC`xJfhhN4!8DzY+$G}aOqdS-N|cN3I}7rh%;k2jjy~TgNZmF;`pRD8!!z(6 zFy5ar-VYl5sL8;G$7hgnOthr`n($ooZ>Rbo5a=JbIq!@-O9io&er}wBXQ%PpD~Oyu z#><)B1E=6sa~RJ<#(&uOKPO24epfKWh#)?D!r-?A=L!F=Ap6(97fj~`w9iN{wp{YT zsr~hScC3j!A_;V_D&XixH}oBn(JAO@;HxnPXd5WVcN*8TQ*u4N4~mxhLj@kEg*VJu z7a~X-`JsXh|KHapZFs66&)Hq>5wn5uxcC>R`Xi;KjQ$g%Cp|5QjC0mT_!2?V)q?nV zxgcx6je?BFMnT47n_xN~`0>G0=!N#6@qEnSrv=?_kBJvMo-D}l{;6qNzkN?Uoe)@B zdRbSH3vd3R>3xAs*}7;0w3}z3?J!#6W}j%`d7!{^I`)28Je}h8^n=$#dy#w0upr}o1k>l^X2L$r+f;Q|kRBL%;m0ul=(hedkghvYC~lk?#GU(&lF zsw86vdM{BO{vmta64kW`C-a;fx*JqSoRYn6v+6p9d%9zcB-?K200Oez_nC|1lRX{>bz`fsS|? zH{Q1xe2>9@WAMWU|GmM_8vGqWAE*0Ip$8o&657Kv(B?N!%6(!6TK&C&x((S!r|&B^ z957n^xnu^~Bcg@p_Y(O#XW%(uwBhwj!Q0mPIRoUs_Gi0bn&3n3PSZPd26~4ivojI;hZjta>4yvY zoXqtels?9vemrJ2K3U*#T6nS5WdLa-f3IM}!52-+%|9Od-XWN#(~;XHp3a2nV=s>J z`$Mziaf9G*dgX?!qD*?xr4hbc{PgXh;0>SH7~YlQ{aKP&LSJ}Z{iy=qBcf+q9~X39 zcz6$%l=6O4yl&5vCKG&1z9HMGOyV6PQpz_zKgQ6xvJ2ZndZa6W+;MxyF6G;)Z>;is z+0*&|UgaLWCz8}Xc%&t(sqVlhC+Xhyn=RRb*Xv!8Uzx0X=jU6p^SA1KhotTksyi&Y zV+rr0s;jB)$%O9Ps=HsjPbGEpzR;3AsJf#G?^UWB5byVsy3MNlkm|md)D5fdpz0n@ z>fW!qyH(dH@jSidS6i}N`3B{!%Da?DmG4*nfbu7mzo7gTi5Ut^8%xk=p-5OE#|jMdj}+ulP0L%8w{NqrB=<(yjcc z@>7Rfvd&*`$@VB8S6=cPE!jThPb+^{x&71fsqz<i5wHGW;nupMH=&O$o5Z4&Vb5yDt9Sgs{BRO z{gQI4%6}{Pxbl9V6~Z48?MevJ+m&}I?^Aw{@&}YZ zs(e^^k?7A?COsqko04@gUySLe zu{w7@XLCv4*gUCz+d19wZ$IgGK*h#K&%2|qT-z{K*`}YQ43}=*b&sTFk7Vog6Qf#b zJ%3;C4&8~Ix2;qQh~5ay*6D8*ls4+8wEFt_`DbJ;4o}c_p;Zm-+IgX&DSk&AJ8AR$$sYS)xA6PIrUzB)NHK3vsxSI z?0mzT9XsyK-cL*XrGIbuEnB^@XKh#Ko!NuVIjApE;ND(&dbmy`37aiL$yR}QP+|Fg4YqIP=pS8MIe%L)cwk!0t zZ@ARSpQaKBynv#aa2-YvWIJG)w` z*4Y^;m*3uD<}H``pOTynW&Wa*E9hBsTW@)6*Ti6Fr&MjkJ=tHLySl31#E(jJ^h|UN zMAP{u^j)6s-6Sc!n~>6X?rI6C%b3Z#E@91@+vPSwBm2$h>;68ZoT`)C)^zu*=~;XG zpnjBE^Wj*o4&AsGzIOfUHMiHto!RjB@+GU&Y(>cyrm<%K>fT$cgZt|Ir#qg3 zd+40igZc|nL$l_N(I5k^W)4+{%7Zh-!t2+r-?&CWJvkA2)^sgfqiGpp>Q^=Q^?GWh zZpqA%AP;Qpy+vdBhl+(#EzGYoVb{BqNi58$*Q4OV0$2Ea*bKp|0Masa`eC;$%#t5y zJzbff?IXU-qIdj3Cw|8+9pKpI<$$kUjU z7Fr)Udv)LN-oE|S-qA6>rqgMYtyfoC+d^oHg-t=WOjfSd72Xzdze0Ai9&g!p`?{WG zD>~x->*h>f0o0G7OS&iS?OnHT-v<6bQrtRL^bYftsujCl>aUFG5Btw%&Hjc73Ouc&s^*4}4YlGR2OrM~a{5_dI{-rQKj%T>TK2YlCuR_@5CrJhR^QnE;H** zFh!pHJvx?U`-4yQqkCykH}_~enLR+yYt+d*{X={}Aw;lZH5tPyf7VdG7|g2W-TJ&y zmc1tH)gUOOEw+x(#K${;lSVbd(TDba5&es`B$CT*Ir(TePzY;r|D<>(=ueaDo00l#jdo!DrEs(%voAc^uI_>C zWl62BD_W9Onf)cT+xBY?jPUuCHC1)JL@C>moYHLDtXZ;=ReS?ipnk4xpUC=4Wvwxt zekBUOsR;)|S$5zzU;cYtw|uAbOPt|y=A9;RvOedw^3{FWS@V>jYgMA2GKn*4z6sLI zO&>I4pcw}i<>ry((r;n0&38L~yx;9;j&E~(n=#Ogfo2ReW1txW%@}CLKr;rKG0=>GW(+iA zfEYM~bk=NB78%Yy{RBsy`kd2A;(#F~J@?cpgCWqTbmyHS!6Al7K8232D>O>ti1bFC z()>ij1cwwr@5BjROM?_SjNWMzy62sg0!NS^$c;83<0BDMQskI75BflE#FIqNFC^oL z^pV<#>xAb|P0k_t&EN z!ud%`IS>zdppL{&`J%}*g~Q1MbtE>*7f+_C97u;eP)A}Ty|A7N97Z09Bdt+hR8K_? zNrya8M`9y=iKmk|j66^WVxxSir;|A(9&)H7aU^}2rv@Aec_22@i!C+ch{7kSBk9X6 zHRO27OCU#fAdaN3u+*4ik~~lc+Ml#E4Mz|TbwYeeOw)2WIg%skD`T3TL(=Qif%ejv zPQhWqp$@c{#dIo;OD=KhK%2*ON{%3WlKS$HPR(&C1;VVI-Y&@$w#`g6Ur^W(_McrlXo@vUX#D4 znc|eG_x2R$9Zue}k1};mk1Z)bx>J7o>*EO@GQGWs z(}w;uzL1^DM;2q?`YEUKk?HhaR#l+S`?|x}V>7zQ$N?ugj(u($?Tv6~q4D-cxSFT5 zJC2Xwb^ad(jxDMF=Nd;h3IBQjpDWyTyS^rlCt_kee%$@Rdchj(>qH}*zthcHgg~y{ z;?Sr508jk^p4#K>)VX|Ya(^M8GIg}OUZ+iQWTiN3XNr3)!AnAB+Mf1{cJ$KjHc$sn zJ#~%)NwlT%h@lk6kKpbz=Rt2O51i!fKoaAe$|D9+oH%j$^c5a(%Bg&ClDFeGeC0T0 z>Ks?G-tK*O`bIcyu8;OcI5Ls%?J16K*H3$jyRW?cOmKMJKKN&gi=}R#k5y{VOzqH; z=)dbfUEIgg?VoEnu|)FzH}SdW55}Iv{PDG=iO&sx_}Ke+H*q`>6Z4_z5BEl#4^4kG z{ox*H&X4B$&|D9EHvH>dAKCNyeJ|rlnL3}}++X?m4ei`xaUbdJ(55)_j?)G`8G3Nq zU7weMv=?#cxhG5IQKru6-R4F(ZQR$p{31?0+0TC{bB^KXX)fFC2S>l#13hKzbp1sf zTb&>J6o(Ieejej^+CO+x`6-S)*a}2{5l0{GB)1R#bUbNu`{1Wca(d3T+&<)`ICgOk z}G2MI3o)e^VTJjE(oNh{Knj3xSh-Je{68`cuTA$9C5br2l?i2Ts}j z15RJuf5;=J{V(FQQRn(o9C^$IpAX>pI@OOZ__2Yu`O4UExiWlm9>g~uO zJC6L6o;GZyoigpnbUf9ET$0llaqJ;``jC86K#OL1&Z?N4#+MW45y2@Y@C|JmYVpQ3-ZIQmHL|JmR^ zc5Z(Yk7GHP{6Xxb{cYlN%O8wAiS@(he-ob@{_wH)@owUHA|~cT(;x1QI3Jq+X!^rF z(3~I5^`W^Q_-y#sxjv3Rq2C**3q5a+@W87!g|mVqAL|bAvCnshvx}aqBHWp83i$kc zy2Cwr&q#!az8&GtKaKFI=S6t@f=z+0^P%o=k1=#-{B6Ti!r5!?ylzvdKQ2D*Tlf8T zgxR^90)B8L!UIP4jk6>DiQy>kgtb5X#fV>gOKk7><%o|jj_}FNW{2bwv*U-p|M22X{z2JPuV1W$!0)=#SgIL}mCl8C)%ho>7Bu z6hz*y8~nEh-zSI-e{1kB4gP^3ec304$ff`IjEs$B^uvqKE>fniS1Ln)lfhRRTq=k? z+YG+WV3#0v?NvtB9~*wJ;eRUVK13h>2fCj*$EE!$W%RByxJnRxyA9qch@OudzR~cv z8=NqRzp&$L2EQtZT#u(VmFcga|6XnF>kW1aqPJqO-{2jB=>Mp}2L;jdjKL=i{*fSk zdzbtU91%nw=hN8nI%WF1z;OIW{TgNHss>Af==+?(Pa6DXLG-prF7W?1{J#pK?`KT! z+YH_#haEBoJf5qTO41Pcmedn3pr&UJJFPfg8HCQuvzaTNbUlR>j6GS&Y z2i|6IyTR8BqW5D4KWy;l1kro0iRsY4DgJ{+=+uR|K)^w?vPgbCr?*cgonZ z&)^<|%sbluAA{c#MBjs^@4KewI|h#%{F=eX4F0|#eDI_HA@QS+H4ph;F?ihIHx2%U z!6yab|0(eS-)Zoz28RXd=RWJ-mxQC|4^02VhJRj=Id@cw(NF)O`+r4;9e<__{JOzo zg6OM=5BL_7^G%ccX9m9_h}=JtTo{}d7m{sDu#KFE}x4)<^}5k zwg8D0GJOD24|E!Aq7FIU2K4!Lp4CfzXqWn+51cmF!F?XM%n!00M=o`a!-r1C;ep0+ z%G7}~#w4dN;?Q~Dou9r@=Q#F}9rt`azqw7jc*G_JiYB=l6E%TtBofk9Nu_KlVF6 z`Y2Nee-U?mMR~3ddStu&MmXc1>MP>3rSr9jW1H(oei5fFwZDjCYieH+r>)qZ6enI& z`%~QKHNGRxz|;8wjt{AWCZ#7f!RZs(+o^}gamv&=jvj9(Rw+|Qdm|j(E}!-yPMh0D zdy2dLs;=v&oXW$tQ{l9^{VqSn(Vglq;_#Eae<{wILEl~fnc(oc|9lOa4NhO&e)wmL z!|VQle>S*}z3cx`;OKULq5rwW@fXSaeG4ofOC)G=M}6S&O995iXKE+7Fx)=?}jlzPFJ7RjhxiHNt}nV*Mf2W8aYKfrsvnaK~38 z+^6>!s2^V#;c;s}_FIPQeG7c_nBJcNo*0dA{)Mr9b2;KW_5KF!Pdz`@KP|oB$F7Vp z>y7ZK^CRqeXM_j79pMq9+oAU`;LG)12JoQX2MN&Lr)Kg$R$xZgBd5Up$V% ziK{dYX!E#)C&i(M*2fW?aq>6;r<{&E@;wfb=l9wkhpMW_4SJy`(+-ZV6sPR^X-8hM z-Q&>to!;$r`XcW3No3FujtsKfOW)vgJZ+~;o1c3&!tsy$i}oT8ugj;sh+|VKzlhUD zo%=7vv7O}n;FL*DkMDe)LVppbE%k4Tqc{_D~NG^cNX)xt9y4eW}5pG>Ba4kqxB3lrJ;r?Tdxe&U+#BjeY>p zLp@{Va~S>D55#_#4IMNNkG1!|iO0DxSN!2?rO&syh|_lx*AJina|I{Px#qD~ zp#R{MsRQrPd*MUM2kiZD+PKC$E$cOV4#!=d<7%qQq7MJE_h7H%IA!V_XMad`9Qo{# z9H;C$k;fjVD33a)N4CrJ_09D)!f8wAe~Np2IKTHtEOmX@=02hwAGtlqrH+h!;3Q}q zr!A$Y?DRwW9l!(1hm{{wc7MA+z$yFqfz!tnr%ave1D}q6-v_%xUpjWi`*xR?($iP= zjV@2cdjFxPo#gF|pN|LajGd1kexQwd=)p-&4^DRfdl~5T=yU&3PdObAc-^1C6o(#v z6#3nM(BnJT-w3D8{p<2moW7;}DNY$(@VUQI967YPJ>b~v{fD3A{RJ=jAO4h{a;mS0 z)8_47cK?7=PTR4~p1d=AAgSsoN~H85KF~&k1yznrDD6s z7wwEqvE9cDJMgFbw-Jv2d_K@##A&0>`_{1GMMLv||U5eq$T{0*42j7^e(GrjH{ssK*bKX@`$8 z5dQ+tQg&JJQxA?Wp!G3u$QZ%Lm;*`B6Gx<18jhVlUuZ{viep!b(@sVP^z1{*>Ow%K3{p`rUrlpW=*# z`-Ao(P8)SDzlbB>?Q{7lj;^A;DNZ@Hr--``Tz?VA9_qZkh~xXz|0xb1wx;7rUmd4E z&`gKZ1`RsV@3_+w+q6ML`4*U3^f3`UB;QoVuwm7^#f8d`jj_ug&{huw4ztZ@dEl&J+d|>}< zabm~g2maaOTsPA3n=KA6JgNUq7sqe(-REB;9DmX;Hd4JaUcJ5{b2lO zgVSH+r2Ri#oc^-@ru~1eabnNoAA6ol96zDk=8s=L;hzmo>~SCI>(5-o={r6k ze(C>Q!hNp!d~JlM`vKaEIR5hMH|;5oKauV8+x@Gm;BV;D_-llxN9mKic5+>p{<0cXm+unDYE_y^p7SQ2Chhe0_5W zxvZbA51jt^dk~M-=mYw}(dGKQJ;f=zeNN9h=l0WI>~4fZPjdf&Qzkh*wz+)d zV6XQF93IBd=~b-bv^fv$MV#>>xj(=ulb{DDyMMe4^mh8{_ES$e?LYddcUv7-Rj9|; zzCJ@&#Oa&&pY{~T59mwdpR(ISJGQug!08Jy;r7$!_PYEOXM9~g?M0k6j|bX|IR5l_ zqP-EG`ZtX~=;2NKPo3M(cv7a0{!E8cpSC;BSdiWRA`TtN+rcT5keBOy&z;JLl#eUt zJB2GBQa-Ni;{YwPQyf_-P9IX-#}-}^W0JPxlN86U6sMfx_&CKGhZH9UQyjmiIDSs? zG|sS(I7-_&&rWg9sZ-p~%i$$)o}IS)Iect=_E~=)&~e_MOX+!EFU9@&g41)3pSE+J zp5mP2r?{WHJHMY_JI?uVO7G7Pyge_pUtYkkFr0BAHsDL;U0I-CP{0=!@T&^=)rO~W zhI}%0t}l&CZ*OGJBIEV`EiT~K6!2>eN0-kZz5mY@?y>Iv zZsIW(=ZZgkt@ZxSMV!9-e53z!31_~0V*P32?v1z}|G4{uSm!?5=Rc4=4Et!}p{H+C zz^UW@8-Gv_&iyp=#qso3=EP0s z8{_ZWkKG!-&woO{b7#IC(eKsq#bNuM`_P7X#^3Qogvac6>-n*WKWyLo@3b$)Xj^4CA#j)GZ@zI~+*vWcJAK(XPoXOzs54Uf& zIQm#mfyirwciqmg0a^M4c*>UB74b&%92(?7kIt08h@;EL z1Ns!lKC;gXF9Y3P;=$vCdSv-{An#Q35_)J|KRB`+hu>}T{-ij5qi^(y_SxddBBlN* z;6vuA-jUBWXagQmN4^El*f*w3wXTb5H#}7DV>YN@OKAx1x zK7L*XLhp7{rY^;io#OZ&96HwrPPvgh`keAZ2aa6#2RLQw+#Y0kJ8?qUjv$D97o zCEWY!{cqwi7MlKu>q#>ne!Sy>>l(@9y@}5~e=znW_79AI6A$i~6aHX*_r&-&aregL z_0MaX{%OX?kK6oUz2`ZdpBI30{^92(;G8c&L;O3vpFe=Zo6=KG<#C=-7g5d$Oy$_CQP7&qEsF$aj9) zi#UCE`)N;c?7;?j+&*k``=IAcA+@K7(?%WqZlB}GMwZ(L4vpiKshbYRKC<`U%Ruyv z>pQ?Cr*rxEl+5`HeWTtpw6tNDpU*fg5PIs#^aFazw2>VL(oUiu&;Z>JDUNRR!B0Cl zW%o0(;B~*9364D14?o%UQBRyx=l0RhbX+NW9JnnWH`qybdM~^EKy>*$1E=iz-S^Jl z2uEkyUc_mm&iz-!vEB6}KgHc1?;kk6_PBx`-=z9eoHD$ODf+=FyS&41kIz0-brKDA z&VwFwJ5HH8$KCJ9r*1l2%~RSPM;6KB2pk)I9FRwy_oIlTmpX6veo~j(AFsx|4s+_MLc~Ug!Urtb@ZEZ5r>{S zZ!hB5l8!@)AJE@*&(7PF9Z=5Z2`XnlA*h_S2r6gK6I9Mx1(mbs3o2*l$5>-beO&Q7 z{qu40aRXvs5og?p3y)uLQp!(T%Aevs?&w55IA!+-IQ<2BJFv9}-`6-SpaA=u3 z&^V6HG+yx!w$Kh=io*{rJkF18WT!_ybd7N8-3I5!mXsga)8X_Vdw}qt364IuAAZX2 z4!8#7IHHTP(--m1 z6?$&3d`S72a;Cq>(4mYR_|oekWtU4k+4pUf@t@CcaLVpqrv;|{@cB>#dhy6?buUncYBEo+I(D!IQ;3jf~Vu=^xog;aQNu2 zw>u6br}jBbN>AN%IAi1d&=qmoeEeK?iZdQ5e-Wq6$ItmwocW*f7jfFCOYKi_VkYG; z;f0c zQ-2UsDNc;0IAfpUlvA8JnBvUa6lcz-c)AWUeyk~JJ8MviGe#-i{2lL9e_USh&lLsy z$^yQifG;fIR~7K93;3b}zPNy2Q^2n+;7ba4TLEt`;7bd5M*&}EIC1LhQyMSJlXhQ! zXlKs*dJImPI${!>dEx6VIP%l=30+10R6nv(e#)tQY$@`m_MxlTp6bU=(siQ4K6DrL z740eNFVYwFr|nVOv(K)O9(+NY+f&5do>U)Yw+DK3d3z(AHn)fNB95$7UJ=K(RDKbs zEww+zv7hAp;FL-D!R<};V{3|2PVG-|#ueR8ejZb9YoAwlKwvY_(#J%Y;P_X;YH4+|)4PMzb}?|tQ+Qe?Y%q!(Q$^DPtqwi=vEOeEW$qe&ah#lo{t+ ztc(vYkO1nLLl=mUGWWh0%dEyesCW|+2v5CAMdw%mr4EeAjK$^nX?y!#!Yqk z*iK5v9lL#;cl>S~=Ogxaa(X^%f6rE90^RY;;+f{5?r3NJxmbTpe+QQKqlO=}-v@5o z9DgU6>F?!Y)_i>r5O_>u0Bq6o2H?~7d%y=iAMwNXKEQm*LGHm@?DvKrkL^8%A9!_a zKVtRS%7`zLUiy0Yb&+q8$vgP2IDQAz5A+_f-y7!l#`+VACHQ*u_kw`O^!vsj$DWJK z*YgzcT>c1j#@C_WOM`cOBG&KJn1UbF?-PrR*FNL;>bvGWTZHH zQXHF7oPMM@w`gV)EOF`?}8 zia7d6P7h9*PqG?`^m@r@awQ8}r25 zQ{3;(oFANf7VaBUdZE+eoCCn)^eK)!&JoD8yFPzU4ST6O6;2y8F29JQujr3d9({5B z=u6Kv4tK|Mx1PoEeCLGDx9}AineGR0%B}~9oC}n(tBB(d>~cH6DN_f%``G!xDZ4&! z++)rA-^4>G)#t-p@CRd0V*b$ICLY`|C;Z`K z?c?9Xw8neUXT^YKn` z?w5G46396ObnVK}^eA(`{PW73In0wV;M2;SKYUg=@Ye)6qxguF1Ao@wdku~lJWr6b zkrpXK&JJbtavlVvjr&*L&%%zYl(FMxW$bvT!TSW^f70OB41QSDDMvHmme$oUD?qkpY3 zdf#F2Z3g!mtO!E?=LWxG@TkFu1krz+>ATTjo57bGB#zNXydm!&l+pVZgZm9m7<{uJ zbpOTRR}KDw!QU1{?_DN;lfe}RuQWJckp8z=|KTBjPW9-o(xyCSa6}Nje`fGc3_fb` zOM>wCnf%QLUt{nZgFh*V-V3D{_*UWQd66>wpAwFqCzOH54E`sBe{AqS8vLTc-!%9i z1d-DzIl!d`FEx0+AbQU>{riQZpZJ6RR^jOVBW2(p8vH$jzhm(820twb-xia<#^5r8 zmm9oL5WUYcy>BtRDu{mC$RAcadLLE>{+7Yd8T^bO`gWMy*BM-8u*2XL245nG+!veP zw;MiTa8wZe$b{}e(NVrr_2~bUGVrj$PYTk0liGo=GI*`Q%M4y*kokn%vrPY9!^aKY zBZz+19Oxb}{cBZ^{2L6eGYbB!50~96@>pB(|5n&dkntW;E2Jp!IB{Q#TM598G_!6RS$fr!515R zzQGoQ=Ln+rZ3gc%STi_g@Lq#M1_uoe2%?_^yjGd@=pus`8f1P_|3ZUYpTW@$Bu0Rq z8Bfai6}gmwT-$)04FRP-(181%fI9dcr%WBVc1eWNl;>FB$i*foz$sJbIQm&*!Ck(~ zEaLE!+y-#UB$tPL=XZUM(-(BRK5*zs&QDuvUlGSQjK9+tar#5@c61c&b)RA%}QbN3M^p+wJ>@S6SOqL2TZvOl;h5aM<7*1hIkZ9FTfqiR&xy zUW2a}LnAa-msxW?dO zLF{?0LFA#2c>!cz0P!XIFIGlBe84M|(GNec!{8!8^miIuE{OhH4BjM&-X4Q14PGvY zo>v;=@4th;Tp4}W8oXK%efSIbYGw4j(V&kDcA=Mg;6{Vj3!?vZ2C)wuz39PT=zXc- z*BGQ<=v!y-HG=5vHF&E*^iWSbdOaT28@@~seQOOep5Tlx^0z2s$3lZw3Q`X}aFs#q zM9*CYHyOmg)H5FF$1WiLLeHHBeH<1ECl0SthVQM)=+BkWcY{I32^@bxceg>t6`Z&N zG9Ku=!{E&ZiBI%*8w5x127{Lh!at&n9_AYme^LJ?gF6hq&LDn4AM*%^KY-`~VmI&_ zW%PF%Tw?Ggg4jWvp$Gq<_gaIC1*vCTfZYc1C%DVUALxM&=ytJQpqID-GA`(&e?aCP zkn0li@E7{8FdRPW83!Qa55zC%!5_fQ23^lR!qJC3pvOJqjJ~T4zRV!=969(O`Pc_! zoPhL$cKid}Y7l$CJ>Kab`ZgM*9(=Ju*GIg+K$$qi9&{k*b}L_FaFIdg1MS2Mu+yNg zZ`TS(5A8tW5QrQgX~Pa6d5<#kyOgnsxCBQYkoX7syxpWSe8fM{=QsWZ zzu4e>LG-e&0MSXlz~D~^LhtdrL}m0K2gtYqi3{j_KGT2jHiMT5BAk^?p0<`qdO{0mmo4|0v?LQRnR`jt?0} zWYZ2#O6Aed>F{&ahJS$Y0~s&mIPPQRxcks?e3H`Bf43KTslDL%1Dl*5`%`}UlJcKd zz>$&i!<*7mPTMJ`xX_T$|D?X(x#NFzXHP2cct%ip$3F@x@A#ph@{VT(m3Qdm=t<=r zX9+6rI6M9(7W>G^!xqZe2#zh3y}gKI7j54E+2TD{cV`Eck15Yz)SdMxA5=c3JYVlT zq7Q$&{31?0{!Zfudl?h&4`uI<_b;WV?ERxX9Zz&4heY2}+--@i(RXP(I#V1S;PAP9 z;FPIDPD+nmw2^)Mi#YVOQSbbeNshaZ97is7DW1|(PeM*=4`tWq{(=U1ZhsMno;GNZ z2~Khxdh9QnPc?bM-z z{vpf#-3X`6_0gW<-dE>86C7T*7yjAc*h6ytjd0pX-rp2QAAR%w%@${D;dT3;Yn*XM zx7$D0aQsd3{{JX&bd!iLAOGhH_qpQn*Tmy|m`na3*3$kq@ww#>#-7CbG_i5Tn9YM!urU*4aTAK8vOzuWIPHlWXK1)d4M^Pz5W#43iVMxqZb`rf6NpR#Wh;;L~$r+akK4W(03q07GC_x^O#O%z=bT~CVB{iG6#LKKps zk{k&kB&jGANeHQsBt;0JQVHSzn){sX`>9{w@53|x<9Wt-IAeTTd+p0wYp*reTywtX zd+iFppD5?^+ZF5=7Hn6JrHz8)%dxaeFlafJeiOV{j-~I;FFcNAjTe^lGH&u+LOB+h zIx(B?K5qQiHx1=j-lH);IZn!vV`=;Ch3Atp<$P(*$#)6mSY%ATODM-l`O;pwNBTS& zzs!6hA6))JzT{n`4!J+>dyeH?l9#q5@+#Mpdy?z&telg4QjQ!;8#43Kw#^9dFlVmyy%_G zyo^a^UUW!iUfPkF7n#elrMkD^OBci`4jn)`=zeT`ZDt(lTvna{lAl!XOs5H^M5tZBS+Q$ zSMySz{K@+!_5ay?GImM(|BiX-tIYTRJLQwPl*r3J`2tz^yYz?1eex&zhw(FVPVPeJ|(!T|T)c z&tyKIv|pZ=zWz`7MCRprx&PR_ynE8Way>II^-J0Emsx+(U&;N+^<(qWwoLi|C;v}> z{38!CTMFjWKl9>q%bflfKPt|6k2Z-AVmP`~PfS z+9UNP?|;0!Tua73X@6#3&L!=a<74x3Z_*yQmYGl5o0Rug^HQFaoyg|OS@XpfkoHSo$~;Z@Ji-H#{*m)?pZpRWMedjWke^(a zRNg_Jm;2j|Goj-~wMx{Qb1C(p?>;Tg$wS(7A{^O8z?<-X)6btPrV zbr};$r5(~Xc~7~X+$Z(Pb!l7jZjws5lFFYvEA5fI%+KTHr9JXXt{&w7X>`R0WAx-h0E_PNEgAyly|8xw;-Ll zq9EPCbJ9oS%N6h&cho6JEAapI%6Vm3L7J}@oL|HqV>!PUzNNHh_r-RFd^bvaJ@NAhxS(*KfAbd~g%!ONH}mU){|Bf$$MUZEh4Pjvl&>~$X5}4~LV1*9sWT~0 z@^UQaq`o$O+tg@&3;1o}SBn3;-Qg!?i%ew7fgESbiHw1iC*{cfQf|^Ol9%gAJ(8Dq zPWnmma-8&otjxSTlbM$`NnYws+9UbQ`ZMpB`y?;rChe2F9LqUrgXE>$%<|+o zd4IVs?L78*IhQ;ysr<=va=*0a*zz*pU&>DUPwtoF%=+XwGha}8fo+|%Jt_ZqdAXLn zpIkp)K52h)J;^8Uo0KnkIhH?ZNAiBhwmQ2T_>i?h4%UC7jCH4PL<`Y>>>i;|D<=vCd68GaPvn=#uiz`0c{xt-7r9@sn&i6FCq9k%E%LnN1s_T5 zAvrI{nR&8*2zKL1CJFr&{vT5AxjwsaM)7bx40nDsg0~Pue4C@_mRiIF@?D!qg#^ z@;el!Z41+;g{kzX)YHB&mHQXq+CNGk6y_@(rV)Stw)<-6ZfzkIh{ z>g`>ao=Ym_4KGYDDLii#=A~V7UA~hp?|Wups*p;3^8Ij0rGKSv86T;~<0tKqev-V# zPwMSen96%ez7;J#~wROY9oGEd~1lq2a`{G^@>3sZT2sjp*UzDZ$TKdE2j zKx9wOOZoEtQg8D9GC$RF^~$`GRL)5% zeJ$;fIWP6d{gP%Ert)1FDPQ_YQkgeW?zx3|8Ar(*{G?2!Fl|68<;!_Vr5s6e@R~2Bjq6^qJkYhO~d1<4JQ)XVy$vY+2N4q{s&t=+`9AA&vt$O z#h1Ik`g-5~9}XNm^yA^5ey&K9i)LjN%PJ{NE>d(9zhV`$iq}?4RBCoX$=<_Gs-sC^QK_g3jM{M|BD>l!=H*e9)y8~x|ne8YdM(SNl0k0z&5>zW@me#*bb z@2K+yr;m~anUgZCnX)0rM?I&;561E`a%O=9B>yhz)G9t~oNm@NZ_Ln~o&yK>AJVjG zD)W4w-u-&^&dnXtx9Nzye#g5ue0c9MJqPEE>Y1A}`0~5~g|{75Mu(AkLr3Oy${U{3 zdk{q&b*=5-qb?nFty50UmA(7q=EV0LQ%GhTll%Tv!_jpl*Z)&p=j9Cgrl*Mh$L7m6^SA-pJg%fgR6pEnR$6J%#rk`}#-SGjPa=p1es;($LI42y%N5 z>eH`xPpiM(w~yJUzv1-n@AS5N%TYhW$x%&1Q`G)$bc}o???>5x>IF0FOxNw%cF2f6 zP1_VUDDzs!!>&wZa+=6k8Mx#oTm5Fbi>g5D2Cma z$8Fp0pVLQIO(#cjbCll4K9{^l!CU;-qnz2+{e z*6o^9a*T`|zn(wQQ~$rz^Cw2~zo;j(&y#nFkG`j1-VXe8qIuL@N#p^!{!8=y zFO1$%^>rECcgUcj!*fQA$mz#~@02Lgqu=Lva`Go;>|g5Ff%^Hph%1nf)kEE z`o)UGHoS72^QCdS1fS_up=SL5uOIy!7)pBdpxo@Ma)ysUuZH#2#!CI{9M+0{0|#Fo z*6-4}RU@Z<_K3XRgZuT)9Wpp4tUo4aME!JhLYbg9OUa-b5jy%CtW zgL;o>G-zPo;X_6Y>7Un#RmbZ+Vo>9&)cVZEkTo` z+7vYTGUYmDt}M(!|ojN3Bk8_bSU*#*yedY*ob{*dv6@rzx|Y3y5m_n=pBLvU-bKlnK)8lD=S z9@^n~;h?ZwbaJ#QE#QyTw_jPOo@|sd%b69-%H}e2jrpi`rhUJCiZjvq#>sb2^SqSvA;(qE)gO;b{3>O(EkFVer%w^}bad!571C~t;$p8$a!3vr~NO5g-dgRa44 zL8@25IiI&`s2N%x;|e1+v;d1Ko<1S{Zu-NtNV?!WSDDwDADD01j|5Kzsi_6n&L`2A zQ7WH3MqKY`cecCRJ?vg~KYM_kYY(;a?9ui$_IP`uJ;|P8PqnApGwnHczCGVwU@x>6 z*-Px@_DXw|y~bW=ueUeYo9!+3HhYJ?%ieA8vG>|1I_;dQL9L)`R6KolI<=_a|CPO2 zy-R&rJ*b{RdoR`cYWHXlY8$oUx~aF+2k9g97xfLsmqr)!3A3Wr*}k5-Z?`|S&vj-w zFFKo?Jx){aMsJUIfuHYx?zaoB3sb8K=4Vl5g7T7blG;kWLY=8@Q}?SCwQ5=|ZKn3H zHdXhG_2xk9Jo{36g>5@if_H*3VTtJSXiRh*h}q$NN6V~ z+uQGzL{6{rANLpg&-pCm2 zkyIYZh03kU5^cG*Qd_0fL<0=b^Yw-LbNUv2qfyW7XHGF6GhZ@ym}gtVtQFQKYo~SC zI>T;g>-Ic%x%;BK(cR{L;qGxuFhZw!XER2j*UG!XTkWk3iiG!t?}ho%f@o*-OnOT? z)v-vbA9Y@;_0z7@hHGQA>$PRn`;K;tv7Fgg)jY?{GwWH6=nda$PLK4puC!jaezRV3 zes{k24tXQ|UE%I71S0Z_$P`aCbz8b^+<(oW zUT!~kfSc$&Ry?r za5uYK=&K#>E_XNmwbwo19(IqoDKE<_<(2a)c$K~C%*|}CuGhe8=qdE1;{{$*ucg<< zYwvaRI(yx{9$qi6pEtnE^&aty1(nfqje@s=&x1X|55W!Lv~X6KAO0NfjOwHJ3i_dx zT0yIo{D3l0R!qWjXRRYl^s%rxaOrL5JkOd~IZz zm!q|p*_)jW?w9T%cfWVCZ}@ibd{{Y3?I;r4HnWws>gDQSb%54P?`vLR4l_ra*PD~f zJI$Hq1LgwrX>++*F!Od;yR6-oX`kyp>b>T@?Y-w64lhZk_7;g_)hDwKnc8_;QG2R0 z!oAO3=D*`t3Y&*o)F)ai`U{j^R8bxELbW+^cTk^dE;fr>wXFtL6YDwaQTsyo2HxsH zFUNn#Zyekd%m|(j)`a~BUHYaOx5+Ewf`?6Yi> zRdyz8>2muW`vX?FQ=NuRD`%iH*16fa-MPz|>pbW@=B!}Oo#0k;>$y$brtW#X!F9;` zeeT2VTBP}X_cQk!_n`ZWTf{4m+w=I`^*!k%azvJs&hu8;1F@}tGkifC2zMzkGkVo!7^Dw945OB(sJ2h&fZ8(v2PeVzUxeHa~GG_{<5E~->jYAE#yxSXS$uUw?`Q7%`8Dc38v zD7Py!m1mWe%3I1d=PifC9dS)HtltZS{On9CcGfqhm5*6T(>_XK%NQI87V_3#zj-z!~g}a_)0pc8a;B-A-c#v1gYcPit2gMS-i{Fwiyzro+`mkO!}qk?OLN8+(98kP(jg>Kj@ z93DOxz8&ree+cVF=SH2QLDBSRZuAu6`DRoueR8^CT4lu=n!YYQmyvrT{a$)cyk-?m z)n(kuFlLRJAN`bE)vQ^om>{otQDyh|(C5;)SVd@yhW~I7b-KZW`e^tveBFnW` zw9VQJ7cRak|mM=)}4(&X|Z+eBG#Rx@OuOVooscGD}&ttgEfb*7Mez z*5~NLV)hAkB|F=0VGp#gwW~W#oj%U3PCgdm2hOM1i2Ix)Xvop-T=yZjf;Ysw%Dc&% zjHPuyJyg`M>eu%h`l{dFALw7_Pw*%C55~Q;%ir(+=$8#z1>J)?f?a`!>|Y%A3Ev4f zhr7b8sB%;@Iy-WsW>H(#x<1hr(bduH=&|UTXf-zc#%N1aoxbXyemnhD`e)YIqNzQi z@|3~K%}DX<^v|ctRP|o$(q>5CO02L=S_xgzBYn7jgZ`kt9NTxeaij5(vEL|a)-WTp zquJ9OXRa_mH@~M3s#}_MnKjfJXU%8z7acMVo9``qll`&%o&6K`_DNVNfz#3H<>WXc zocpmEPqwTl|}G;i7N_GkSoL=PYtZ$}?RpGF6xlhSUwcX|n)%a7?)ucE0o$U|wR zJQ`C~0;R1oQn^XFN13NQgB|=1^R}vbr8-)@PQ6*ZO??Rcy-EF8{ZY-)24QwT{H?vAE)7R?T^j-S5`mcH^qmiK*HYoc@<7(q^<5gC-@_03~&4;j! z-Y_?td(3_2Av249YHr&uc5%C`T@jgS7|*))_J#Ik_C5Ba_Sg1) zyR_pumpOUPOlOtT-n+)T9a(wH+u_yq$NH1~2Ux{6`(OJNSmnmqKKAna>CX%1)zG4;HHb`>Qb%dP%+i(4c&h`H;mRcXat;>3N6Jp@*dt02 zJd}p4Lc`Rn)QRfdtcZ`POVk(fH#Xw?e4*}De^#@!6Sb4^S{iCiwU$~Nt-aP!>#TLx zdT70{`vz#a+E6V|8?9ZVjn^h>le8(?`{==XXub>4bdS>e+w?>FZ~7Z%u6470uYHCy zn)&sK)5EQdg}KK2$-B_M$$!*e>X*g~J~#C7R=&aCESg#w%l!$;$;#PEYvoe3!_~^{ zSdV|E>{SA_h1y>ogl3pXyPsBftCeVHBmBXpT5GL~c9k|&>uTf}la2e0mgafpJ7yKD zmDL6P`98LXW4E-=MLYJVH7_}9owuCL&UWW#XSdr5yKICvkz9N}!b4HnbiK5aJ~w?w`jF_gsYO$h;{Go~-{&eLlze5a z@~%=7UvR2AM}10tO&zG!(mNP)zys=;hPl)H!aRWA(7?)JPWEFxf5d(XYh%0pg`MS` z?zChk4tAzH&p7WoU!j#wbpveBW_Yl_dXxM){!f0H;G>{k?+i27G)`|8hc=SW;H|;B(yWPiQtKl2B2{Jz4dko8wrUX*^38O};gFtccC3W>=$>S`LfyIozNKA}FVZdQL#D{H0}X*t@> z+C$n4+6L`=t%5#Vf5|LiSGW7ytL-CpIp<{OHfI`Idb6_&4c*G^iq~=qcFG{Htbek9 zq2D*QN}k4>+wMm}2T+!4gW17?U?2WVAc1I4k}JqUs>;6ww1;lVY*cyNGwgGYnK z!Lnd=@Gjoz_F#8VEYw0LjKVg|h~D9qpb)o(bHaJy!f+{?{|(l@FT)?hV$lgvwWv1h zpT-K<6btZtEWjSvfLBDr@Z`ruH-S-1kM51;MUO^{qGi#G(W}w>c!NJjb<$_0!*siJ z4|Lwd^eyQb>HDz&KTdy|{!S!o1Nwrotf`!-q?PvA*$b5oN^P|@IL<_nqBmG4zD1iA z*D7cYG?lfpGxpr&=!n(Y+Sqpc4K$+ycH3!see8*I_5S)qeTsf32*+CeE&W6NGi>t1 zdJ&@>^Q8qNe2a0XG1qv+SZw@Yq|B4d>SjH&o0((Y$QVD3&9=$>+DuuctxAk=ef$zH z_JA+6E@qAo!VZ~$C9=p`g%AF*^_lgRbw@AE^(iCKXJ?Ag;vJ{Jqr)M zv)A7P7xu0PCwj7%~Rq5N)52F+IiG>5!mFW5sN^Nw#iKle8vQ_PlM>ZWB z=Si%b;#hWD@Ny5CznG=1n)K!cR#&T^HOji4ew<<55B~I&^(-^!^|(jBw0^W6#wS{A zzd^6|uh`zh{~0rxm7#ymREXMMap z@R-`nfgrGu?f&72@cQs}(6yPMbx*}uTG7;QUSWl@T4|!5s}4{nu!h#s+ZjiU;%0fQ z_%lt%Y-M&f`hgZ^X}cPcw|@$+0K?X-6;bb33NJA<%29&=s+SK8`)0XqDX zQx$J-FxJ{EeAU(Nhi*BfV6^u#>so0>cBsDq9VxzBm7r$OE|?tbz*=h&b`ESEgkRkYkjM9tKGko9)i}q0(XUER=i;y56Z{%< zMVc0dhr(7-_h=|K&->tk#RRHOouz2X0{rGm+S!`IdeKL#iiV9q-yUWT6|?WK@3z0O z4`7d#cWb+c@LDbih9IXu7nb=>cs5eGG+GyxPdCA{?9DrFlXuK67Gv0!(nh%hWdBno zOYO>tKBc~cB~(P~ijDKWwp(ig#(aZ5AFHMm{#t)y4VHFSy!2;TJ5RDA>uzfSDB~t; zhxMKHJGfL`yES&=4Pek4-S^VpKE^#)q z_AxZH5q4uduLy4lZw_ZLrj*gKSd6oz)SJCp===d7jdy{BKk2{Zukkned;MR~{e7cU zuVOK0HV1F&3F~Dm0HJ@&{>Xk56!#mfkT&l3?s?vH^vO~zk;(p>G9QK(JaZfC;$qOi z1&l~fJd6cSBYe(FnQd2rc20C}2Va|w|4>ERGrm}Cr`%&TvHKt|qwVYLTkX4;y)W6H z*=3zNP6II00A1GsJ7~0XFaF3@R{w9DUz{>-1=hMVT+eL|rg4><<$d5)@tc56wf6J; ztFhZ=Vp~3mHL%Wq-{0kbg>RM$O0cqJ2W_#wCt(|`4}K3Og)3R5Hie&pMy6SfQd0~1 zsH##=S*WM*7j8FhvSy-V4l^zn**Af>)RK5gez6z>6?^)SQVQ$fYJ8I2;7Ucc6ByrC zS|{w}D?#}m!RlHKPH<2ws+ZSK!8*P_MrPOOOO16PPH&o@BEQdCCo`+haeH9Lj7o1! z@0KxNRM3|8jQLASe^9mCOa<+i!zxlWwgGB56QevZzhW`h+yc}17O$v?=4$Ko#`dr7 zQtuTnh}ZYtc&W?%SN)Ct$LR3dLF2&3Qyoqm>YiXeF`f5W%kMygr#2LeW1RKS#;w%u zc;2Rck(2ABb`*=_Qa9m?-eIi83M=a=fdTdt5KU?c{?k6_7<9&~>4D|dFBrgl9x7nn z-h%SJHqu@Nkk0D(hfW+%$cph@!F5aNwn?(Pn8m%3F!X&>`;2C1f5@!atBUd*evnOVE_gJ5xOjJkG*pbaZpNAL~g zqhnUw*FPu$o{*)t(SOt{8g-0j#(l;@;!eZywkukK>Tf{r9(I3sOL-@IZM{z3SnRGj zV3Y5ApL_j-(b5OKvLxIFPS`}L3M%!YdL`cM2l~UH=ogrmTQ55^7_s&K7XMSfcuVH#_!PdGRn9X=i|4qs&Ue`f;yQO|DPoPCh?Z?}zH?f;zl9fp+)R;(48BcPjGsEn z&FXXNiA1p;Fcujlv3zc|b6v&Tw@%Z6TJk1H|KKd_OBH6_txBfPz$yY7n2Q z8#Ra;MhbB%Ckn6#TN2~=qmT2mVy^xvSOuEmD&4FW=`Q%YW8yiH75i8NRTs^_9nW$G zG12w>rGvE5iOhk~=h z0AIU6SB?s=32$PRpC2v**ZLs*7~gvj5sIv+BG&7OXd!6L1;j<^k5yR`dPyw+*IgN- zGoLGc)qU!v#HtqIVeQht*E@nUlqP;#)vRMSHa)Y2*&b|s6o|uf#A5n@=blac<#IIN zC^X-VL`m<$(tjYf^`FPl0|Ekity%Dqk35GKBFYKZBC3_jf?KUUZ0P({v5XY+t_%YVXYsI zN`c+hOgBnv>E?`CPK@2&fyF)_tmp0Y_Vi~3$Sv{GEOGTyrIZtula$jz0o#LB3<9ed zuiSNV;u>YYSw?^oYe zx2nIW<+PKCk~Gph@PLcJD)O`&(Zly^3$E(DHZ-PO8mfoLE?Z}caCRo`?V2<_h z9Y-U1layw7j+YS2dQ3I&6$Sn8tBusgf^ppl&NvIU!K2zzq-Z@7bc)_cZ=sLYr|Dgc z;duS`8?PA~u>XsJJ&z$GT;I~I&}w0Ivj&2@jwP@9 z#!L|Uc|?bof+4PjsqnG0+bQDKa2qi`qurlbM@kc)Ihoa}F_FZ6#EY-ShhM?^z7?eL zEAJO9`%3;_~g(V5KebMV$aigra`R;6!?c%f3GUb@or@1QK7A`l(_FBo#p#tq zyf&nNA%>R~`{5@lm6ck`8HKpYU}Y@5dXq9mxl4IiS+1-C=YI=7;tOKwKQNn%s+H7g z>X~Ywo};!?FH`f>Td^PS$MRmHu4UE!8jX5LEw5G4PJxTjM6<#8+G^)x`H$A_W=21u zJ*%w)FZx*9qwT|wFRNE&PS?eD2#BT41OHu3r1U-g7rh*KR}Dz!&5gFk`9^0@;9SOR z9Nzpw=I~2I47M8w!Q^aKw9Cx?cx-nwTdP@3t#hr;*nbb@*g+H(zuYETb{t-Nm z(sotwnnQLerv^CPI7V&@k^Q|+L-cV3Ph*gKbL{E-1LoPJ<|iya8 z_c9+|MI-Nw(YfNO%IM-EjNRFa0p@xc5wxq7J3(Ea00;XR)U~8qK|LMZt_=uSfAFuV zc!3MSi{DjusTxt#^U<=`f~suRKGZ%zzy1b-rx5`gj#j-L9>N;16p45Js+TY-8YhE1 zHZ&xbe=#F52pxMXQJb~K2Y6JcgPEOUUVyLsG?>{-=DXl#yJBpCcJ&?02%<6WprqnZ!JN_k6dT+shpRL*PdDQFj?UfLB3aH)7j~ zZv5RXNxZ)+as27T&8qr(yyCXOx9aB)CQdpL59?2;RZ2FwCkTMn-F7BQ7C(Sb#x z(pXcqS)Ut%tfj%#&Wkz`UFwfE%!?+lM&C<>X=(H_a_~v?ee?^Ga0+;ump+Ht+&O(0 zdU1Jr6_W67`h)b2^q0gDen|f$_DzN2sRqbI7BQKsh4BPKX{xj$!g>iYg^@6GX2Y#{ zR{5TIf}#4vWnKVhs{m`NrdEg5H_%$3J-cX^5Ir5FjesR`6Y{YfU+8tDWT1W>INMBp zF44O!uxUPHjuyeIzLHt_n(?-A25aej7#=U+Tfbp`Oa!YunzSvE&_3{MW>~K>>hCcZ zzXG8?VimPZG4iJnpQ(pM)xtjCzJyhCfIZB<${rhg;J0C0%_82l7JKRoaH0M9mkyrg zxlT8yF9^zY@T=}Y1HXo6vo*$2%iv$0M&zqG{_Dlaz?JTBBIlE^ux7DFKJC8leg*sE zAlPbI@1$5S8=mW>(apoL_3!ZJV(UK%-nQD?=xy;n_CEE#1#kNqDXEE%uKO;S^*B)1 zss6qGJUrDUc;V}?)wcSd#Qy4c*seeMzauLrpd;#m#=1c|I2Zk$!-_cyJoc7gR*)Y& zgiX5?oAz~BY3~I)@dLhP1uY5YT{~>Y8rmbwff+U#P4PJR_cEksGv4l3;lZ#B>!%g9 z!0zq^`g$+c+`?#O^fCJX8zOW?(xuTFP0|jQTn8c?bJGtI!+jo9=si%APw`N{6BIAI zcq%|nQc5}EHT9GnEVz}*%gQ>UxjU4vkd8X>iuyFV;vIDdjECY_XXCUgu(>+xx9WF* z^FOSA2iv3=2x}$7$CGM}6yzB9 z#P1fvkX&oNjmF+;?lupCtQD~YTRWM^Z$rx^{?p0oVNJ2_C8GBvdVGbo8pM5Ltjz_1 zJpuxIqFq_MB5+s@{JlNCet*#S$wbx{fWW;6_FCCF#i<7((G(qW2^wS!QZv!H!wmDd3cNWBpRH#!7#`k@aJLr1<9LVI?l&-D zaQ0bkTBX|)lNytrgXBDxehTYrZF+rrBk}F;iI-tBD8*BAu)&IeyA8+wnvKW)2>AVC zSTYrfy3|w8S9_|t#C@l$bBPwM0M8c-e;l^h9kDI;f!3I{KGH|(Z|d*rrx{J~xW*e# zvZB98eD@7wGpqVn#!vXERm@u8griy4Z;G+l$B>!b=6A4%PPAIWQ0r*rfhgYuru?w= zIIGIb)@w1Aw}sXIyO=Xj$}W$DoCZGI014?#{C6CPFF4 zuj>%SoPh1N7zWKQ*cpf6XJn~mh=uhg8b1+x?Pn0La#}_0bmA*M_E`t58=R{5w2!oJ zwV$*iU|y!~$6T1+`Z#Rm=k?9#`$KwJqn1(M=s=`4*BEA8Z`?%W>^`H8*#r;DHCvjU z%)aIzxYbv~;aHB(bdab@dFJz3#8fO8mcLqU!9Fho`5A_9^eQuSD^W4Q`>TNmG{hH5 zv)Z>KLUt+RF$hM(4XpV2&U~!wg+$DjILn=tSleruvs)RT-<`^C9rS(R_C(LmgZ;P6 zeF4tj7W|+CV5=uEQq}Q-6vnCr?5M6@UvD6Bf~&!gUPQxhXP$nIe$VnxB%ab3OT4Au zfw?&z8(=yX`4h}h@q^y+-vfIWWFi%m2`Yi=WD{9#5||)qEkVy_qSF__TU!-uiWz}2 zM~gE*tH2CsNGzfwnC{SU447_y_#DX2hVUb>mT$w~!;&B@m7~)b>9gQd2E^F95@YKF z2l&zGNf=g}umyLc!CSC#6qKH$cDVq_0em2J4xGB;3zzeF{zgK1?>E+8v9h zY82Xr7W}F{_~;{)F|7W#F<&21mJlmlr@RMd{ynl$L@fvNxh@g<(duG2RjhUdxbY0D$8T^LE1K1q z|7T%Ub_1XL1s1GrrLA*dRb2@Ra}}Q1^>}8ph$bzxmNN4{fhY70JS(v*BqG}hd*X8J zhsW&~W54@r`%e6|hn&aZ5WI`!xXsxKJMbVfRNSqE*LDhWB0T3daI|}QIq+zQde?cA z;1=8qYJR{g=hp(Q)QQCiR(%6L!M*-dSc&UmJ8>ue!9J|SQo%{V$-(Jpb2nz#U5w{8 z2|fM--oSdK!B6b5{8edJ+^$u)Bkqn9HFHNsW zzau=yUd4r`%i3Qa&*4<8#53XG+4v6~l%DV(u2QZcp7MaQ059Sh;$&~ah1gCE=>SZ; zlv)A~%BkuZpgB!c2Tk9Zh|6fAXm`QtScLz#9NyO|bq%s}0&F}_y9G&Ep?$7>r)8s0 zTEdp>2WB&p-4&nedx*%i#$ve3m<5Y&HMsg)#wKGYe7b#%e<@SNYP^e8{|)Qb7(IE3 zD0&H}3R1t^|!7=nqNkeb@byJ=Uev@JeA?zwcZ5paqk&0 zoAr1t+d*u;_Vy76E{*1@hIP>p^v3mD_*W7Ez78MecHZC_yqL8h3fp*tAN<3-!-=tU z3aX$5HoB`7Jb}^ptapMe<_AykR%?PcSetg>$NV0Y4Nt?mP(u$H?GDP=HyntJj>R&) z4NZ1GXyaGJ{Ia4-Q5|$wr>Hj)nit&)qBApk5XAr8=tDf1pQ8%tD(I}!S-JFdQ|!_% zU_7JHTT{V!UPdZ6vuEYg*pG=Vj8tlTfqhzBDT9<&S85`qP4ID}m{&BFc=H2jv3HaY z6yX+Ssb%3F)>iAo_|TEcc5p;{!fhT4k6Or_?`|)~Ysoae(U@|Ot}R1Y)v9=7sDJM4bS=|JfKaijyv&!4#6=g ziUoTbdaofY6AwSA19og5_`|bcmF|VFBn-hzU{&S96dLPa@85!4Jp!{}D-tEE;m>~2 zpfvHh>cphah9}pYh|-0uhXdg8Odv+}C@9E_vArYf;{G6u{Ua5^>S3+$jPR^bVHZ^d zYS;V~_PE9SaPv@b*R>9<2&pwb(l&_JK>S{LpIhVM9M>s(};1Lf2yPBX*j&YIs zXs?y{wQAiepHXBC1LN^1j90jowQ-~%SCP`v%hEoJclJP9bN-d{7~DD)wCZb zaT&cL@>3s#QP*38pv=)90+)Uj6lD{flwGWRm00z%jk7^f`WmCasBZwBo?$$IL@i|9 zTTXO(y`h^O%(+O;&)B*3t;XPyKDKUmG{ab!jmu*e%62^HlkE`ZNdfENF8g;_24!J` z)`4LZ!JL>3J~`WY0(yx>N+uQJUF(Eb`@g8)fo9cSVY6%(B0wXqYJ+S^D2ie zbUK*i18@$W@Snwo-RSS|5Bg`LHN4A`a#9$U~9-v=k+qrQPnvxV5pmta~4 z(FtXu=GZcw(FL7}*$)GKoCU|Nc*?*o*`=IElrje%;L^CyH>mH!;r?9x4p!MuSR5z7 z@~^9%#hmr&^DDJca24-luFiqO{RCXImt(~08|?>dj^Bw1lpzvX6ArgQTp(hVY0oNi z1t``iBLDZ|sV;$Ky9PvYD~QE+`T=$%mB4R33uMtUBG#bx@%$cYT!jU4Js#`~<6hWc zPZ}>6uYfVW1H$#OvD?_oY)_eGV!Ncf*_%BRW8o>!0r7Z-U3NS0O!i@=l)=_j(dB*M ziCu$d@`SY#1oAzi1j1mhVK=o~*%#Q|;ECMCoPLlwy#zfkeBLkZU)jr5+7V7~P2xs2 zKI{3+?i@HndCqvS4jI#X;#pqY&1P0NVV!H?wu3j;op?Yl`xqy}kGT^c^?r5=JOQ(4 z1>WjA*uuO1^!{RdmcIX&8zI!_RqxLX&$qS9%UUY5;O$)x`B0K z9jHYGtlLwV$?b{6$?9-Rcn7P(z2REsu2?R`z`4ptRiauT)aSx2>c;wTGc)$CXcmaY zzigPVqy5qE>;o$sBiGH4mh00GfLQE{QO?w&;zA`!6;sM$ubjee&L)b7P1_Mft3Oul zco=|pD6@zfKUEmh+k#yyai`+o)Tgp8oUK|!`rE7BnDK*%_}|QY7xwJqNZ)E=I9erLs~g4{JB z>KzeP?xbG^i#ZRE=~i|Q%-5gLpV41{x48-5=_};!cM$E9i90ud(;O0|?i8;odC1)D z#y#=6vKX0L$J!zu@F8Ln<;+UNsp^{=_-cEzi+Ks0wV}w}P3+T|V?JUoVV}txu-86D z`hI|=SlX&wh@LdJ+OXDKY7HQUaRYLACpgN(=#Lk{;5J)Z+0*mA^)uYX%2>*$voFB` zf$NAi>CfJTtB}qqSk4dIPl2Mmg!TL$J5|2758JtBC=jsypPb2WGZ$UH7g17njlpftdVy zSQR_j)AdtOBKF^Eu}+!nXX+5k_yFQs*CFZCv3?%IMqdMpzahqTzr#-dHAd&E5-D#4 zMi)e_koq3%I314NK8f90^Px~RnMed+F4oZ# z$}$kWx0Ef|NZ+x)wFI2l8tkKKsM>0CcDQyY4m%hdX%bP`d(;Pr3oOHKe;1@?2N4|E zX>|heo71&3H67MgTliG6`i(4{3-e&_Kc~IOT-c~>(RRe^pIEmi;QgI}_h&I5TIm<) zJ(v$8^{dgtw-TkzXGT1SE?x^)L)OE6v5i#*E30NaCjz6D(b2dROKUK?_&VY|(_w8c zfVH_2J^UU!tUiVRe=ydKg1k)4vz0zAQ@i}^Zx-fqXd!N)10$n9i9fw=t69F zFj&U5SZTL|FFj23Vi{iOYuIWZ6MH%YH%gGlsxaWr26s$@Hg#pTTn;y26js}9?me)t z9(SK*#=MRF_7S^)zGDY!G4Ku94b(Wc-CCo=FJ*t?NO+?+#rqiwqP(x7%{LNp{5-bk z#9ycibJPauXzzFSFUOm`27lomf4;vEJo`0bzT3dEeNp_dK z#tN|+#>toLF8e(!3&W&(bb1^UZiR){4Scd-&fLll=zH-b9w!>In%zn7VeNgzZnL84 zlIim4YV0>_#Jmx&w+m6u!OWYn=?TP+XTeupoL-iG2^P#oSjS(omc+iT^O2ex<4KGn6BH9)d?qajvZLTDZ@5!*9(eVz~6dbd-Q>Lf6|-I z`|ujRa)ilnF1zC|!*&^oWN&7V?oKRIiOtmX>Uj0>)^*tLE#YEaadIYee2^Irg$c^8}I8+?@NpzCKN#a9Q{6MvbDKe7RD z)baVPneAcIs zs|~^p-BCO>1z*219;&AFQl=^QA~!#QwwAyrt%&u}13z?p%yhY%y(AB_mqg^FCi`91 z;yHY*`Rp=$oY7nZ4n7PV{BGkxu#gSLhp~5g*eGkBjE+mgP3aA;I@Y|sP`kZvZZkh) z&EL!3r)sSDqSwrrV=aE=Rn|Skz8|+1vy-?q`wiQGxprpP;ron^*qCLU@}R8>%%sa; z`pT%h%|3*K?5GhA^4YPU(An+FUh7frIQCPoU?24xjLn{Sjjrz1V#jG4_K;lxl6oDU z!(6<@Rd6{4`>sH|yb*g#TEJ-NM4aPtJjV$zR%bCP3&6{k;7zhrr$}3+E8}v7GL&5+4-)xY3YXzs_EQ~FzA&wrm3|rA z{=4zN*IDmirSC(sPqphK*&h9NBfOnAh&hfxcITm^@1ZX$V4HODHn68KKjvsv1m9}| z|7=F6^F4?!qkGurN^AHlk(w|6(w>IIUWHRJ3EbiXWgimKmDP6?zUMYP%|jqV7Q40X z(blrYU4cb66EyQ{W?5BQ(w;pf*JFzvvWpV=Z0$VYJ`&?utwDsU`VG+BWk8{a6IGl` zbZ94W#Cq)Q*c>)tpT-?%%&nlt#raNx=*O%0M#4-Y24YjJ7c8(siFglRMS9G|q8`Ui zj9K*2Iz@OKzZ3OqgWcNNHT?MLfJ8`)xZUcOsR(uPf8=lSp*2O&cT2{u%csh@;e`0MMllz{i+|TR_kiBXR zL2`$AV_-Yo4TJL$tjFiPH`(*}0kOHyupfV91k3pq**)Qa=stm_u&@V5q9ew|@!7?} z3iQE;XoM0V^i^YS##pSj6Vff<(~M=6nN56b1u=N`zh#$5)rc`w`QA(|tg@Sx=`jy( z8~diVvj9TC!7`L@g5d?R2UandL8K%a-3ww5otY~*_`+u<(mx91Tb8HhD~GgiUd zAU(oBJU1wh&TJQ>HS=L~)j~&(V~w6mbn0z%=5~~O&WEeKpWcDNM zbB6i*!WMXtd!tIQ6$inANHr}He@mkrtN2|?Emr1h*?qiKy%x)KKWwjd-~iL;*-!N< z?3x=6V`VWmJtkYjPqeGt^^_4 zU~DsXfkqr5Mp6OqurBd^4jZEOYsabPX;~f_<7#%z1gVCfdOMqTMjoQWZ+YZ5x2k zwO9Dn*`;Dm_y5bqyax8bL=e^~u=J*zsivjmGe)W7eW9a((O$r2&%|qdhvY;8aA|4Y707HrMZePp6td8*^3`i&Z+<( zsxJJ7mN3-1E%D2{^9_MqXDGe7E|y$ zrsH|c0aadtzrGINV^<+3qB4GmQpjWPft@ir{w~o}I5i8{&$upH53A+?>t`vxQB;>0 zTSN8@r^c6xIg>{W*(urv%S?3hB=+JiVwc#qLVxoJd-n@`&8FZm9pSND!#=A8XzP{i z(A~x8RzOqN#iwk~c#2P%3(7w;9??a78)OyV);hq5X2o`Njd=H%!hOR**ybacL9^AKyd>LmtU&Wcv_i#3V`tAS&Jm6Mlk6}|d3%QKh zOi-0I#FMsQNvBv1C599f`h`6hqe+a+98eVDFzm%%O9iDEmjZvVJt(mFf>W49OPD{x z%s(8|U|tBPAt?0zdN3Dq8I5Zgi>dVgN=Bf-_uCcofscR`OZ>YAI}6&tRPO;VWg_1l zSOP-0hW_7-me|D?Mh-+rqAW(CGGBYD%QzT(XQU-emCo!i?ZSCE0*oiISv3FK_#NV{YBmOxN z?(1~+qAVbKusP;X>>>Vngh*34wK6D5T~HJQ{%cECo6gwy{ouRg!DyeTPJ#6@2VZbu z98FjQy0{q|Zk+^K^dq>3dx!(`pVG2^XJeI-~zC#W0yzWR|9_))bF(R=XUtt&epaRjQAdW0eLWlo*iR;C@ zpMoE;90Xdv;8B4Y?!Yzg$G*g=#3g0@Sz(}_YXL{`=yC)qsTWG8$!c#%RJqA78Rj(T^PH~-QU zQ?cFhvD+45k*>lT-GIF&Hs{{h>MUiXb`;2>Xo0_E2K&q{dVA zpO^W6C*PB>7G`4UEx=w_&I+{->+WB&w3i)XDc-KaQG3~_cxah;uV6l7xEY;a9ZlbZ z(aL9>w$T2L=;?ggdO%Z%Gfu?9Kdje4`{u(~$;C2V&px4m-Qlt$n9~0F`(NmR{||mY BxPAZt literal 0 HcmV?d00001 diff --git a/contrib/preflate/LICENSE b/contrib/preflate/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/contrib/preflate/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/contrib/preflate/Makefile b/contrib/preflate/Makefile new file mode 100644 index 0000000..c024264 --- /dev/null +++ b/contrib/preflate/Makefile @@ -0,0 +1,63 @@ +CC = g++ +COPT = -x c -std=c99 -O3 -funroll-loops -ffast-math -fomit-frame-pointer -DZ_SOLO -DNO_GZIP +CCOPT = -std=c++11 -O3 -Wall -Wno-misleading-indentation -pedantic -funroll-loops -ffast-math -fomit-frame-pointer +DEMONAME = preflate_demo.exe +OBJDIR = objs +BINDIR = bin + +PREFLATE_LIB_FILEROOTS = block_decoder block_reencoder block_trees complevel_estimator \ + constants decoder hash_chain info parameter_estimator parser_config \ + predictor_state reencoder statistical_codec statistical_model \ + token_predictor token tree_predictor +SUPPORT_LIB_FILEROOTS = arithmetic_coder array_helper bit_helper bitstream const_division \ + filestream huffman_decoder huffman_encoder huffman_helper \ + memstream outputcachestream support_tests task_pool +PACKARI_FILEROOTS = aricoder bitops +PREFLATE_DEMO_FILEROOTS = main preflate_checker preflate_dumper preflate_unpack +ZLIB_FILEROOTS = adler32 inffast inflate inftrees trees zutil +DEMO_FILEROOTS = main checker dumper unpack + +PREFLATE_LIB_SRC_FILES = $(addprefix preflate_, $(addsuffix .cpp, $(PREFLATE_LIB_FILEROOTS))) +PREFLATE_LIB_OBJ_FILES = $(addprefix $(OBJDIR)/preflate_, $(addsuffix .o, $(PREFLATE_LIB_FILEROOTS))) +SUPPORT_LIB_SRC_FILES = $(addprefix support/, $(addsuffix .cpp, $(SUPPORT_LIB_FILEROOTS))) +SUPPORT_LIB_OBJ_FILES = $(addprefix $(OBJDIR)/prefsup_, $(addsuffix .o, $(SUPPORT_LIB_FILEROOTS))) +PACKARI_SRC_FILES = $(addprefix packARI/, $(addsuffix .cpp, $(PACKARI_FILEROOTS))) +PACKARI_OBJ_FILES = $(addprefix $(OBJDIR)/packari_, $(addsuffix .o, $(PACKARI_FILEROOTS))) +ZLIB_SRC_FILES = $(addprefix zlib1.2.11.dec/, $(addsuffix .cpp, $(ZLIB_FILEROOTS))) +ZLIB_OBJ_FILES = $(addprefix $(OBJDIR)/zlib_, $(addsuffix .o, $(ZLIB_FILEROOTS))) +DEMO_OBJ_FILES = $(addprefix $(OBJDIR)/prefdemo_, $(addsuffix .o, $(DEMO_FILEROOTS))) + +.PHONY: all +all: dirs bin/$(DEMONAME) + +.PHONY: clean +clean: + rm -f objs/*.o + +dirs: objs bin lib + +objs bin lib: + mkdir $@ + +lib/libpreflate.a: $(PREFLATE_LIB_OBJ_FILES) $(SUPPORT_LIB_OBJ_FILES) $(PACKARI_OBJ_FILES) + ar r $@ $? + +bin/$(DEMONAME): $(ZLIB_OBJ_FILES) $(DEMO_OBJ_FILES) lib/libpreflate.a + $(CC) $(CCOPT) -s -o $@ $? + +$(OBJDIR)/preflate_%.o : preflate_%.cpp + $(CC) $(CCOPT) -Werror -o $@ -c -Isupport -IpackARI $< +$(OBJDIR)/prefsup_%.o : support/%.cpp + $(CC) $(CCOPT) -Werror -o $@ -c -Isupport -IpackARI $< +$(OBJDIR)/packari_%.o : packARI/source/%.cpp + $(CC) $(CCOPT) -o $@ -c $< +$(OBJDIR)/zlib_%.o : zlib1.2.11.dec/%.c + $(CC) $(COPT) -o $@ -c -Izlib1.2.13.dec $< +$(OBJDIR)/prefdemo_main.o : main.cpp + $(CC) $(CCOPT) -Werror -o $@ -c -Isupport -IpackARI -Izlib1.2.13.dec $< +$(OBJDIR)/prefdemo_checker.o : preflate_checker.cpp + $(CC) $(CCOPT) -Werror -o $@ -c -Isupport $< +$(OBJDIR)/prefdemo_dumper.o : preflate_dumper.cpp + $(CC) $(CCOPT) -Werror -o $@ -c -Isupport -Izlib1.2.13.dec $< +$(OBJDIR)/prefdemo_unpack.o : preflate_unpack.cpp + $(CC) $(CCOPT) -Werror -o $@ -c -Isupport -Izlib1.2.13.dec $< diff --git a/contrib/preflate/README.md b/contrib/preflate/README.md new file mode 100644 index 0000000..3ffcca9 --- /dev/null +++ b/contrib/preflate/README.md @@ -0,0 +1,143 @@ +preflate v0.1.2 +=============== +Library to split deflate streams into uncompressed data and reconstruction information, +or reconstruct the original deflate stream from those two. + + +What's it all about? +-------------------- +Long term storage. There are a lot of documents, archives, etc that contain deflate stream. +Deflate is a very simple, but not very strong compression algorithm. For long term storage, +it makes sense to compress the uncompressed deflate stream with a stronger algorithm, like +lzma, rolz, bwt or others. + +Reconstructing the original deflate stream becomes important if the position or size +of the reconstructed deflate streams must not differ, e.g. if those streams are embedded +into executables, or unsupported archive files where the indices cannot be adapted correctly. + +There are currently at least two tools available which try to solve this problem: +- "precomp" is a tool which can do the bit-correct reconstruction very efficiently, + but only for deflate streams that were created by the zlib library. (It only needs + to store the three relevant zlib parameters to allow reconstruction.) + It bails out for anything created by 7zip, kzip, or similar tools. + Of course, "precomp" also handles JPG, PNG, ZIP, GIF, PDF, MP3, etc, which makes + a very nice tool, and it is open source. +- "reflate" can reconstruct any deflate stream (also 7zip, kzip, etc), but it is only + efficient for streams that were created by zlib, compression level 9. + All lower compression levels of zlib require increasing reconstruction info, the further + from level 9, the bigger the required reconstruction data. + "reflate" only handles deflate streams, and is not open source. As far as I know, + it is also part of PowerArchiver. + + +What about "difflate"? +---------------------- +The author of "precomp" has announced quite some time ago to work on "difflate", +which should basically be an open source alternative to "reflate". It is still in +development and not yet feature complete. Let's wait and see. + + +So, what is the point of "preflate"? +------------------------------------ +The goal of "preflate" is to get the best of both worlds: +- for deflate streams created by zlib at any compression level, we want to + be able to reconstruct it with only a few bytes of reconstruction information (like "precomp") +- for all other deflate streams, we want to be able to reconstruct them with + reconstruction information that is not much larger than "reflate" + +Right now, it has been tested on 11159 valid deflate streams, extracted with +"rawdet" from archives etc., and preflate was capable of inflating and reconstructing +all of them. + +There are still known (and also likely unknown) corner cases of valid deflate stream in +which preflate will fail. + + +So, is "preflate" already better than "precomp" and "reflate"? +-------------------------------------------------------------- +No. It isn't. + +Test coverage is still quite low, and testing it is currently quite cumbersome +(because it only works on raw deflate streams which need to be extracted first.) + +It's very slow. (50-500% slower than "precomp" or "reflate"). Especially for files +containing long runs of the same byte (e.g. \0 or spaces), it gets very, very slow. + +It will not handle all valid deflate streams. (E.g., preflate will fail if the reference +length 258 is encoded as 227+31.) I don't know if this is really a problem. All good +encoders would never encode a length of 227+31 anyway. + +The detection of the zlib compression parameters is not always on spot, which leads to +the creation of larger diffs than necessary. + +Right now, it is a proof of concept, that we can do better than both "precomp" and "reflate". +It just isn't stable and fast enough yet to be of practical use. + + +How do I build it? +------------------ +There is a make file, but it has only been tested so far with MinGW gmake. +The produced executable is larger than 1MiB, while the MSVC compiler generated +executables were around 100KiB. The reason for that is unclear at the moment. + + +Credits +------- +- "precomp" by Christian Schneider +- "reflate" and "rawdet" by Eugene Shelwien +- "zlib" by Mark Adler et al. +- "7zip" by Igor Pavlov +- "kzip" by Ken Silverman + +All of the software above is just AWESOME! + +- the ENCODE.RU data compression forum (http://encode.ru/forum/2-Data-Compression) + +If you want to know about the new hot stuff in data compression (doesn't happen +too often though), look here first. + +- www.squeezechart.com by Stephan Busch + +Contains information about a lot of interesting compression tools of which I probably +would never have known without this site. Also, Stephan helped getting rid of several +bugs in preflate. Thank you. + + +Notes +----- +Currently, "preflate" uses code from two libraries: +- packARI by Matthias Stirner, which is licensed under LGPL3 + + (directory packARI) + + It is used for the arithmetic coding of the reconstruction information. +- zlib 1.2.11 by Mark Adler et al., under the zlib license. + + (directory zlib 1.2.11.dec. Does NOT contain the full zlib library!) + + It is used for the decoding of deflate streams, and some callbacks were + added to get the decoded trees and tokens, which are then used to build + the reconstruction information. + +The usage of both libraries will be removed in the future. +There already is a new implementation of deflate decoding (which is still slower +than the zlib one with callbacks). +And packARI is much more powerful and flexible than what is actually needed +in "preflate" right now. + + +License +------- +Copyright 2018 Dirk Steinke + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/contrib/preflate/main.cpp b/contrib/preflate/main.cpp new file mode 100644 index 0000000..4aa2cd9 --- /dev/null +++ b/contrib/preflate/main.cpp @@ -0,0 +1,178 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include +#include +#include +#include + +#include "preflate_checker.h" +#include "preflate_decoder.h" +#include "preflate_info.h" +#include "preflate_reencoder.h" +#include "support/support_tests.h" + +bool loadfile( + std::vector& content, + const std::string& fn) { + FILE* f = fopen(fn.c_str(), "rb"); + if (!f) { + return false; + } + fseek(f, 0, SEEK_END); + long length = ftell(f); + fseek(f, 0, SEEK_SET); + content.resize(length); + long read = fread(content.data(), 1, content.size(), f); + fclose(f); + return read == length; +} +bool savefile( + const std::vector& content, + const std::string& fn) { + FILE* f = fopen(fn.c_str(), "wb"); + if (!f) { + return false; + } + size_t written = fwrite(content.data(), 1, content.size(), f); + fclose(f); + return written == content.size(); +} + +int test(const char* const * const fns, const unsigned fncnt) { + bool ok = true; + for (unsigned i = 0; i < fncnt; ++i) { + std::vector content; + if (!loadfile(content, fns[i])) { + printf("loading of %s failed\n", fns[i]); + ok = false; + } else { + printf("checking %s\n", fns[i]); + bool check_ok = preflate_checker(content); + ok = ok && check_ok; + } + } + if (ok) { + printf("All checks ok\n"); + } + return ok ? 0 : -1; +} +int split(const char* const * const fns, const unsigned fncnt) { + bool ok = true; + for (unsigned i = 0; i < fncnt; ++i) { + std::vector content; + if (!loadfile(content, fns[i])) { + printf("loading of %s failed\n", fns[i]); + ok = false; + } else { + std::vector unpacked; + std::vector recon; + bool check_ok = preflate_decode(unpacked, recon, content); + if (check_ok) { + savefile(unpacked, std::string(fns[i]) + ".u"); + savefile(recon, std::string(fns[i]) + ".r"); + printf("splitting %s successful (%d -> %d + %d)\n", + fns[i], (int)content.size(), (int)unpacked.size(), (int)recon.size()); + } else { + printf("splitting %s failed\n", fns[i]); + } + ok = ok && check_ok; + } + } + if (ok) { + printf("All ok\n"); + } + return ok ? 0 : -1; +} +int combine(const char* const * const fns, const unsigned fncnt, const std::string& ext) { + bool ok = true; + for (unsigned i = 0; i < fncnt; ++i) { + std::vector unpacked; + std::vector recon; + if (!loadfile(unpacked, std::string(fns[i]) + ".u") + || !loadfile(recon, std::string(fns[i]) + ".r")) { + printf("loading of %s.u/.r failed\n", fns[i]); + ok = false; + } else { + std::vector content; + bool check_ok = preflate_reencode(content, recon, unpacked); + if (check_ok) { + savefile(content, std::string(fns[i]) + ext); + printf("recombining %s%s successful (%d + %d -> %d)\n", + fns[i], ext.c_str(), (int)unpacked.size(), (int)recon.size(), (int)content.size()); + } else { + printf("recombining %s%s failed\n", fns[i], ext.c_str()); + } + ok = ok && check_ok; + } + } + if (ok) { + printf("All ok\n"); + } + return ok ? 0 : -1; +} + +int main(int argc, const char * const * const argv) { + if (!support_self_tests()) { + return -1; + } + +/* static const char* const def_fns[] = { + "../testdata/zlib1.raw", "../testdata/zlib2.raw", "../testdata/zlib3.raw", + "../testdata/zlib4.raw", "../testdata/zlib5.raw", "../testdata/zlib6.raw", + "../testdata/zlib7.raw", "../testdata/zlib9.raw", + "../testdata/7zfast.raw", "../testdata/7zultra.raw", "../testdata/kz.raw", + "../testdata/dump.raw", "../testdata/dump_kz.raw", + "../testdata/new_pet.raw", "../testdata/bluevi6.raw", + "../testdata/test1a.png.raw", "../testdata/test1b.png.raw", "../testdata/test2b.png.raw", + }; + */ +static const char* const def_fns[] = { + "../testdata/broken/00000065_inf.raw", +}; + const char* const * fns = def_fns; + unsigned fncnt = sizeof(def_fns) / sizeof(def_fns[0]); + + if (argc >= 2) { + if (!strcmp(argv[1], "-t")) { + if (argc >= 3) { + fns = argv + 2; + fncnt = argc - 2; + } + return test(fns, fncnt); + } + if (argc >= 3 && !strcmp(argv[1], "-s")) { + return split(argv + 2, argc - 2); + } + if (argc >= 3 && !strcmp(argv[1], "-r")) { + return combine(argv + 2, argc - 2, ""); + } + if (argc >= 3 && !strcmp(argv[1], "-x")) { + return combine(argv + 2, argc - 2, ".x"); + } + } + printf("usage: %s -t FILE [FILE ... FILE]\n", argv[0]); + printf(" test uncompression and recompression\n"); + printf(" %s -s FILE [FILE ... FILE]\n", argv[0]); + printf(" split deflate stream (FILE) into uncompressed part\n"); + printf(" (FILE.u) and reconstruction info (FILE.r)\n"); + printf(" %s -r FILE [FILE ... FILE]\n", argv[0]); + printf(" recombine uncompressed part (FILE.u) and reconstruction\n"); + printf(" info (FILE.r) into deflate stream (FILE)\n"); + printf(" %s -x FILE [FILE ... FILE]\n", argv[0]); + printf(" recombines into FILE.x instead of FILE\n"); + return -1; +} diff --git a/contrib/preflate/packARI/.gitignore b/contrib/preflate/packARI/.gitignore new file mode 100644 index 0000000..7c4e65b --- /dev/null +++ b/contrib/preflate/packARI/.gitignore @@ -0,0 +1,31 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Folders to ignore +/zzz_backup/ diff --git a/contrib/preflate/packARI/LICENSE b/contrib/preflate/packARI/LICENSE new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/contrib/preflate/packARI/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/contrib/preflate/packARI/README.md b/contrib/preflate/packARI/README.md new file mode 100644 index 0000000..e4c6954 --- /dev/null +++ b/contrib/preflate/packARI/README.md @@ -0,0 +1,8 @@ +# packARI +A very basic compression tool for any file, mainly intended as base for bigger projects + +packARI is a compression tool based solely on the core entropy encoding component used in all my other compression softwares (that means packJPG, packMP3, packPNM, …). On it’s own it might not achieve good results for some file types, but it makes for a great starting point when developing compression tools of your own. + +The entropy coding in packARI has been tested since the beginning in all my other compression softwares, so it might be the most stable of them all. + +You may freely use packARI and it’s source code under the terms of the LGPL. diff --git a/contrib/preflate/packARI/source/Makefile b/contrib/preflate/packARI/source/Makefile new file mode 100644 index 0000000..fb7b98e --- /dev/null +++ b/contrib/preflate/packARI/source/Makefile @@ -0,0 +1,56 @@ +# packXXX Makefile, based on UniMake: Universal Makefile +# Created by Matthias Stirner, 01/2016 + +TARGET = packARI +CC = gcc +CPP = g++ +RC = windres -O coff +CPPFLAGS = -I. -O3 -Wall -pedantic -funroll-loops -ffast-math -fsched-spec-load -fomit-frame-pointer +LDFLAGS = -static -static-libgcc -static-libstdc++ +CSRC = $(wildcard *.c) +CPPSRC = $(wildcard *.cpp) +DEPS = $(wildcard *.h) Makefile +OBJ = $(patsubst %.c,%.o,$(CSRC)) $(patsubst %.cpp,%.o,$(CPPSRC)) + +# conditional stuff +ifeq ($(OS),Windows_NT) +LDFLAGS += -lpthread -L libwinpthread-1.dll +RES = icons.res +UPX := -upx --best --lzma $(TARGET).exe +else +CPPFLAGS += -DUNIX +RC = +RES = +UPX = +endif + +%.o: %.cpp $(DEPS) + $(CPP) -c -o $@ $< $(CPPFLAGS) + +%.res: %.rc + @-$(RC) $< $@ + +$(TARGET): $(OBJ) $(RES) + $(CPP) -o $@ $^ -s $(LDFLAGS) + $(UPX) + +.PHONY: all dev lib dll + +all: $(TARGET) + +dev: CPPFLAGS += -DDEV_BUILD +dev: $(TARGET) + +lib: CPPFLAGS += -DBUILD_LIB +lib: $(OBJ) + ar r $(TARGET)lib.a $(OBJ) + ranlib $(TARGET)lib.a + +dll: CPPFLAGS += -DBUILD_DLL +dll: LDFLAGS += -Wl,--out-implib,libpackJPG.a -fvisibility=hidden +dll: $(OBJ) + $(CPP) -shared -o $(TARGET).dll $^ $(LDFLAGS) + +clean: + @echo clean... + @-rm *.o *.a $(TARGET) $(TARGET).exe $(TARGET).dll diff --git a/contrib/preflate/packARI/source/app_icon.ico b/contrib/preflate/packARI/source/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..dcb200822fa7b7aebc359ab6a06f751792fe1269 GIT binary patch literal 3262 zcmeH~&r1S96vvDe&qgf_49dJZWA#ihqC}x)(tdm~`-95F1?*qeAJD znSoG9DAXaS=ukxWdh4^tus>$kP3h9e4sX8meV;cwJM1Dr0Dn_cfc+$t#sDS&U=}Zw zU;!^fm$dAVnyR)kneI;EsaAXY>NPAn6!y~6DFLm$4}K(amCfEa8Xv2xmw~_TF#+QiWhI>BIG*E=Sihpv1@sZUQI0c_$r3x!)w^cYC^sZ{&?{GB+ln2!8r z^Ti{UZC3uwOnqbHkqy5Lto%fxEi&m~lftnnz#$q)6nhk{d{nB{{sDH%5+MYq1+bro zw){}2&IUr!kYf{HEWsX1vE`$`DiGYpGV5a68y>?w2+telc!kpa~IzE=uD@( zxc*AzVQ#*tD7#+nWgtG8>0OHFYDD~>Dx>9NmE+@A*IV$hKVnKeZu7+{mF~E%XeLoq zJjVD+zq$FO^u@(}d^CG|{SqR +#include "bitops.h" +#include "aricoder.h" + +#define ERROR_EXIT { error = true; exit( 0 ); } + + +/* ----------------------------------------------- + constructor for aricoder class + ----------------------------------------------- */ + +aricoder::aricoder( iostream* stream, int iomode ) +{ + // iomode (i/o mode) + // 0 -> reading + // 1 -> writing + + int i; + + // set initial values + ccode = 0; + clow = 0; + chigh = CODER_LIMIT100 - 1; + cstep = 0; + bbyte = 0; + cbit = 0; + nrbits = 0; + + // store pointer to iostream for reading/writing + sptr = stream; + + // store i/o mode + mode = iomode; + + if ( mode == 0 ) { // mode is reading / decoding + // code buffer has to be filled before starting decoding + for ( i = 0; i < CODER_USE_BITS; i++ ) + ccode = ( ccode << 1 ) | read_bit(); + } // mode is writing / encoding otherwise +} + +/* ----------------------------------------------- + destructor for aricoder class + ----------------------------------------------- */ + +aricoder::~aricoder( void ) +{ + if ( mode == 1 ) { // mode is writing / encoding + // due to clow < CODER_LIMIT050, and chigh >= CODER_LIMIT050 + // there are only two possible cases + if ( clow < CODER_LIMIT025 ) { // case a.) + write_bit( 0 ); + // write remaining bits + write_bit( 1 ); + while ( nrbits-- > 0 ) + write_bit( 1 ); + } + else { // case b.), clow >= CODER_LIMIT025 + write_bit( 1 ); + } // done, zeroes are auto-read by the decoder + + // pad code with zeroes + while ( cbit > 0 ) write_bit( 0 ); + } +} + +/* ----------------------------------------------- + arithmetic encoder function + ----------------------------------------------- */ + +void aricoder::encode( symbol* s ) +{ + // update steps, low count, high count + cstep = ( ( chigh - clow ) + 1 ) / s->scale; + chigh = clow + ( cstep * s->high_count ) - 1; + clow = clow + ( cstep * s->low_count ); + + // e3 scaling is performed for speed and to avoid underflows + // if both, low and high are either in the lower half or in the higher half + // one bit can be safely shifted out + while ( ( clow >= CODER_LIMIT050 ) || ( chigh < CODER_LIMIT050 ) ) { + if ( chigh < CODER_LIMIT050 ) { // this means both, high and low are below, and 0 can be safely shifted out + // write 0 bit + write_bit( 0 ); + // shift out remaing e3 bits + for ( ; nrbits > 0; nrbits-- ) + write_bit( 1 ); + } + else { // if the first wasn't the case, it's clow >= CODER_LIMIT050 + // write 1 bit + write_bit( 1 ); + clow &= CODER_LIMIT050 - 1; + chigh &= CODER_LIMIT050 - 1; + // shift out remaing e3 bits + for ( ; nrbits > 0; nrbits-- ) + write_bit( 0 ); + } + clow <<= 1; + chigh <<= 1; + chigh++; + } + + // e3 scaling, to make sure that theres enough space between low and high + while ( ( clow >= CODER_LIMIT025 ) && ( chigh < CODER_LIMIT075 ) ) { + nrbits++; + clow &= CODER_LIMIT025 - 1; + chigh ^= CODER_LIMIT025 + CODER_LIMIT050; + // clow -= CODER_LIMIT025; + // chigh -= CODER_LIMIT025; + clow <<= 1; + chigh <<= 1; + chigh++; + } +} + +/* ----------------------------------------------- + arithmetic decoder get count function + ----------------------------------------------- */ + +unsigned int aricoder::decode_count( symbol* s ) +{ + // update cstep, which is needed to remove the symbol from the stream later + cstep = ( ( chigh - clow ) + 1 ) / s->scale; + + // return counts, needed to decode the symbol from the statistical model + return ( ccode - clow ) / cstep; +} + +/* ----------------------------------------------- + arithmetic decoder function + ----------------------------------------------- */ + +void aricoder::decode( symbol* s ) +{ + // no actual decoding takes place, as this has to happen in the statistical model + // the symbol has to be removed from the stream, though + + // alread have steps updated from decoder_count + // update low count and high count + chigh = clow + ( cstep * s->high_count ) - 1; + clow = clow + ( cstep * s->low_count ); + + // e3 scaling is performed for speed and to avoid underflows + // if both, low and high are either in the lower half or in the higher half + // one bit can be safely shifted out + while ( ( clow >= CODER_LIMIT050 ) || ( chigh < CODER_LIMIT050 ) ) { + if ( clow >= CODER_LIMIT050 ) { + clow &= CODER_LIMIT050 - 1; + chigh &= CODER_LIMIT050 - 1; + ccode &= CODER_LIMIT050 - 1; + } // if the first wasn't the case, it's chigh < CODER_LIMIT050 + clow <<= 1; + chigh <<= 1; + chigh++; + ccode <<= 1; + ccode |= read_bit(); + nrbits = 0; + } + + // e3 scaling, to make sure that theres enough space between low and high + while ( ( clow >= CODER_LIMIT025 ) && ( chigh < CODER_LIMIT075 ) ) { + nrbits++; + clow &= CODER_LIMIT025 - 1; + chigh ^= CODER_LIMIT025 + CODER_LIMIT050; + // clow -= CODER_LIMIT025; + // chigh -= CODER_LIMIT025; + ccode -= CODER_LIMIT025; + clow <<= 1; + chigh <<= 1; + chigh++; + ccode <<= 1; + ccode |= read_bit(); + } +} + +/* ----------------------------------------------- + bit writer function + ----------------------------------------------- */ + +void aricoder::write_bit( unsigned char bit ) +{ + // add bit at last position + bbyte = ( bbyte << 1 ) | bit; + // increment bit position + cbit++; + + // write bit if done + if ( cbit == 8 ) { + sptr->write( (void*) &bbyte, 1, 1 ); + cbit = 0; + } +} + +/* ----------------------------------------------- + bit reader function + ----------------------------------------------- */ + +unsigned char aricoder::read_bit( void ) +{ + // read in new byte if needed + if ( cbit == 0 ) { + if ( sptr->read( &bbyte, 1, 1 ) == 0 ) // read next byte if available + bbyte = 0; // if no more data is left in the stream + cbit = 8; + } + + // decrement current bit position + cbit--; + // return bit at cbit position + return BITN( bbyte, cbit ); +} + + +/* ----------------------------------------------- + universal statistical model for arithmetic coding + ----------------------------------------------- */ + +model_s::model_s( int max_s, int max_c, int max_o, int c_lim ) +{ + // boundaries of this model: + // max_s (maximum symbol) -> 1 <= max_s <= 1024 (???) + // max_c (maximum context) -> 1 <= max_c <= 1024 (???) + // max_o (maximum order) -> -1 <= max_o <= 4 + // c_lim (maximum count) -> 2 <= c_lim <= 4096 (???) + // WARNING: this can be memory intensive, so don't overdo it + // max_s == 256; max_c == 256; max_o == 4 would be way too much + + table_s* null_table; + table_s* start_table; + int i; + + + // set error false + error = false; + + // copy settings into model + max_symbol = max_s; + max_context = max_c; + max_order = max_o; + max_count = c_lim; + + + // alloc memory for totals table + // totals = ( unsigned short* ) calloc( max_symbol + 2, sizeof( short ) ); + totals = ( unsigned int* ) calloc( max_symbol + 2, sizeof( int ) ); + + // alloc memory for scoreboard, set sb0_count + scoreboard = ( char* ) calloc( max_symbol, sizeof( char ) ); + sb0_count = max_symbol; + + // set current order + current_order = max_order; + + + // set up null table + null_table = ( table_s* ) calloc( 1, sizeof( table_s ) ); + if ( null_table == NULL ) ERROR_EXIT; + null_table->counts = ( unsigned short* ) calloc( max_symbol, sizeof( short ) ); + if ( null_table->counts == NULL ) ERROR_EXIT; + for ( i = 0; i < max_symbol; i++ ) + null_table->counts[ i ] = 1; // set all probabilities + // set up internal counts + null_table->max_count = 1; + null_table->max_symbol = max_symbol; + + // set up start table + start_table = ( table_s* ) calloc( 1, sizeof( table_s ) ); + if ( start_table == NULL ) ERROR_EXIT; + start_table->links = ( table_s** ) calloc( max_context, sizeof( table_s* ) ); + if ( start_table->links == NULL ) ERROR_EXIT; + // set up internal counts + start_table->max_count = 0; + start_table->max_symbol = 0; + + // build links for start table & null table + start_table->lesser = null_table; + null_table->links = ( table_s** ) calloc( max_context, sizeof( table_s* ) ); + if ( null_table->links == NULL ) ERROR_EXIT; + for ( i = 0; i < max_context; i++ ) + null_table->links[ i ] = start_table; + + // alloc memory for storage & contexts + storage = ( table_s** ) calloc( max_order + 3, sizeof( table_s* ) ); + if ( storage == NULL ) ERROR_EXIT; + contexts = storage + 1; + + // integrate tables into contexts + contexts[ -1 ] = null_table; + contexts[ 0 ] = start_table; + + // build initial 'normal' tables + for ( i = 1; i <= max_order; i++ ) { + // set up current order table + contexts[ i ] = ( table_s* ) calloc( 1, sizeof( table_s ) ); + if ( contexts[ i ] == NULL ) ERROR_EXIT; + contexts[ i ]->max_count = 0; + contexts[ i ]->max_symbol = 0; + // build forward and backward links + contexts[ i ]->lesser = contexts[ i - 1 ]; + if ( i < max_order ) { + contexts[ i ]->links = ( table_s** ) calloc( max_context, sizeof( table_s* ) ); + if ( contexts[ i ]->links == NULL ) ERROR_EXIT; + } + else { + contexts[ i ]->links = NULL; + } + contexts[ i - 1 ]->links[ 0 ] = contexts[ i ]; + } +} + + +/* ----------------------------------------------- + model class destructor - recursive cleanup of memory is done here + ----------------------------------------------- */ + +model_s::~model_s( void ) +{ + table_s* context; + + + // clean up each 'normal' table + context = contexts[ 0 ]; + recursive_cleanup ( context ); + + // clean up null table + context = contexts[ -1 ]; + if ( context->links != NULL ) + free( context->links ); + if ( context->counts != NULL ) free( context->counts ); + free ( context ); + + // free everything else + free( storage ); + free( totals ); + free( scoreboard ); +} + + +/* ----------------------------------------------- + updates statistics for a specific symbol / resets to highest order + ----------------------------------------------- */ + +void model_s::update_model( int symbol ) +{ + // use -1 if you just want to reset without updating statistics + + table_s* context; + unsigned short* counts; + int local_order; + int i; + + + // only contexts, that were actually used to encode + // the symbol get their counts updated + if ( symbol >= 0 ) { + for ( local_order = ( current_order < 0 ) ? 0 : current_order; + local_order <= max_order; local_order++ ) { + context = contexts[ local_order ]; + counts = context->counts + symbol; + // update count for specific symbol & scale + (*counts)++; + // store side information for totalize_table + if ( (*counts) > context->max_count ) context->max_count = (*counts); + if ( symbol >= context->max_symbol ) context->max_symbol = symbol+1; + // if counts for that symbol have gone above the maximum count + // the table has to be resized (scale factor 2) + if ( (*counts) >= max_count ) + rescale_table( context, 1 ); + } + } + + // reset scoreboard and current order + current_order = max_order; + for ( i = 0; i < max_symbol; i++ ) + scoreboard[ i ] = 0; + sb0_count = max_symbol; +} + + +/* ----------------------------------------------- + shift in one context (max no of contexts is max_c) + ----------------------------------------------- */ + +void model_s::shift_context( int c ) +{ + table_s* context; + int i; + + // shifting is not possible if max_order is below 1 + // or context index is negative + if ( ( max_order < 1 ) || ( c < 0 ) ) return; + + // shift each orders' context + for ( i = max_order; i > 0; i-- ) { + // this is the new current order context + context = contexts[ i - 1 ]->links[ c ]; + + // check if context exists, build if needed + if ( context == NULL ) { + // reserve memory for next table_s + context = ( table_s* ) calloc( 1, sizeof( table_s ) ); + if ( context == NULL ) ERROR_EXIT; + // set counts NULL + context->counts = NULL; + // setup internal counts + context->max_count = 0; + context->max_symbol = 0; + // link lesser context later if not existing, this is done below + context->lesser = contexts[ i - 2 ]->links[ c ]; + // finished here if this is a max order context + if ( i == max_order ) + context->links = NULL; + else { + // build links to higher order tables otherwise + context->links = ( table_s** ) calloc( max_context, sizeof( table_s* ) ); + if ( context->links == NULL ) ERROR_EXIT; + // add lesser link for higher context (see above) + contexts[ i + 1 ]->lesser = context; + } + // put context to its right place + contexts[ i - 1 ]->links[ c ] = context; + } + + // switch context + contexts[ i ] = context; + } +} + + +/* ----------------------------------------------- + flushes the whole model by diviging through a specific scale factor + ----------------------------------------------- */ + +void model_s::flush_model( int scale_factor ) +{ + recursive_flush( contexts[ 0 ], scale_factor ); +} + + +/* ----------------------------------------------- + exclude specific symbols using this function + ----------------------------------------------- */ + +void model_s::exclude_symbols( char rule, int c ) +{ + // exclusions are back to normal after update_model is used + // modify scoreboard according to rule and value + switch ( rule ) + { + case 'a': + // above rule + // every symbol above c is excluded + for ( c = c + 1; c < max_symbol; c++ ) { + if ( scoreboard[ c ] == 0 ) { + scoreboard[ c ] = 1; + sb0_count--; + } + } + break; + + case 'b': + // below rule + // every symbol below c is excluded + for ( c = c - 1; c >= 0; c-- ) { + if ( scoreboard[ c ] == 0 ) { + scoreboard[ c ] = 1; + sb0_count--; + } + } + break; + + case 'e': + // equal rule + // only c is excluded + if ( scoreboard[ c ] == 0 ) { + scoreboard[ c ] = 1; + sb0_count--; + } + break; + + default: + // unknown rule + // do nothing + break; + } +} + + +/* ----------------------------------------------- + converts an int to a symbol, needed only when encoding + ----------------------------------------------- */ + +int model_s::convert_int_to_symbol( int c, symbol *s ) +{ + // search the symbol c in the current context table_s, + // return scale, low- and high counts + + table_s* context; + + + // totalize table for the current context + context = contexts[ current_order ]; + totalize_table( context ); + + // finding the scale is easy + s->scale = totals[ 0 ]; + + // check if that symbol exists in the current table. send escape otherwise + if ( c >= 0 ) { + if ( context->counts[ c ] > 0 ) { + // return high and low count for the current symbol + s->low_count = totals[ c + 2 ]; + s->high_count = totals[ c + 1 ]; + return 0; + } + } + + // return high and low count for the escape symbol + s->low_count = totals[ 1 ]; + s->high_count = totals[ 0 ]; + current_order--; + return 1; +} + + +/* ----------------------------------------------- + returns the current context scale needed only when decoding + ----------------------------------------------- */ + +void model_s::get_symbol_scale( symbol *s ) +{ + // getting the scale is easy: totalize the table_s, use accumulated count -> done + totalize_table( contexts[ current_order ] ); + s->scale = totals[ 0 ]; +} + + +/* ----------------------------------------------- + converts a count to an int, called after get_symbol_scale + ----------------------------------------------- */ + +int model_s::convert_symbol_to_int( int count, symbol *s ) +{ + // seek the symbol that matches the count, + // also, set low- and high count for the symbol - it has to be removed from the stream + + int c; + + // go through the totals table, search the symbol that matches the count + for ( c = 1; count < (signed) totals[ c ]; c++ ); + // set up the current symbol + s->low_count = totals[ c ]; + s->high_count = totals[ c - 1 ]; + // send escape if escape symbol encountered + if ( c == 1 ) { + current_order--; + return ESCAPE_SYMBOL; + } + + // return symbol value + return ( c - 2 ); +} + + +/* ----------------------------------------------- + totals are calculated by accumulating counts in the current table_s + ----------------------------------------------- */ + +void model_s::totalize_table( table_s *context ) +{ + // update exclusion is used, so this has to be done each time + // escape probability calculation also takes place here + + // accumulated counts must never exceed CODER_MAXSCALE + // as CODER_MAXSCALE is big enough, though, (2^29), this shouldn't happen and is not checked + + unsigned short* counts; + signed int local_symb; + unsigned int curr_total; + unsigned int curr_count; + unsigned int esc_prob; + int i; + + // make a local copy of the pointer + counts = context->counts; + + // check counts + if ( counts != NULL ) { // if counts are already set + // locally store current fill/symbol count + local_symb = sb0_count; + + // set the last symbol of the totals table_s zero + i = context->max_symbol - 1; + totals[ i + 2 ] = 0; + // (re)set current total + curr_total = 0; + + // go reverse though the whole counts table and accumulate counts + // leave space at the beginning of the table for the escape symbol + for ( ; i >= 0; i-- ) { + // only count probability if the current symbol is not 'scoreboard - excluded' + if ( scoreboard[ i ] == 0 ) { + curr_count = counts[ i ]; + if ( curr_count > 0 ) { + // add counts for the current symbol + curr_total = curr_total + curr_count; + // exclude symbol from scoreboard + scoreboard[ i ] = 1; + sb0_count--; + } + } + totals[ i + 1 ] = curr_total; + } + // here the escape calculation needs to take place + if ( local_symb == sb0_count ) + esc_prob = 1; + else if ( sb0_count == 0 ) + esc_prob = 0; + else { + // esc_prob = 1; + esc_prob = sb0_count * ( local_symb - sb0_count ); + esc_prob /= ( local_symb * context->max_count ); + esc_prob++; + } + // include escape probability in totals table + totals[ 0 ] = totals[ 1 ] + esc_prob; + } + else { // if counts are not already set + // setup counts for current table + context->counts = ( unsigned short* ) calloc( max_symbol, sizeof( short ) ); + if ( context->counts == NULL ) ERROR_EXIT; + // set totals table -> only escape probability included + totals[ 0 ] = 1; + totals[ 1 ] = 0; + } +} + + +/* ----------------------------------------------- + resizes one table by bitshifting each count using a specific value + ----------------------------------------------- */ + +inline void model_s::rescale_table( table_s* context, int scale_factor ) +{ + unsigned short* counts = context->counts; + int lst_symbol = context->max_symbol; + int i; + + // return now if counts not set + if ( counts == NULL ) return; + + // now scale the table by bitshifting each count + for ( i = 0; i < lst_symbol; i++ ) { + if ( counts[ i ] > 0 ) + counts[ i ] >>= scale_factor; + } + + // also rescale tables max count + context->max_count >>= scale_factor; + + // seek for new last symbol + for ( i = lst_symbol - 1; i >= 0; i-- ) + if ( counts[ i ] > 0 ) break; + context->max_symbol = i + 1; +} + + +/* ----------------------------------------------- + a recursive function to go through each context and rescale the counts + ----------------------------------------------- */ + +inline void model_s::recursive_flush( table_s* context, int scale_factor ) +{ + int i; + + // go through each link != NULL + if ( context->links != NULL ) + for ( i = 0; i < max_context; i++ ) + if ( context->links[ i ] != NULL ) + recursive_flush( context->links[ i ], scale_factor ); + + // rescale specific table + rescale_table( context, scale_factor ); +} + + +/* ----------------------------------------------- + frees all memory for all contexts starting at a given table_s + ----------------------------------------------- */ + +inline void model_s::recursive_cleanup( table_s *context ) +{ + // be careful not to cut any link too early! + + int i; + + // go through each link != NULL + if ( context->links != NULL ) { + for ( i = 0; i < max_context; i++ ) + if ( context->links[ i ] != NULL ) + recursive_cleanup( context->links[ i ] ); + free ( context->links ); + } + + // clean up table + if ( context->counts != NULL ) free ( context->counts ); + free( context ); +} + + +/* ----------------------------------------------- + special version of model_s for binary coding + ----------------------------------------------- */ + +model_b::model_b( int max_c, int max_o, int c_lim ) +{ + // boundaries of this model: + // ... (maximum symbol) -> 2 (0 or 1 ) + // max_c (maximum context) -> 1 <= max_c <= 1024 (???) + // max_o (maximum order) -> -1 <= max_o <= 4 + + table* null_table; + table* start_table; + int i; + + + // set error false + error = false; + + // copy settings into model + max_context = max_c; + max_order = max_o; + max_count = c_lim; + + + // set up null table + null_table = ( table* ) calloc( 1, sizeof( table ) ); + if ( null_table == NULL ) ERROR_EXIT; + + null_table->counts = ( unsigned short* ) calloc( 2, sizeof( short ) ); + if ( null_table->counts == NULL ) ERROR_EXIT; + null_table->counts[ 0 ] = 1; + null_table->counts[ 1 ] = 1; + null_table->scale = 2; + + // set up start table + start_table = ( table* ) calloc( 1, sizeof( table ) ); + if ( start_table == NULL ) ERROR_EXIT; + start_table->links = ( table** ) calloc( max_context, sizeof( table* ) ); + if ( start_table->links == NULL ) ERROR_EXIT; + start_table->scale = 0; + + // build links for start table & null table + start_table->lesser = null_table; + null_table->links = ( table** ) calloc( max_context, sizeof( table* ) ); + if ( null_table->links == NULL ) ERROR_EXIT; + for ( i = 0; i < max_context; i++ ) + null_table->links[ i ] = start_table; + + // alloc memory for storage & contexts + storage = ( table** ) calloc( max_order + 3, sizeof( table* ) ); + if ( storage == NULL ) ERROR_EXIT; + contexts = storage + 1; + + // integrate tables into contexts + contexts[ -1 ] = null_table; + contexts[ 0 ] = start_table; + + // build initial 'normal' tables + for ( i = 1; i <= max_order; i++ ) { + // set up current order table + contexts[ i ] = ( table* ) calloc( 1, sizeof( table ) ); + if ( contexts[ i ] == NULL ) ERROR_EXIT; + contexts[ i ]->scale = 0; + // build forward and backward links + contexts[ i ]->lesser = contexts[ i - 1 ]; + if ( i < max_order ) { + contexts[ i ]->links = ( table** ) calloc( max_context, sizeof( table* ) ); + if ( contexts[ i ]->links == NULL ) ERROR_EXIT; + } + else { + contexts[ i ]->links = NULL; + } + contexts[ i - 1 ]->links[ 0 ] = contexts[ i ]; + } +} + + +/* ----------------------------------------------- + model class destructor - recursive cleanup of memory is done here + ----------------------------------------------- */ + +model_b::~model_b( void ) +{ + table* context; + + + // clean up each 'normal' table + context = contexts[ 0 ]; + recursive_cleanup ( context ); + + // clean up null table + context = contexts[ -1 ]; + if ( context->links != NULL ) + free( context->links ); + if ( context->counts != NULL ) free( context->counts ); + free ( context ); + + // free everything else + free( storage ); +} + + +/* ----------------------------------------------- + updates statistics for a specific symbol / resets to highest order + ----------------------------------------------- */ + +void model_b::update_model( int symbol ) +{ + // use -1 if you just want to reset without updating statistics + + table* context = contexts[ max_order ]; + + // only contexts, that were actually used to encode + // the symbol get their counts updated + if ( ( symbol >= 0 ) && ( max_order >= 0 ) ) { + // update count for specific symbol & scale + context->counts[ symbol ]++; + context->scale++; + // if counts for that symbol have gone above the maximum count + // the table has to be resized (scale factor 2) + if ( context->counts[ symbol ] >= max_count ) + rescale_table( context, 1 ); + } +} + + +/* ----------------------------------------------- + shift in one context (max no of contexts is max_c) + ----------------------------------------------- */ + +void model_b::shift_context( int c ) +{ + table* context; + int i; + + // shifting is not possible if max_order is below 1 + // or context index is negative + if ( ( max_order < 1 ) || ( c < 0 ) ) return; + + // shift each orders' context + for ( i = max_order; i > 0; i-- ) { + // this is the new current order context + context = contexts[ i - 1 ]->links[ c ]; + + // check if context exists, build if needed + if ( context == NULL ) { + // reserve memory for next table + context = ( table* ) calloc( 1, sizeof( table ) ); + if ( context == NULL ) ERROR_EXIT; + // set internal counts NULL + context->counts = NULL; + context->scale = 0; + // link lesser context later if not existing, this is done below + context->lesser = contexts[ i - 2 ]->links[ c ]; + // finished here if this is a max order context + if ( i == max_order ) { + context->links = NULL; + } + else { + // build links to higher order tables otherwise + context->links = ( table** ) calloc( max_context, sizeof( table* ) ); + if ( context->links == NULL ) ERROR_EXIT; + // add lesser link for higher context (see above) + contexts[ i + 1 ]->lesser = context; + } + // put context to its right place + contexts[ i - 1 ]->links[ c ] = context; + } + + // switch context + contexts[ i ] = context; + } +} + + +/* ----------------------------------------------- + flushes the whole model by dividing through a specific scale factor + ----------------------------------------------- */ + +void model_b::flush_model( int scale_factor ) +{ + recursive_flush( contexts[ 0 ], scale_factor ); +} + + +/* ----------------------------------------------- + converts an int to a symbol, needed only when encoding + ----------------------------------------------- */ + +int model_b::convert_int_to_symbol( int c, symbol *s ) +{ + table* context = contexts[ max_order ]; + + // check if counts are available + check_counts( context ); + + // finding the scale is easy + s->scale = context->scale; + + // return high and low count for current symbol + if ( c == 0 ) { // if 0 is to be encoded + s->low_count = 0; + s->high_count = context->counts[ 0 ]; + } + else { // if 1 is to be encoded + s->low_count = context->counts[ 0 ]; + s->high_count = context->scale; + } + + return 1; +} + + +/* ----------------------------------------------- + returns the current context scale needed only when decoding + ----------------------------------------------- */ + +void model_b::get_symbol_scale( symbol *s ) +{ + table* context = contexts[ max_order ]; + + // check if counts are available + check_counts( context ); + + // getting the scale is easy + s->scale = context->scale; +} + + +/* ----------------------------------------------- + converts a count to an int, called after get_symbol_scale + ----------------------------------------------- */ + +int model_b::convert_symbol_to_int( int count, symbol *s ) +{ + table* context = contexts[ max_order ]; + unsigned short counts0 = context->counts[ 0 ]; + + // set up the current symbol + if ( count < counts0 ) { + s->low_count = 0; + s->high_count = counts0; + return 0; + } + else { + s->low_count = counts0; + s->high_count = s->scale; + return 1; + } +} + + +/* ----------------------------------------------- + this function checks if counts exist, and, if they exist and are below max + ----------------------------------------------- */ + +inline void model_b::check_counts( table *context ) +{ + unsigned short* counts = context->counts; + + // check if counts are available + if ( counts == NULL ) { + // setup counts for current table + counts = ( unsigned short* ) calloc( 2, sizeof( short ) ); + if ( counts == NULL ) ERROR_EXIT; + counts[ 0 ] = 1; + counts[ 1 ] = 1; + // set scale + context->counts = counts; + context->scale = 2; + } +} + + +/* ----------------------------------------------- + resizes one table by bitshifting each count using a specific value + ----------------------------------------------- */ + +inline void model_b::rescale_table( table* context, int scale_factor ) +{ + unsigned short* counts = context->counts; + + // return now if counts not set + if ( counts == NULL ) return; + + // now scale the table by bitshifting each count, be careful not to set any count zero + counts[ 0 ] >>= scale_factor; + counts[ 1 ] >>= scale_factor; + if ( counts[ 0 ] == 0 ) counts[ 0 ] = 1; + if ( counts[ 1 ] == 0 ) counts[ 1 ] = 1; + context->scale = counts[ 0 ] + counts[ 1 ]; +} + + +/* ----------------------------------------------- + a recursive function to go through each context and rescale the counts + ----------------------------------------------- */ + +inline void model_b::recursive_flush( table* context, int scale_factor ) +{ + int i; + + // go through each link != NULL + if ( context->links != NULL ) + for ( i = 0; i < max_context; i++ ) + if ( context->links[ i ] != NULL ) + recursive_flush( context->links[ i ], scale_factor ); + + // rescale specific table + rescale_table( context, scale_factor ); +} + + +/* ----------------------------------------------- + frees all memory for all contexts starting at a given table + ----------------------------------------------- */ + +inline void model_b::recursive_cleanup( table *context ) +{ + int i; + + // go through each link != NULL + if ( context->links != NULL ) { + for ( i = 0; i < max_context; i++ ) + if ( context->links[ i ] != NULL ) + recursive_cleanup( context->links[ i ] ); + free ( context->links ); + } + + // clean up table + if ( context->counts != NULL ) free ( context->counts ); + free( context ); +} diff --git a/contrib/preflate/packARI/source/aricoder.h b/contrib/preflate/packARI/source/aricoder.h new file mode 100644 index 0000000..df73286 --- /dev/null +++ b/contrib/preflate/packARI/source/aricoder.h @@ -0,0 +1,268 @@ +// defines for coder +#define CODER_USE_BITS 31 // must never be above 31 +#define CODER_LIMIT100 ( (unsigned int) ( 1 << CODER_USE_BITS ) ) +#define CODER_LIMIT025 ( ( CODER_LIMIT100 / 4 ) * 1 ) +#define CODER_LIMIT050 ( ( CODER_LIMIT100 / 4 ) * 2 ) +#define CODER_LIMIT075 ( ( CODER_LIMIT100 / 4 ) * 3 ) +#define CODER_MAXSCALE CODER_LIMIT025 - 1 +#define ESCAPE_SYMBOL CODER_LIMIT025 + + +// symbol struct, used in arithmetic coding +struct symbol { + unsigned int low_count; + unsigned int high_count; + unsigned int scale; +}; + +// table struct, used in in statistical models, +// holding all info needed for one context +struct table { + // counts for each symbol contained in the table + unsigned short* counts; + // links to higher order contexts + struct table** links; + // link to lower order context + struct table* lesser; + // accumulated counts + unsigned int scale; +}; + +// special table struct, used in in model_s, +// holding additional info for a speedier 'totalize_table' +struct table_s { + // counts for each symbol contained in the table + unsigned short* counts; + // links to higher order contexts + struct table_s** links; + // link to lower order context + struct table_s* lesser; + // speedup info + unsigned short max_count; + unsigned short max_symbol; + // unsigned short esc_prob; +}; + + +/* ----------------------------------------------- + class for arithmetic coding of data to/from iostream + ----------------------------------------------- */ + +class aricoder +{ + public: + aricoder( iostream* stream, int iomode ); + ~aricoder( void ); + void encode( symbol* s ); + unsigned int decode_count( symbol* s ); + void decode( symbol* s ); + + private: + // bitwise operations + void write_bit( unsigned char bit ); + unsigned char read_bit( void ); + + // i/o variables + iostream* sptr; + int mode; + unsigned char bbyte; + unsigned char cbit; + + // arithmetic coding variables + unsigned int ccode; + unsigned int clow; + unsigned int chigh; + unsigned int cstep; + unsigned int nrbits; +}; + + +/* ----------------------------------------------- + universal statistical model for arithmetic coding + ----------------------------------------------- */ + +class model_s +{ + public: + + model_s( int max_s, int max_c, int max_o, int c_lim ); + ~model_s( void ); + + void update_model( int symbol ); + void shift_context( int c ); + void flush_model( int scale_factor ); + void exclude_symbols( char rule, int c ); + + int convert_int_to_symbol( int c, symbol *s ); + void get_symbol_scale( symbol *s ); + int convert_symbol_to_int( int count, symbol *s ); + + bool error; + + + private: + + // unsigned short* totals; + unsigned int* totals; + char* scoreboard; + int sb0_count; + table_s **contexts; + table_s **storage; + + int max_symbol; + int max_context; + int current_order; + int max_order; + int max_count; + + inline void totalize_table(table_s* context ); + inline void rescale_table(table_s* context, int scale_factor ); + inline void recursive_flush(table_s* context, int scale_factor ); + inline void recursive_cleanup(table_s* context ); +}; + + +/* ----------------------------------------------- + binary statistical model for arithmetic coding + ----------------------------------------------- */ + +class model_b +{ + public: + + model_b( int max_c, int max_o, int c_lim ); + ~model_b( void ); + + void update_model( int symbol ); + void shift_context( int c ); + void flush_model( int scale_factor ); + + int convert_int_to_symbol( int c, symbol *s ); + void get_symbol_scale( symbol *s ); + int convert_symbol_to_int( int count, symbol *s ); + + bool error; + + + private: + + table **contexts; + table **storage; + + int max_context; + int max_order; + int max_count; + + inline void check_counts( table *context ); + inline void rescale_table( table* context, int scale_factor ); + inline void recursive_flush( table* context, int scale_factor ); + inline void recursive_cleanup( table *context ); +}; + + +/* ----------------------------------------------- + shift context x2 model_s function + ----------------------------------------------- */ +static inline void shift_model( model_s* model, int ctx1, int ctx2 ) +{ + model->shift_context( ctx1 ); + model->shift_context( ctx2 ); +} + + +/* ----------------------------------------------- + shift context x3 model_s function + ----------------------------------------------- */ +static inline void shift_model( model_s* model, int ctx1, int ctx2, int ctx3 ) +{ + model->shift_context( ctx1 ); + model->shift_context( ctx2 ); + model->shift_context( ctx3 ); +} + + +/* ----------------------------------------------- + shift context x2 model_b function + ----------------------------------------------- */ +static inline void shift_model( model_b* model, int ctx1, int ctx2 ) +{ + model->shift_context( ctx1 ); + model->shift_context( ctx2 ); +} + + +/* ----------------------------------------------- + shift context x3 model_b function + ----------------------------------------------- */ +static inline void shift_model( model_b* model, int ctx1, int ctx2, int ctx3 ) +{ + model->shift_context( ctx1 ); + model->shift_context( ctx2 ); + model->shift_context( ctx3 ); +} + + +/* ----------------------------------------------- + generic model_s encoder function + ----------------------------------------------- */ +static inline void encode_ari( aricoder* encoder, model_s* model, int c ) +{ + static symbol s; + static int esc; + + do { + esc = model->convert_int_to_symbol( c, &s ); + encoder->encode( &s ); + } while ( esc ); + model->update_model( c ); +} + +/* ----------------------------------------------- + generic model_s decoder function + ----------------------------------------------- */ +static inline int decode_ari( aricoder* decoder, model_s* model ) +{ + static symbol s; + static unsigned int count; + static int c; + + do{ + model->get_symbol_scale( &s ); + count = decoder->decode_count( &s ); + c = model->convert_symbol_to_int( count, &s ); + decoder->decode( &s ); + } while ( c == ESCAPE_SYMBOL ); + model->update_model( c ); + + return c; +} + +/* ----------------------------------------------- + generic model_b encoder function + ----------------------------------------------- */ +static inline void encode_ari( aricoder* encoder, model_b* model, int c ) +{ + static symbol s; + + model->convert_int_to_symbol( c, &s ); + encoder->encode( &s ); + model->update_model( c ); +} + +/* ----------------------------------------------- + generic model_b decoder function + ----------------------------------------------- */ +static inline int decode_ari( aricoder* decoder, model_b* model ) +{ + static symbol s; + static unsigned int count; + static int c; + + model->get_symbol_scale( &s ); + count = decoder->decode_count( &s ); + c = model->convert_symbol_to_int( count, &s ); + decoder->decode( &s ); + model->update_model( c ); + + return c; +} diff --git a/contrib/preflate/packARI/source/bitops.cpp b/contrib/preflate/packARI/source/bitops.cpp new file mode 100644 index 0000000..ba80de9 --- /dev/null +++ b/contrib/preflate/packARI/source/bitops.cpp @@ -0,0 +1,926 @@ +/* +This file contains special classes for bitwise +reading and writing of arrays +*/ + +#include +#include +#include +#include "bitops.h" + +#ifdef _MSC_VER // Changed by schnaader to enable compilation by MSVC +#include +#define setmode _setmode +#endif + +#define BUFFER_SIZE 1024 * 1024 + + +// special realloc with guaranteed free() of previous memory +static inline void* frealloc( void* ptr, size_t size ) { + void* n_ptr = realloc( ptr, (size) ? size : 1 ); + if ( n_ptr == NULL ) free( ptr ); + return n_ptr; +} + + +/* ----------------------------------------------- + constructor for abitreader class + ----------------------------------------------- */ + +abitreader::abitreader( unsigned char* array, int size ) +{ + cbyte = 0; + cbit = 8; + peof = 0; + eof = false; + + data = array; + lbyte = size; +} + +/* ----------------------------------------------- + destructor for abitreader class + ----------------------------------------------- */ + +abitreader::~abitreader( void ) +{ +} + +/* ----------------------------------------------- + reads n bits from abitreader + ----------------------------------------------- */ + +unsigned int abitreader::read( int nbits ) +{ + unsigned int retval = 0; + + // safety check for eof + if ( eof ) { + peof += nbits; + return 0; + } + + while ( nbits >= cbit ) { + nbits -= cbit; + retval |= ( RBITS( data[cbyte], cbit ) << nbits ); + cbit = 8; + if ( ++cbyte >= lbyte ) { + peof = nbits; + eof = true; + return retval; + } + } + + if ( nbits > 0 ) { + retval |= ( MBITS( data[cbyte], cbit, (cbit-nbits) ) ); + cbit -= nbits; + } + + return retval; +} + +/* ----------------------------------------------- + reads one bit from abitreader + ----------------------------------------------- */ + +unsigned char abitreader::read_bit( void ) +{ + unsigned char bit; + + // safety check for eof + if (eof) { + peof++; + return 0; + } + + // read one bit + bit = BITN( data[cbyte], --cbit ); + if ( cbit == 0 ) { + if ( ++cbyte == lbyte ) eof = true; + cbit = 8; + } + + return bit; +} + +/* ----------------------------------------------- + to skip padding from current byte + ----------------------------------------------- */ + +unsigned char abitreader::unpad( unsigned char fillbit ) +{ + if ( ( cbit == 8 ) || eof ) return fillbit; + else { + fillbit = read( 1 ); + while ( cbit != 8 ) read( 1 ); + } + + return fillbit; +} + +/* ----------------------------------------------- + get current position in array + ----------------------------------------------- */ + +int abitreader::getpos( void ) +{ + return cbyte; +} + +/* ----------------------------------------------- + get current bit position + ----------------------------------------------- */ + +int abitreader::getbitp( void ) +{ + return cbit; +} + +/* ----------------------------------------------- + set byte and bit position + ----------------------------------------------- */ + +void abitreader::setpos( int pbyte, int pbit ) +{ + if ( pbyte < lbyte ) { + // reset eof + eof = false; + // set positions + cbyte = pbyte; + cbit = pbit; + } else { + // set eof + eof = true; + // set positions + cbyte = lbyte; + cbit = 8; + peof = ( ( pbyte - lbyte ) * 8 ) + 8 - pbit; + } +} + +/* ----------------------------------------------- + rewind n bits + ----------------------------------------------- */ + +void abitreader::rewind_bits( int nbits ) +{ + if ( eof ) { + if ( nbits > peof ) nbits -= peof; + else { + peof -= nbits; + return; + } + eof = false; + } + for ( cbit += nbits; cbit > 8; cbyte--, cbit -= 8 ); + if ( cbyte < 0 ) { + cbyte = 0; + cbit = 8; + } +} + + +/* ----------------------------------------------- + constructor for abitwriter class + ----------------------------------------------- */ + +abitwriter::abitwriter( int size ) +{ + fillbit = 1; + adds = 65536; + cbyte = 0; + cbit = 8; + + error = false; + fmem = true; + + dsize = ( size > 0 ) ? size : adds; + data = ( unsigned char* ) malloc ( dsize ); + if ( data == NULL ) { + error = true; + return; + } + + // fill buffer with zeroes + memset( data, 0, dsize * sizeof( char ) ); + // for ( int i = 0; i < dsize; i++ ) data[i] = 0; +} + +/* ----------------------------------------------- + destructor for abitwriter class + ----------------------------------------------- */ + +abitwriter::~abitwriter( void ) +{ + // free memory if pointer was not given out + if ( fmem ) free( data ); +} + +/* ----------------------------------------------- + writes n bits to abitwriter + ----------------------------------------------- */ + +void abitwriter::write( unsigned int val, int nbits ) +{ + // safety check for error + if ( error ) return; + + // test if pointer beyond flush treshold + if ( cbyte > ( dsize - 5 ) ) { + dsize += adds; + data = (unsigned char*) frealloc( data, dsize ); + if ( data == NULL ) { + error = true; + return; + } + memset( ( data + cbyte + 1 ), 0, ( dsize - ( cbyte + 1 ) ) * sizeof( char ) ); + } + + // write data + while ( nbits >= cbit ) { + data[cbyte] |= ( MBITS32(val, nbits, (nbits-cbit)) ); + nbits -= cbit; + cbyte++; + cbit = 8; + } + + if ( nbits > 0 ) { + data[cbyte] |= ( (RBITS32(val, nbits)) << (cbit - nbits) ); + cbit -= nbits; + } +} + +/* ----------------------------------------------- + writes one bit to abitwriter + ----------------------------------------------- */ + +void abitwriter::write_bit( unsigned char bit ) +{ + // safety check for error + if ( error ) return; + + // write data + if ( bit ) data[cbyte] |= 0x1 << (--cbit); + else --cbit; + if ( cbit == 0 ) { + // test if pointer beyond flush treshold + if ( ++cbyte > ( dsize - 5 ) ) { + dsize += adds; + data = (unsigned char*) frealloc( data, dsize ); + if ( data == NULL ) { + error = true; + return; + } + memset( ( data + cbyte + 1 ), 0, ( dsize - ( cbyte + 1 ) ) * sizeof( char ) ); + } + cbit = 8; + } +} + +/* ----------------------------------------------- + pads data using fillbit + ----------------------------------------------- */ + +void abitwriter::pad( unsigned char fillbit ) +{ + while ( cbit < 8 ) + write( fillbit, 1 ); +} + +/* ----------------------------------------------- + gets data array from abitwriter + ----------------------------------------------- */ + +unsigned char* abitwriter::getptr( void ) +{ + // data is padded here + pad( fillbit ); + // forbid freeing memory + fmem = false; + // realloc data + data = (unsigned char*) frealloc( data, cbyte ); + + return data; +} + +/* ----------------------------------------------- + gets size of data array from abitwriter + ----------------------------------------------- */ + +int abitwriter::getpos( void ) +{ + return cbyte; +} + +/* ----------------------------------------------- + get current bit position + ----------------------------------------------- */ + +int abitwriter::getbitp( void ) +{ + return cbit; +} + + +/* ----------------------------------------------- + constructor for abytewriter class + ----------------------------------------------- */ + +abytereader::abytereader( unsigned char* array, int size ) +{ + cbyte = 0; + eof = false; + + data = array; + lbyte = size; + + if ( ( data == NULL ) || ( lbyte == 0 ) ) + eof = true; +} + +/* ----------------------------------------------- + destructor for abytewriter class + ----------------------------------------------- */ + +abytereader::~abytereader( void ) +{ +} + +/* ----------------------------------------------- + reads 1 byte from abytereader + ----------------------------------------------- */ + +int abytereader::read( unsigned char* byte ) +{ + if ( cbyte >= lbyte ) { + cbyte = lbyte; + eof = true; + return 0; + } + else { + *byte = data[ cbyte++ ]; + return 1; + } +} + +/* ----------------------------------------------- + reads n bytes from abytereader + ----------------------------------------------- */ + +int abytereader::read_n( unsigned char* byte, int n ) +{ + int nl = lbyte - cbyte; + int i; + + if ( nl < n ) { + for ( i = 0; i < nl; i++ ) + byte[ i ] = data[ cbyte + i ]; + cbyte = lbyte; + eof = true; + return nl; + } + else { + for ( i = 0; i < n; i++ ) + byte[ i ] = data[ cbyte + i ]; + cbyte += n; + return n; + } +} + +/* ----------------------------------------------- + go to position in data + ----------------------------------------------- */ + +void abytereader::seek( int pos ) +{ + if ( pos >= lbyte ) { + cbyte = lbyte; + eof = true; + } + else { + cbyte = pos; + eof = false; + } +} + +/* ----------------------------------------------- + gets size of current data + ----------------------------------------------- */ + +int abytereader::getsize( void ) +{ + return lbyte; +} + +/* ----------------------------------------------- + gets current position from abytereader + ----------------------------------------------- */ + +int abytereader::getpos( void ) +{ + return cbyte; +} + + +/* ----------------------------------------------- + constructor for abytewriter class + ----------------------------------------------- */ + +abytewriter::abytewriter( int size ) +{ + adds = 65536; + cbyte = 0; + + error = false; + fmem = true; + + dsize = ( size > 0 ) ? size : adds; + data = (unsigned char*) malloc( dsize ); + if ( data == NULL ) { + error = true; + return; + } +} + +/* ----------------------------------------------- + destructor for abytewriter class + ----------------------------------------------- */ + +abytewriter::~abytewriter( void ) +{ + // free data if pointer is not read + if ( fmem ) free( data ); +} + +/* ----------------------------------------------- + writes 1 byte to abytewriter + ----------------------------------------------- */ + +void abytewriter::write( unsigned char byte ) +{ + // safety check for error + if ( error ) return; + + // test if pointer beyond flush threshold + if ( cbyte >= ( dsize - 2 ) ) { + dsize += adds; + data = (unsigned char*) frealloc( data, dsize ); + if ( data == NULL ) { + error = true; + return; + } + } + + // write data + data[ cbyte++ ] = byte; +} + +/* ----------------------------------------------- + writes n byte to abytewriter + ----------------------------------------------- */ + +void abytewriter::write_n( unsigned char* byte, int n ) +{ + // safety check for error + if ( error ) return; + + // make sure that pointer doesn't get beyond flush threshold + while ( ( cbyte + n ) >= ( dsize - 2 ) ) { + dsize += adds; + data = (unsigned char*) frealloc( data, dsize ); + if ( data == NULL ) { + error = true; + return; + } + } + + // copy data from array + while ( n-- > 0 ) + data[ cbyte++ ] = *(byte++); +} + +/* ----------------------------------------------- + gets data array from abytewriter + ----------------------------------------------- */ + +unsigned char* abytewriter::getptr( void ) +{ + // safety check for error + if ( error ) return NULL; + // forbid freeing memory + fmem = false; + // realloc data + data = (unsigned char*) frealloc( data, cbyte ); + + return data; +} + +/* ----------------------------------------------- + peeks into data array from abytewriter + ----------------------------------------------- */ + +unsigned char* abytewriter::peekptr( void ) +{ + return data; +} + +/* ----------------------------------------------- + gets size of data array from abytewriter + ----------------------------------------------- */ + +int abytewriter::getpos( void ) +{ + return cbyte; +} + +/* ----------------------------------------------- + reset without realloc + ----------------------------------------------- */ + +void abytewriter::reset( void ) +{ + // set position of current byte + cbyte = 0; +} + + +/* ----------------------------------------------- + constructor for iostream class + ----------------------------------------------- */ + +iostream::iostream( void* src, int srctype, int srcsize, int iomode ) +{ + // locally copy source, source type # and io mode # + source = src; + srct = srctype; + srcs = srcsize; + mode = iomode; + + // don't free memory when reading - this will be useful if switching occurs + free_mem_sw = false; + + // set binary mode for streams + #if defined( _WIN32 ) + setmode( fileno( stdin ), O_BINARY ); + setmode( fileno( stdout ), O_BINARY ); + #endif + + // open file/mem/stream + switch ( srct ) + { + case 0: + open_file(); + break; + + case 1: + open_mem(); + break; + + case 2: + open_stream(); + break; + + default: + break; + } +} + +/* ----------------------------------------------- + destructor for iostream class + ----------------------------------------------- */ + +iostream::~iostream( void ) +{ + // if needed, write memory to stream or free memory from buffered stream + if ( srct == 2 ) { + if ( mode == 1 ) { + if ( !(mwrt->error) ) { + srcs = mwrt->getpos(); + source = mwrt->getptr(); + fwrite( source, sizeof( char ), srcs, stdout ); + } + } + } + + // free all buffers + if ( srct == 0 ) { + if ( fptr != NULL ) { + if ( mode == 1 ) fflush( fptr ); + fclose( fptr ); + } + } + else if ( mode == 0 ) { + if ( free_mem_sw ) + free( source ); + delete( mrdr ); + } + else + delete( mwrt ); +} + +/* ----------------------------------------------- + switches mode from reading to writing and vice versa + ----------------------------------------------- */ + +void iostream::switch_mode( void ) +{ + // return immediately if there's an error + if ( chkerr() ) return; + + + if ( mode == 0 ) { + // WARNING: when switching from reading to writing, information might be lost forever + switch ( srct ) { + case 0: + fclose( fptr ); + fptr = fopen( ( char* ) source, "wb" ); + break; + case 1: + case 2: + delete( mrdr ); + if ( free_mem_sw ) + free( source ); // see? I've told you so :-) + mwrt = new abytewriter( srcs ); + break; + default: + break; + } + mode = 1; + } + else { + // switching from writing to reading is a bit more complicated + switch ( srct ) { + case 0: + fflush( fptr ); + fclose( fptr ); + fptr = fopen( ( char* ) source, "rb" ); + break; + case 1: + case 2: + source = mwrt->getptr(); + srcs = mwrt->getpos(); + delete( mwrt ); + mrdr = new abytereader( ( unsigned char* ) source, srcs ); + free_mem_sw = true; + break; + default: + break; + } + mode = 0; + } +} + +/* ----------------------------------------------- + generic read function + ----------------------------------------------- */ + +int iostream::read( void* to, int tpsize, int dtsize ) +{ + return ( srct == 0 ) ? read_file( to, tpsize, dtsize ) : read_mem( to, tpsize, dtsize ); +} + +/* ----------------------------------------------- + generic write function + ----------------------------------------------- */ + +int iostream::write( void* from, int tpsize, int dtsize ) +{ + return ( srct == 0 ) ? write_file( from, tpsize, dtsize ) : write_mem( from, tpsize, dtsize ); +} + +/* ----------------------------------------------- + flush function + ----------------------------------------------- */ + +int iostream::flush( void ) +{ + if ( srct == 0 ) + fflush( fptr ); + + return getpos(); +} + +/* ----------------------------------------------- + rewind to beginning of stream + ----------------------------------------------- */ + +int iostream::rewind( void ) +{ + // WARNING: when writing, rewind might lose all your data + if ( srct == 0 ) + fseek( fptr, 0, SEEK_SET ); + else if ( mode == 0 ) + mrdr->seek( 0 ); + else + mwrt->reset(); + + return getpos(); +} + +/* ----------------------------------------------- + get current position in stream + ----------------------------------------------- */ + +int iostream::getpos( void ) +{ + int pos; + + if ( srct == 0 ) + pos = ftell( fptr ); + else if ( mode == 0 ) + pos = mrdr->getpos(); + else + pos = mwrt->getpos(); + + return pos; +} + +/* ----------------------------------------------- + get size of file + ----------------------------------------------- */ + +int iostream::getsize( void ) +{ + int pos; + int siz; + + if ( mode == 0 ) { + if ( srct == 0 ) { + pos = ftell( fptr ); + fseek( fptr, 0, SEEK_END ); + siz = ftell( fptr ); + fseek( fptr, pos, SEEK_SET ); + } + else { + siz = mrdr->getsize(); + } + } + else { + siz = getpos(); + } + + return siz; +} + +/* ----------------------------------------------- + get data pointer (for mem io only) + ----------------------------------------------- */ + +unsigned char* iostream::getptr( void ) +{ + if ( srct == 1 ) + return ( mode == 0 ) ? ( unsigned char* ) source : mwrt->getptr(); + else + return NULL; +} + +/* ----------------------------------------------- + check for errors + ----------------------------------------------- */ + +bool iostream::chkerr( void ) +{ + bool error = false; + + // check for user input errors + if ( ( mode != 0 ) && ( mode != 1 ) ) + error = true; + if ( ( srct != 0 ) && ( srct != 1 ) && ( srct != 2 ) ) + error = true; + + // check for io errors + if ( srct == 0 ) { + if ( fptr == NULL ) + error = true; + else if ( ferror( fptr ) ) + error = true; + } + else if ( mode == 0 ) { + if ( mrdr == NULL ) + error = true; + } + else { + if ( mwrt == NULL ) + error = true; + else if ( mwrt->error ) + error = true; + } + + return error; +} + +/* ----------------------------------------------- + check for eof (read only) + ----------------------------------------------- */ + +bool iostream::chkeof( void ) +{ + if ( mode == 0 ) + return ( srct == 0 ) ? feof( fptr ) : mrdr->eof; + else + return false; +} + +/* ----------------------------------------------- + open function for files + ----------------------------------------------- */ + +void iostream::open_file( void ) +{ + char* fn = (char*) source; + + // open file for reading / writing + fptr = fopen( fn, ( mode == 0 ) ? "rb" : "wb" ); +} + +/* ----------------------------------------------- + open function for memory + ----------------------------------------------- */ + +void iostream::open_mem( void ) +{ + if ( mode == 0 ) + mrdr = new abytereader( ( unsigned char* ) source, srcs ); + else + mwrt = new abytewriter( srcs ); +} + +/* ----------------------------------------------- + open function for streams + ----------------------------------------------- */ + +void iostream::open_stream( void ) +{ + abytewriter* strwrt; + unsigned char* buffer; + int i; + + if ( mode == 0 ) { + // read whole stream into memory buffer + strwrt = new abytewriter( 0 ); + buffer = ( unsigned char* ) calloc( BUFFER_SIZE, sizeof( char ) ); + if ( buffer != NULL ) { + while ( ( i = fread( buffer, sizeof( char ), BUFFER_SIZE, stdin ) ) > 0 ) + strwrt->write_n( buffer, i ); + } + if ( strwrt->error ) { + source = NULL; + srcs = 0; + } + else { + source = strwrt->getptr(); + srcs = strwrt->getpos(); + } + delete ( strwrt ); + free( buffer ); + // free memory after done + free_mem_sw = true; + } + + // for writing: simply open new stream in mem writer + // writing to stream will be done later + open_mem(); +} + +/* ----------------------------------------------- + write function for files + ----------------------------------------------- */ + +int iostream::write_file( void* from, int tpsize, int dtsize ) +{ + return fwrite( from, tpsize, dtsize, fptr ); +} + +/* ----------------------------------------------- + read function for files + ----------------------------------------------- */ + +int iostream::read_file( void* to, int tpsize, int dtsize ) +{ + return fread( to, tpsize, dtsize, fptr ); +} + +/* ----------------------------------------------- + write function for memory + ----------------------------------------------- */ + +int iostream::write_mem( void* from, int tpsize, int dtsize ) +{ + int n = tpsize * dtsize; + + mwrt->write_n( ( unsigned char* ) from, n ); + + return ( mwrt->error ) ? 0 : n; +} + +/* ----------------------------------------------- + read function for memory + ----------------------------------------------- */ + +int iostream::read_mem( void* to, int tpsize, int dtsize ) +{ + int n = tpsize * dtsize; + + return ( mrdr->read_n( ( unsigned char* ) to, n ) ) / tpsize; +} diff --git a/contrib/preflate/packARI/source/bitops.h b/contrib/preflate/packARI/source/bitops.h new file mode 100644 index 0000000..db12311 --- /dev/null +++ b/contrib/preflate/packARI/source/bitops.h @@ -0,0 +1,168 @@ +#define RBITS( c, n ) ( c & ( 0xFF >> (8 - n) ) ) +#define LBITS( c, n ) ( c >> (8 - n) ) +#define MBITS( c, l, r ) ( RBITS( c,l ) >> r ) +#define RBITS16( c, n ) ( c & ( 0xFFFFFFFF >> (16 - n) ) ) +#define LBITS16( c, n ) ( c >> (16 - n) ) +#define MBITS16( c, l, r ) ( RBITS16( c,l ) >> r ) +#define RBITS32( c, n ) ( c & ( 0xFFFFFFFF >> (32 - n) ) ) +#define LBITS32( c, n ) ( c >> (32 - n) ) +#define MBITS32( c, l, r ) ( RBITS32( c,l ) >> r ) +#define BITN( c, n ) ( (c >> n) & 0x1 ) +#define BITLEN( l, v ) for ( l = 0; ( v >> l ) > 0; l++ ) +#define FDIV2( v, p ) ( ( v < 0 ) ? -( (-v) >> p ) : ( v >> p ) ) + +#define TYPE_FILE 0 +#define TYPE_MEMORY 1 +#define TYPE_STREAM 2 +#define MODE_READ 0 +#define MODE_WRITE 1 + +#define BTST_BUFF 1024 * 1024 + +#include + + +/* ----------------------------------------------- + class to read arrays bitwise + ----------------------------------------------- */ + +class abitreader +{ +public: + abitreader( unsigned char* array, int size ); + ~abitreader( void ); + unsigned int read( int nbits ); + unsigned char read_bit( void ); + unsigned char unpad( unsigned char fillbit ); + int getpos( void ); + int getbitp( void ); + void setpos( int pbyte, int pbit ); + void rewind_bits( int nbits ); + bool eof; + int peof; + +private: + unsigned char* data; + int lbyte; + int cbyte; + int cbit; +}; + + +/* ----------------------------------------------- + class to write arrays bitwise + ----------------------------------------------- */ + +class abitwriter +{ +public: + abitwriter( int size ); + ~abitwriter( void ); + void write( unsigned int val, int nbits ); + void write_bit( unsigned char bit ); + void pad ( unsigned char fillbit ); + unsigned char* getptr( void ); + int getpos( void ); + int getbitp( void ); + bool error; + unsigned char fillbit; + +private: + unsigned char* data; + int dsize; + int adds; + int cbyte; + int cbit; + bool fmem; +}; + + +/* ----------------------------------------------- + class to read arrays bytewise + ----------------------------------------------- */ + +class abytereader +{ +public: + abytereader( unsigned char* array, int size ); + ~abytereader( void ); + int read( unsigned char* byte ); + int read_n( unsigned char* byte, int n ); + void seek( int pos ); + int getsize( void ); + int getpos( void ); + bool eof; + +private: + unsigned char* data; + int lbyte; + int cbyte; +}; + + +/* ----------------------------------------------- + class to write arrays bytewise + ----------------------------------------------- */ + +class abytewriter +{ +public: + abytewriter( int size ); + ~abytewriter( void ); + void write( unsigned char byte ); + void write_n( unsigned char* byte, int n ); + unsigned char* getptr( void ); + unsigned char* peekptr( void ); + int getpos( void ); + void reset( void ); + bool error; + +private: + unsigned char* data; + int dsize; + int adds; + int cbyte; + bool fmem; +}; + + +/* ----------------------------------------------- + class for input and output from file or memory + ----------------------------------------------- */ + +class iostream +{ +public: + iostream( void* src, int srctype, int srcsize, int iomode ); + ~iostream( void ); + void switch_mode( void ); + int read( void* to, int tpsize, int dtsize ); + int write( void* from, int tpsize, int dtsize ); + int flush( void ); + int rewind( void ); + int getpos( void ); + int getsize( void ); + unsigned char* getptr( void ); + bool chkerr( void ); + bool chkeof( void ); + +private: + void open_file( void ); + void open_mem( void ); + void open_stream( void ); + + int write_file( void* from, int tpsize, int dtsize ); + int read_file( void* to, int tpsize, int dtsize ); + int write_mem( void* from, int tpsize, int dtsize ); + int read_mem( void* to, int tpsize, int dtsize ); + + FILE* fptr; + abytewriter* mwrt; + abytereader* mrdr; + + bool free_mem_sw; + void* source; + int mode; + int srct; + int srcs; +}; diff --git a/contrib/preflate/packARI/source/file_icon.ico b/contrib/preflate/packARI/source/file_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..16fbf621adb0f386b5078ef1921125fab41e564f GIT binary patch literal 3262 zcmds)K}!Nb6vyA*J4Z(kE_RRtKS2nqA3;x|SC8Tc*pFZcK~PJFJtTzC(LunF7!?-&;qe;HOf9X7f2TN?%m)OQosEAx~6d4R&B> zQkK7OxBJE^$cJYsR&tY;QT$|bAbB!2)DT4qn*umBA{*6DSvJk@^%loTGnamUXbZkS*CemdA4*ZH%`mppc{(`sZTmu< z&a{5va|d@_?4eqj&xtlvKl6)4)pZ?JKUKw$SOYJ^$>fuwve~Ov>w)aw;!^?n{5YMy z1~_({who_sq&apk6oPW1Yq3{A=3{ L{vQ0%2y%Y|=$Ovj literal 0 HcmV?d00001 diff --git a/contrib/preflate/packARI/source/icons.res b/contrib/preflate/packARI/source/icons.res new file mode 100644 index 0000000000000000000000000000000000000000..67d7217cc2c0885b6b65fc3460d16435c4572079 GIT binary patch literal 6922 zcmeI1O-NKx6vxj~X$q>1EhJnF;$VSTxwXY)j6)D9w9u6wvXlfuB77DcpGFlYjqFw#pobh~mSa!)npHj2sxFc$V;Fe0V=KKX;XGoa2~GHC>@D{2ilf zbd@^k2Hm7fu&={d=48PUP43je{%!2Tnf+n9r}fWaEQ%+N$DumZz9n6zl1Qu%4Q)S~ z{JgO6?N`1aWLenV-7gsEtwZozTUXQR4=XD_Mn+yc4i0a0aPXy<%$h*_zP>jaCp)uM zUq6w}ZfSbymgL7`%MA_Bh#p{`lap`7(NZw*2L?757r!&7qazFc+S(UOteAQEO-;*V zW1qy}kb;-r+q%92{OH`7oHB-Ki)aA>@-AG?2~w*=A}g%qr~puuP@4G5@)_k1ZFb zVzI|IYYD_>WB!)ny{Zs@FG^+kh%!I_wd4{)?2qcw(^KRZCzE+EaaChhsv1ifpY)B5 zU3PD8e}bc#o-Tw?38DE6Nha5uo1YTh2S1U>dTFdN)aqnP%6|N!j$Y%UW||WFrfLij z!;nfa%M3BpX7~T2A$9;iogus|U0nEH$_4qTOB%5QIt}k_s94eyI?<;0^H;L@ze1k+T!Q zkP2zO{6dOS>-zDFrb043uMm`vg-9wSz8aRhsJ#Z7Mz+N(aH<0PphcoX@M2XB(Rffe z?Ctr8RcU^RJSEWlv4o&`N>DyR1j +#include +#include +#include + +#include "bitops.h" +#include "aricoder.h" +#include "paritbl.h" + +#if defined BUILD_DLL // define BUILD_LIB from the compiler options if you want to compile a DLL! + #define BUILD_LIB +#endif + +#if defined BUILD_LIB // define BUILD_LIB from the compiler options if you want to compile a library! + #include "packarilib.h" +#endif + +#define INTERN static + +#define INIT_MODEL_S(a,b,c) new model_s( a, b, c, 511 ) +#define INIT_MODEL_B(a,b) new model_b( a, b, 511 ) + +#define ABS(v1) ( (v1 < 0) ? -v1 : v1 ) +#define ABSDIFF(v1,v2) ( (v1 > v2) ? (v1 - v2) : (v2 - v1) ) +#define ROUND_F(v1) ( (v1 < 0) ? (int) (v1 - 0.5) : (int) (v1 + 0.5) ) +#define CLAMPED(l,h,v) ( ( v < l ) ? l : ( v > h ) ? h : v ) + +#define MEM_ERRMSG "out of memory error" +#define FRD_ERRMSG "could not read file / file not found" +#define FWR_ERRMSG "could not write file / file write-protected" +#define MSG_SIZE 128 +#define BARLEN 36 + + + +/* ----------------------------------------------- + function declarations: main interface + ----------------------------------------------- */ + +#if !defined( BUILD_LIB ) +INTERN void initialize_options( int argc, char** argv ); +INTERN void process_ui( void ); +INTERN inline const char* get_status( bool (*function)() ); +INTERN void show_help( void ); +#endif +INTERN void process_file( void ); +INTERN void execute( bool (*function)() ); + + +/* ----------------------------------------------- + function declarations: main functions + ----------------------------------------------- */ + +#if !defined( BUILD_LIB ) +INTERN bool check_file( void ); +INTERN bool swap_streams( void ); +INTERN bool compare_output( void ); +#endif +INTERN bool reset_buffers( void ); +INTERN bool decide_model_order( void ); +INTERN bool encode_file( void ); +INTERN bool decode_file( void ); + + +/* ----------------------------------------------- + function declarations: other coding functions + ----------------------------------------------- */ + +INTERN inline bool check_par_header( void ); +INTERN inline bool read_par_header( void ); +INTERN inline bool write_par_header( void ); +INTERN inline bool endecode_file( bool encoding ); +INTERN inline double cost_count_ari( model_s* model, int c ); + + +/* ----------------------------------------------- + function declarations: miscelaneous helpers + ----------------------------------------------- */ + +#if !defined( BUILD_LIB ) +INTERN inline void progress_bar( int current, int last ); +INTERN inline char* create_filename( const char* base, const char* extension ); +INTERN inline char* unique_filename( const char* base, const char* extension ); +INTERN inline void set_extension( const char* filename, const char* extension ); +INTERN inline void add_underscore( char* filename ); +#endif +INTERN inline bool file_exists( const char* filename ); + + +/* ----------------------------------------------- + function declarations: developers functions + ----------------------------------------------- */ + +// these are developers functions, they are not needed +// in any way to compress or decompress files +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +INTERN bool write_errfile( void ); +#endif + +/* ----------------------------------------------- + global variables: library only variables + ----------------------------------------------- */ +#if defined(BUILD_LIB) +INTERN int lib_in_type = -1; +INTERN int lib_out_type = -1; +#endif + + +/* ----------------------------------------------- + global variables: info about files + ----------------------------------------------- */ + +INTERN char* cmpfilename = NULL; // name of compressed file +INTERN char* uncfilename = NULL; // name of uncompressed file +INTERN int cmpfilesize; // size of compressed file +INTERN int uncfilesize; // size of uncompressed file +INTERN int filetype; // type of current file +INTERN iostream* str_in = NULL; // input stream +INTERN iostream* str_out = NULL; // output stream + +#if !defined( BUILD_LIB ) +INTERN iostream* str_str = NULL; // storage stream + +INTERN char** filelist = NULL; // list of files to process +INTERN int file_cnt = 0; // count of files in list +INTERN int file_no = 0; // number of current file + +INTERN char** err_list = NULL; // list of error messages +INTERN int* err_tp = NULL; // list of error types +#endif + + +/* ----------------------------------------------- + global variables: messages + ----------------------------------------------- */ + +INTERN char errormessage [ 128 ]; +INTERN bool (*errorfunction)(); +INTERN int errorlevel; +// meaning of errorlevel: +// -1 -> wrong input +// 0 -> no error +// 1 -> warning +// 2 -> fatal error + + +/* ----------------------------------------------- + global variables: settings + ----------------------------------------------- */ + +#if !defined( BUILD_LIB ) +INTERN int verbosity = -1; // level of verbosity +INTERN bool overwrite = false; // overwrite files yes / no +INTERN bool wait_exit = true; // pause after finished yes / no +INTERN bool force_enc = false; // force encoding even for already compressed files yes / no +INTERN bool store_name = true; // store file name in compressed files yes / no +INTERN int verify_lv = 0; // verification level ( none (0), simple (1), detailed output (2) ) +INTERN int err_tol = 1; // error threshold ( proceed on warnings yes (2) / no (1) ) + +INTERN bool developer = false; // allow developers functions yes/no +INTERN int action = A_COMPRESS; // what to do with files + +INTERN FILE* msgout = stdout; // stream for output of messages +INTERN bool pipe_on = false; // use stdin/stdout instead of filelist +#else +INTERN bool force_enc = false; // force encoding even for already compressed files yes / no +INTERN bool store_name = false; // store file name in compressed files yes / no +INTERN int err_tol = 1; // error threshold ( proceed on warnings yes (2) / no (1) ) +INTERN int action = A_COMPRESS; // what to do with files +#endif + +/* ----------------------------------------------- + global variables: coding parameters + ----------------------------------------------- */ + +INTERN int model_order = -1; // order of statistical model (decided by analysis) +INTERN int stored_order = -1; // stored model order + + +/* ----------------------------------------------- + global variables: info about program + ----------------------------------------------- */ + +INTERN const unsigned char appversion = 6; +INTERN const char* subversion = "f"; +INTERN const char* apptitle = "packARI"; +INTERN const char* appname = "packARI"; +INTERN const char* versiondate = "01/22/2016"; +INTERN const char* author = "Matthias Stirner"; +#if !defined(BUILD_LIB) +INTERN const char* website = "http://packjpg.encode.ru/"; +INTERN const char* email = "packjpg (at) matthiasstirner.com"; +INTERN const char* copyright = "2012-2016 Matthias Stirner & HTW Aalen"; +INTERN const char* cmp_ext = "par"; +INTERN const char* unc_ext = "unc"; +#endif +INTERN const char cmp_magic[] = { 'A', 'S' }; + + +/* ----------------------------------------------- + main-function + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +int main( int argc, char** argv ) +{ + sprintf( errormessage, "no errormessage specified" ); + + clock_t begin, end; + + int error_cnt = 0; + int warn_cnt = 0; + + double acc_uncsize = 0; + double acc_cmpsize = 0; + + int kbps; + double cr; + double total; + + errorlevel = 0; + + + // read options from command line + initialize_options( argc, argv ); + + // write program info to screen + fprintf( msgout, "\n--> %s v%i.%i%s (%s) by %s <--\n", + apptitle, appversion / 10, appversion % 10, subversion, versiondate, author ); + fprintf( msgout, "Copyright %s\nAll rights reserved\n\n", copyright ); + + // check if user input is wrong, show help screen if it is + if ( ( file_cnt == 0 ) || + ( ( !developer ) && ( (action != A_COMPRESS) || (verify_lv > 1) ) ) ) { + show_help(); + return -1; + } + + // (re)set program has to be done first + reset_buffers(); + + // process file(s) - this is the main function routine + begin = clock(); + for ( file_no = 0; file_no < file_cnt; file_no++ ) { + // process current file + process_ui(); + // store error message and type if any + if ( errorlevel > 0 ) { + err_list[ file_no ] = (char*) calloc( MSG_SIZE, sizeof( char ) ); + err_tp[ file_no ] = errorlevel; + if ( err_list[ file_no ] != NULL ) + strcpy( err_list[ file_no ], errormessage ); + } + // count errors / warnings / file sizes + if ( errorlevel >= err_tol ) error_cnt++; + else { + if ( errorlevel == 1 ) warn_cnt++; + acc_uncsize += uncfilesize; + acc_cmpsize += cmpfilesize; + } + } + end = clock(); + + // errors summary: only needed for -v2 or progress bar + if ( ( verbosity == -1 ) || ( verbosity == 2 ) ) { + // print summary of errors to screen + if ( error_cnt > 0 ) { + fprintf( stderr, "\n\nfiles with errors:\n" ); + fprintf( stderr, "------------------\n" ); + for ( file_no = 0; file_no < file_cnt; file_no++ ) { + if ( err_tp[ file_no ] >= err_tol ) { + fprintf( stderr, "%s (%s)\n", filelist[ file_no ], err_list[ file_no ] ); + } + } + } + // print summary of warnings to screen + if ( warn_cnt > 0 ) { + fprintf( stderr, "\n\nfiles with warnings:\n" ); + fprintf( stderr, "------------------\n" ); + for ( file_no = 0; file_no < file_cnt; file_no++ ) { + if ( err_tp[ file_no ] == 1 ) { + fprintf( stderr, "%s (%s)\n", filelist[ file_no ], err_list[ file_no ] ); + } + } + } + } + + // show statistics + fprintf( msgout, "\n\n-> %i file(s) processed, %i error(s), %i warning(s)\n", + file_cnt, error_cnt, warn_cnt ); + if ( ( file_cnt > error_cnt ) && ( verbosity != 0 ) && + ( action == A_COMPRESS ) ) { + acc_uncsize /= 1024.0; acc_cmpsize /= 1024.0; + total = (double) ( end - begin ) / CLOCKS_PER_SEC; + kbps = ( total > 0 ) ? ( acc_uncsize / total ) : acc_uncsize; + cr = ( acc_uncsize > 0 ) ? ( 100.0 * acc_cmpsize / acc_uncsize ) : 0; + + fprintf( msgout, " -------------------------------- \n" ); + if ( total >= 0 ) { + fprintf( msgout, " total time : %8.2f sec\n", total ); + fprintf( msgout, " avrg. kbyte per s : %8i kbps\n", kbps ); + } + else { + fprintf( msgout, " total time : %8s sec\n", "N/A" ); + fprintf( msgout, " avrg. kbyte per s : %8s kbps\n", "N/A" ); + } + fprintf( msgout, " avrg. comp. ratio : %8.2f %%\n", cr ); + fprintf( msgout, " -------------------------------- \n" ); + } + + // pause before exit + if ( wait_exit && ( msgout != stderr ) ) { + fprintf( msgout, "\n\n< press ENTER >\n" ); + fgetc( stdin ); + } + + + return 0; +} +#endif + +/* ----------------------- Begin of library only functions -------------------------- */ + +/* ----------------------------------------------- + DLL export converter function + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT bool parlib_convert_stream2stream( char* msg ) +{ + // process in main function + return parlib_convert_stream2mem( NULL, NULL, msg ); +} +#endif + + +/* ----------------------------------------------- + DLL export converter function + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT bool parlib_convert_file2file( char* in, char* out, char* msg ) +{ + // init streams + parlib_init_streams( (void*) in, 0, 0, (void*) out, 0 ); + + // process in main function + return parlib_convert_stream2mem( NULL, NULL, msg ); +} +#endif + + +/* ----------------------------------------------- + DLL export converter function + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT bool parlib_convert_stream2mem( unsigned char** out_file, unsigned int* out_size, char* msg ) +{ + clock_t begin, end; + int total; + float cr; + + + // (re)set buffers + reset_buffers(); + action = A_COMPRESS; + + // main compression / decompression routines + begin = clock(); + + // process one file + process_file(); + + // fetch pointer and size of output (only for memory output) + if ( ( errorlevel < err_tol ) && ( lib_out_type == 1 ) && + ( out_file != NULL ) && ( out_size != NULL ) ) { + *out_size = str_out->getsize(); + *out_file = str_out->getptr(); + } + + // close iostreams + if ( str_in != NULL ) delete( str_in ); str_in = NULL; + if ( str_out != NULL ) delete( str_out ); str_out = NULL; + + end = clock(); + + // copy errormessage / remove files if error (and output is file) + if ( errorlevel >= err_tol ) { + if ( lib_out_type == 0 ) { + if ( filetype == F_UNK ) { + if ( file_exists( cmpfilename ) ) remove( cmpfilename ); + } else if ( filetype == F_PAR ) { + if ( file_exists( uncfilename ) ) remove( uncfilename ); + } + } + if ( msg != NULL ) strcpy( msg, errormessage ); + return false; + } + + // get compression info + total = (int) ( (double) (( end - begin ) * 1000) / CLOCKS_PER_SEC ); + cr = ( uncfilesize > 0 ) ? ( 100.0 * cmpfilesize / uncfilesize ) : 0; + + // write success message else + if ( msg != NULL ) { + switch( filetype ) + { + case F_UNK: + sprintf( msg, "Compressed to %s (%.2f%%) in %ims", + cmpfilename, cr, ( total >= 0 ) ? total : -1 ); + break; + case F_PAR: + sprintf( msg, "Decompressed to %s (%.2f%%) in %ims", + uncfilename, cr, ( total >= 0 ) ? total : -1 ); + break; + } + } + + + return true; +} +#endif + + +/* ----------------------------------------------- + DLL export init input (file/mem) + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT void parlib_init_streams( void* in_src, int in_type, int in_size, void* out_dest, int out_type ) +{ + /* a short reminder about input/output stream types: + + if input is file + ---------------- + in_scr -> name of input file + in_type -> 0 + in_size -> ignore + + if input is memory + ------------------ + in_scr -> array containg data + in_type -> 1 + in_size -> size of data array + + if input is *FILE (f.e. stdin) + ------------------------------ + in_src -> stream pointer + in_type -> 2 + in_size -> ignore + + vice versa for output streams! */ + + unsigned char buffer[ 3 ]; + + + // (re)set errorlevel + filetype = F_UNK; + errorfunction = NULL; + errorlevel = 0; + uncfilesize = 0; + cmpfilesize = 0; + + // open input stream, check for errors + str_in = new iostream( in_src, in_type, in_size, 0 ); + if ( str_in->chkerr() ) { + sprintf( errormessage, "error opening input stream" ); + errorlevel = 2; + return; + } + + // open output stream, check for errors + str_out = new iostream( out_dest, out_type, 0, 1 ); + if ( str_out->chkerr() ) { + sprintf( errormessage, "error opening output stream" ); + errorlevel = 2; + return; + } + + // free memory from filenames if needed + if ( uncfilename != NULL ) free( uncfilename ); uncfilename = NULL; + if ( cmpfilename != NULL ) free( cmpfilename ); cmpfilename = NULL; + + // check input stream + if ( !force_enc ) { + str_in->read( buffer, 1, 3 ); + if ( (buffer[0] == cmp_magic[0]) && (buffer[1] == cmp_magic[1]) ) { + // file might be PAR - check version and header + if ( check_par_header() ) { + filetype = F_PAR; + if ( buffer[2] != appversion ) { + sprintf( errormessage, "incompatible file, use %s v%i.%i", + appname, buffer[2] / 10, buffer[2] % 10 ); + errorlevel = 2; + return; + } + // copy filenames + cmpfilename = (char*) calloc( ( in_type == 0 ) ? strlen( (char*) in_src ) + 1 : 32, sizeof( char ) ); + uncfilename = (char*) calloc( ( out_type == 0 ) ? strlen( (char*) out_dest ) + 1 : 32, sizeof( char ) ); + strcpy( cmpfilename, ( in_type == 0 ) ? (char*) in_src : "PAR in memory" ); + strcpy( uncfilename, ( out_type == 0 ) ? (char*) out_dest : "ANY in memory" ); + } + } + str_in->rewind(); + } + + if ( filetype == F_UNK ) { + // file is any other file type + filetype = F_UNK; + // copy filenames + uncfilename = (char*) calloc( ( in_type == 0 ) ? strlen( (char*) in_src ) + 1 : 32, sizeof( char ) ); + cmpfilename = (char*) calloc( ( out_type == 0 ) ? strlen( (char*) out_dest ) + 1 : 32, sizeof( char ) ); + strcpy( uncfilename, ( in_type == 0 ) ? (char*) in_src : "PAR in memory" ); + strcpy( cmpfilename, ( out_type == 0 ) ? (char*) out_dest : "ANY in memory" ); + // get uncompressed file size + uncfilesize = str_in->getsize(); + str_in->rewind(); + } + + // store types of in-/output + lib_in_type = in_type; + lib_out_type = out_type; +} +#endif + + +/* ----------------------------------------------- + DLL export force encoding setting + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT void parlib_force_encoding( bool setting ) +{ + // adopt the setting + force_enc = setting; +} +#endif + + +/* ----------------------------------------------- + DLL export version information + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT const char* parlib_version_info( void ) +{ + static char v_info[ 256 ]; + + // copy version info to string + sprintf( v_info, "--> %s library v%i.%i%s (%s) by %s <--", + apptitle, appversion / 10, appversion % 10, subversion, versiondate, author ); + + return (const char*) v_info; +} +#endif + + +/* ----------------------------------------------- + DLL export version information + ----------------------------------------------- */ + +#if defined(BUILD_LIB) +EXPORT const char* parlib_short_name( void ) +{ + static char v_name[ 256 ]; + + // copy version info to string + sprintf( v_name, "%s v%i.%i%s", + apptitle, appversion / 10, appversion % 10, subversion ); + + return (const char*) v_name; +} +#endif + +/* ----------------------- End of libary only functions -------------------------- */ + +/* ----------------------- Begin of main interface functions -------------------------- */ + + +/* ----------------------------------------------- + reads in commandline arguments + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN void initialize_options( int argc, char** argv ) +{ + int tmp_val; + char** tmp_flp; + int i; + + + // get memory for filelist & preset with NULL + filelist = (char**) calloc( argc, sizeof( char* ) ); + for ( i = 0; i < argc; i++ ) + filelist[ i ] = NULL; + + // preset temporary filelist pointer + tmp_flp = filelist; + + + // read in arguments + while ( --argc > 0 ) { + argv++; + // switches begin with '-' + if ( strcmp((*argv), "-p" ) == 0 ) { + err_tol = 2; + } + else if ( strcmp((*argv), "-ver" ) == 0 ) { + verify_lv = ( verify_lv < 1 ) ? 1 : verify_lv; + } + else if ( sscanf( (*argv), "-v%i", &tmp_val ) == 1 ){ + verbosity = tmp_val; + verbosity = ( verbosity < 0 ) ? 0 : verbosity; + verbosity = ( verbosity > 2 ) ? 2 : verbosity; + } + else if ( strcmp((*argv), "-vp" ) == 0 ) { + verbosity = -1; + } + else if ( strcmp((*argv), "-np" ) == 0 ) { + wait_exit = false; + } + else if ( strcmp((*argv), "-o" ) == 0 ) { + overwrite = true; + } + else if ( strcmp((*argv), "-f" ) == 0 ) { + force_enc = true; + } + #if defined(DEV_BUILD) + else if ( strcmp((*argv), "-dev") == 0 ) { + developer = true; + } + else if ( strcmp((*argv), "-test") == 0 ) { + verify_lv = 2; + } + else if ( strcmp((*argv), "-nfn") == 0 ) { + store_name = false; + } + else if ( sscanf( (*argv), "-mo%i", &tmp_val ) == 1 ) { + tmp_val = ( tmp_val < 0 ) ? 0 : tmp_val; + tmp_val = ( tmp_val > MAX_ORDER ) ? MAX_ORDER : tmp_val; + stored_order = tmp_val; + } + #endif + else if ( strcmp((*argv), "-") == 0 ) { + // switch standard message out stream + msgout = stderr; + // use "-" as placeholder for stdin + *(tmp_flp++) = (char*) "-"; + } + else { + // if argument is not switch, it's a filename + *(tmp_flp++) = *argv; + } + } + + // count number of files (or filenames) in filelist + for ( file_cnt = 0; filelist[ file_cnt ] != NULL; file_cnt++ ); + + // alloc arrays for error messages and types storage + err_list = (char**) calloc( file_cnt, sizeof( char* ) ); + err_tp = (int*) calloc( file_cnt, sizeof( int ) ); +} +#endif + + +/* ----------------------------------------------- + UI for processing one file + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN void process_ui( void ) +{ + clock_t begin, end; + const char* actionmsg = NULL; + const char* errtypemsg = NULL; + int total, bpms; + float cr; + + + errorfunction = NULL; + errorlevel = 0; + uncfilesize = 0; + cmpfilesize = 0; + #if !defined(DEV_BUILD) + action = A_COMPRESS; + #endif + + // compare file name, set pipe if needed + if ( ( strcmp( filelist[ file_no ], "-" ) == 0 ) && ( action == A_COMPRESS ) ) { + pipe_on = true; + filelist[ file_no ] = (char*) "STDIN"; + } + else { + pipe_on = false; + } + + if ( verbosity >= 0 ) { // standard UI + fprintf( msgout, "\nProcessing file %i of %i \"%s\" -> ", + file_no + 1, file_cnt, filelist[ file_no ] ); + + if ( verbosity > 1 ) + fprintf( msgout, "\n----------------------------------------" ); + + // check input file and determine filetype + execute( check_file ); + + // get specific action message + switch ( action ) { + case A_COMPRESS: ( filetype == F_UNK ) ? actionmsg = "Compressing" : actionmsg = "Decompressing"; + break; + } + + if ( verbosity < 2 ) fprintf( msgout, "%s -> ", actionmsg ); + } + else { // progress bar UI + // update progress message + fprintf( msgout, "Processing file %2i of %2i ", file_no + 1, file_cnt ); + progress_bar( file_no, file_cnt ); + fprintf( msgout, "\r" ); + execute( check_file ); + } + fflush( msgout ); + + + // main function routine + begin = clock(); + + // streams are initiated, start processing file + process_file(); + + // close iostreams + if ( str_in != NULL ) delete( str_in ); str_in = NULL; + if ( str_out != NULL ) delete( str_out ); str_out = NULL; + if ( str_str != NULL ) delete( str_str ); str_str = NULL; + // delete if broken or if output not needed + if ( ( !pipe_on ) && ( ( errorlevel >= err_tol ) || ( action != A_COMPRESS ) ) ) { + if ( filetype == F_UNK ) { + if ( file_exists( cmpfilename ) ) remove( cmpfilename ); + } else if ( filetype == F_PAR ) { + if ( file_exists( uncfilename ) ) remove( uncfilename ); + } + } + + end = clock(); + + // speed and compression ratio calculation + total = (int) ( (double) (( end - begin ) * 1000) / CLOCKS_PER_SEC ); + bpms = ( total > 0 ) ? ( uncfilesize / total ) : uncfilesize; + cr = ( uncfilesize > 0 ) ? ( 100.0 * cmpfilesize / uncfilesize ) : 0; + + + if ( verbosity >= 0 ) { // standard UI + if ( verbosity > 1 ) + fprintf( msgout, "\n----------------------------------------" ); + + // display success/failure message + switch ( verbosity ) { + case 0: + if ( errorlevel < err_tol ) { + if ( action == A_COMPRESS ) fprintf( msgout, "%.2f%%", cr ); + else fprintf( msgout, "DONE" ); + } + else fprintf( msgout, "ERROR" ); + if ( errorlevel > 0 ) fprintf( msgout, "\n" ); + break; + + case 1: + fprintf( msgout, "%s\n", ( errorlevel < err_tol ) ? "DONE" : "ERROR" ); + break; + + case 2: + if ( errorlevel < err_tol ) fprintf( msgout, "\n-> %s OK\n", actionmsg ); + else fprintf( msgout, "\n-> %s ERROR\n", actionmsg ); + break; + } + + // set type of error message + switch ( errorlevel ) { + case 0: errtypemsg = "none"; break; + case 1: ( err_tol > 1 ) ? errtypemsg = "warning (ignored)" : errtypemsg = "warning (skipped file)"; break; + case 2: errtypemsg = "fatal error"; break; + } + + // error/ warning message + if ( errorlevel > 0 ) { + fprintf( msgout, " %s -> %s:\n", get_status( errorfunction ), errtypemsg ); + fprintf( msgout, " %s\n", errormessage ); + } + if ( (verbosity > 0) && (errorlevel < err_tol) && (action == A_COMPRESS) ) { + if ( total >= 0 ) { + fprintf( msgout, " time taken : %7i msec\n", total ); + fprintf( msgout, " byte per ms : %7i byte\n", bpms ); + } + else { + fprintf( msgout, " time taken : %7s msec\n", "N/A" ); + fprintf( msgout, " byte per ms : %7s byte\n", "N/A" ); + } + fprintf( msgout, " comp. ratio : %7.2f %%\n", cr ); + } + if ( ( verbosity > 1 ) && ( action == A_COMPRESS ) ) + fprintf( msgout, "\n" ); + } + else { // progress bar UI + // if this is the last file, update progress bar one last time + if ( file_no + 1 == file_cnt ) { + // update progress message + fprintf( msgout, "Processed %2i of %2i files ", file_no + 1, file_cnt ); + progress_bar( 1, 1 ); + fprintf( msgout, "\r" ); + } + } +} +#endif + + +/* ----------------------------------------------- + gets statusmessage for function + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN inline const char* get_status( bool (*function)() ) +{ + if ( function == NULL ) { + return "unknown action"; + } else if ( function == *check_file ) { + return "Determining filetype"; + } else if ( function == *decide_model_order ) { + return "Deciding model order"; + } else if ( function == *encode_file ) { + return "Compressing file"; + } else if ( function == *decode_file ) { + return "Decompressing file"; + } else if ( function == *swap_streams ) { + return "Swapping input/output streams"; + } else if ( function == *compare_output ) { + return "Verifying output stream"; + } else if ( function == *reset_buffers ) { + return "Resetting program"; + } + #if defined(DEV_BUILD) + // no specific developer functions! + #endif + else { + return "Function description missing!"; + } +} +#endif + + +/* ----------------------------------------------- + shows help in case of wrong input + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN void show_help( void ) +{ + fprintf( msgout, "\n" ); + fprintf( msgout, "Website: %s\n", website ); + fprintf( msgout, "Email : %s\n", email ); + fprintf( msgout, "\n" ); + fprintf( msgout, "Usage: %s [switches] [filename(s)]", appname ); + fprintf( msgout, "\n" ); + fprintf( msgout, "\n" ); + fprintf( msgout, " [-f] force encoding for compressed files\n" ); + fprintf( msgout, " [-ver] verify files after processing\n" ); + fprintf( msgout, " [-v?] set level of verbosity (max: 2) (def: 0)\n" ); + fprintf( msgout, " [-np] no pause after processing files\n" ); + fprintf( msgout, " [-o] overwrite existing files\n" ); + fprintf( msgout, " [-p] proceed on warnings\n" ); + #if defined(DEV_BUILD) + if ( developer ) { + fprintf( msgout, "\n" ); + fprintf( msgout, " [-mo?] force model order for coding (0...%i)\n", MAX_ORDER ); + fprintf( msgout, " [-nfn] don't store filenames\n" ); + } + #endif + fprintf( msgout, "\n" ); + fprintf( msgout, "Examples: \"%s -v1 -o image??.%s\"\n", appname, cmp_ext ); + fprintf( msgout, " \"%s -p *.txt\"\n", appname ); +} +#endif + + +/* ----------------------------------------------- + processes one file + ----------------------------------------------- */ + +INTERN void process_file( void ) +{ + if ( filetype == F_UNK ) { + switch ( action ) { + case A_COMPRESS: + execute( decide_model_order ); + execute( encode_file ); + #if !defined(BUILD_LIB) + if ( verify_lv > 0 ) { // verifcation + execute( reset_buffers ); + execute( swap_streams ); + execute( decode_file ); + execute( compare_output ); + } + #endif + break; + + #if !defined(BUILD_LIB) && defined(DEV_BUILD) + // no developers functionality! + #else + default: + break; + #endif + } + } + else if ( filetype == F_PAR ) { + switch ( action ) + { + case A_COMPRESS: + execute( decode_file ); + #if !defined(BUILD_LIB) + // this does not work yet! + // and it's not even needed + /*if ( verify_lv > 0 ) { // verifcation + execute( reset_buffers ); + execute( swap_streams ); + execute( decide_model_order ); + execute( encode_file ); + execute( compare_output ); + }*/ + #endif + break; + + #if !defined(BUILD_LIB) && defined(DEV_BUILD) + // no developers functionality! + #else + default: + break; + #endif + } + } + #if !defined(BUILD_LIB) && defined(DEV_BUILD) + // write error file if verify lv > 1 + if ( ( verify_lv > 1 ) && ( errorlevel >= err_tol ) ) + write_errfile(); + #endif + // reset buffers + reset_buffers(); +} + + +/* ----------------------------------------------- + main-function execution routine + ----------------------------------------------- */ + +INTERN void execute( bool (*function)() ) +{ + if ( errorlevel < err_tol ) { + #if !defined BUILD_LIB + clock_t begin, end; + bool success; + int total; + + // write statusmessage + if ( verbosity == 2 ) { + fprintf( msgout, "\n%s ", get_status( function ) ); + for ( int i = strlen( get_status( function ) ); i <= 30; i++ ) + fprintf( msgout, " " ); + } + + // set starttime + begin = clock(); + // call function + success = ( *function )(); + // set endtime + end = clock(); + + if ( ( errorlevel > 0 ) && ( errorfunction == NULL ) ) + errorfunction = function; + + // write time or failure notice + if ( success ) { + total = (int) ( (double) (( end - begin ) * 1000) / CLOCKS_PER_SEC ); + if ( verbosity == 2 ) fprintf( msgout, "%6ims", ( total >= 0 ) ? total : -1 ); + } + else { + errorfunction = function; + if ( verbosity == 2 ) fprintf( msgout, "%8s", "ERROR" ); + } + #else + // call function + ( *function )(); + + // store errorfunction if needed + if ( ( errorlevel > 0 ) && ( errorfunction == NULL ) ) + errorfunction = function; + #endif + } +} + +/* ----------------------- End of main interface functions -------------------------- */ + +/* ----------------------- Begin of main functions -------------------------- */ + + +/* ----------------------------------------------- + check file and determine filetype + ----------------------------------------------- */ + +#if !defined(BUILD_LIB) +INTERN bool check_file( void ) +{ + unsigned char fileid[ 3 ] = { 0, 0, 0 }; + const char* filename = filelist[ file_no ]; + + // preset file type + filetype = F_UNK; + + // open input stream, check for errors + str_in = new iostream( (void*) filename, ( !pipe_on ) ? 0 : 2, 0, 0 ); + if ( str_in->chkerr() ) { + sprintf( errormessage, FRD_ERRMSG ); + errorlevel = 2; + return false; + } + + // free memory from filenames if needed + if ( uncfilename != NULL ) free( uncfilename ); uncfilename = NULL; + if ( cmpfilename != NULL ) free( cmpfilename ); cmpfilename = NULL; + + // check if this is a compressed par file + while ( !force_enc ) { + // read file id and version number + if ( str_in->read( fileid, 1, 3 ) != 3 ) break; + // check magic number + if ( ( fileid[0] != cmp_magic[0] ) || ( fileid[1] != cmp_magic[1] ) ) break; + // check par header, extract file name + if ( !check_par_header() ) break; + // alright: this is a .par file! + // compare version number + if ( fileid[2] != appversion ) { + sprintf( errormessage, "incompatible file, use %s v%i.%i", + appname, fileid[2] / 10, fileid[2] % 10 ); + errorlevel = 2; + return false; + } + // file is .par and compatible + filetype = F_PAR; + // create filenames + if ( !pipe_on ) { + cmpfilename = (char*) calloc( strlen( filename ) + 1, sizeof( char ) ); + strcpy( cmpfilename, filename ); + if ( uncfilename != NULL ) { + // ugly fix for path names in drag and drop + if ( strrchr( uncfilename, '.' ) != NULL ) { + uncfilename = ( overwrite ) ? + create_filename( filename, strrchr( uncfilename, '.' ) + 1 ) : + unique_filename( filename, strrchr( uncfilename, '.' ) + 1 ); + } else { + uncfilename = ( overwrite ) ? + create_filename( filename, NULL ) : + unique_filename( filename, NULL ); + } + // also, making full file name redundant + /*if ( !overwrite ) while ( file_exists( uncfilename ) ) { + uncfilename = (char*) realloc( uncfilename, strlen( uncfilename ) + 2 ); + add_underscore( uncfilename ); + }*/ + } else { + uncfilename = ( overwrite ) ? + create_filename( filename, (char*) unc_ext ) : + unique_filename( filename, (char*) unc_ext ); + } + } + else { + free( uncfilename ); + uncfilename = create_filename( "STDOUT", NULL ); + cmpfilename = create_filename( "STDIN", NULL ); + } + // open output stream, check for errors + str_out = new iostream( (void*) uncfilename, ( !pipe_on ) ? 0 : 2, 0, 1 ); + if ( str_out->chkerr() ) { + sprintf( errormessage, FWR_ERRMSG ); + errorlevel = 2; + return false; + } + break; + } + + // filetype is unknown, or compression is forced + if ( filetype == F_UNK ) { + // free uncompressed file name again + if ( uncfilename != NULL ) free( uncfilename ); uncfilename = NULL; + // create filenames + if ( !pipe_on ) { + uncfilename = (char*) calloc( strlen( filename ) + 1, sizeof( char ) ); + strcpy( uncfilename, filename ); + cmpfilename = ( overwrite ) ? + create_filename( filename, (char*) cmp_ext ) : + unique_filename( filename, (char*) cmp_ext ); + } + else { + uncfilename = create_filename( "STDIN", NULL ); + cmpfilename = create_filename( "STDOUT", NULL ); + } + // open output stream, check for errors + str_out = new iostream( (void*) cmpfilename, ( !pipe_on ) ? 0 : 2, 0, 1 ); + if ( str_out->chkerr() ) { + sprintf( errormessage, FWR_ERRMSG ); + errorlevel = 2; + return false; + } + // get uncompressed file size + uncfilesize = str_in->getsize(); + } + + // rewind (need to start from the beginning) + if ( str_in->rewind() != 0 ) { + sprintf( errormessage, FRD_ERRMSG ); + errorlevel = 2; + return false; + } + + + return true; +} +#endif + + +/* ----------------------------------------------- + swap streams / init verification + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN bool swap_streams( void ) +{ + // store input stream + str_str = str_in; + str_str->rewind(); + + // replace input stream by output stream / switch mode for reading + str_in = str_out; + str_in->switch_mode(); + + // open new stream for output / check for errors + str_out = new iostream( NULL, 1, 0, 1 ); + if ( str_out->chkerr() ) { + sprintf( errormessage, "error opening comparison stream" ); + errorlevel = 2; + return false; + } + + + return true; +} +#endif + + +/* ----------------------------------------------- + comparison between input & output + ----------------------------------------------- */ +#if !defined( BUILD_LIB ) +INTERN bool compare_output( void ) +{ + unsigned char* buff_ori; + unsigned char* buff_cmp; + int bsize = 1024; + int dsize; + int i, b; + + + // init buffer arrays + buff_ori = ( unsigned char* ) calloc( bsize, sizeof( char ) ); + buff_cmp = ( unsigned char* ) calloc( bsize, sizeof( char ) ); + if ( ( buff_ori == NULL ) || ( buff_cmp == NULL ) ) { + if ( buff_ori != NULL ) free( buff_ori ); + if ( buff_cmp != NULL ) free( buff_cmp ); + sprintf( errormessage, MEM_ERRMSG ); + errorlevel = 2; + return false; + } + + // switch output stream mode / check for stream errors + str_out->switch_mode(); + while ( true ) { + if ( str_out->chkerr() ) + sprintf( errormessage, "error in comparison stream" ); + else if ( str_in->chkerr() ) + sprintf( errormessage, "error in output stream" ); + else if ( str_str->chkerr() ) + sprintf( errormessage, "error in input stream" ); + else break; + errorlevel = 2; + return false; + } + + // compare sizes + dsize = str_str->getsize(); + /*if ( str_out->getsize() != dsize ) { + sprintf( errormessage, "file sizes do not match" ); + errorlevel = 2; + return false; + }*/ + + // compare files byte by byte + for ( i = 0; i < dsize; i++ ) { + b = i % bsize; + if ( b == 0 ) { + str_str->read( buff_ori, sizeof( char ), bsize ); + str_out->read( buff_cmp, sizeof( char ), bsize ); + } + if ( buff_ori[ b ] != buff_cmp[ b ] ) { + sprintf( errormessage, "difference found at 0x%X", i ); + errorlevel = 2; + return false; + } + } + + + return true; +} +#endif + + +/* ----------------------------------------------- + set each variable to its initial value + ----------------------------------------------- */ + +INTERN bool reset_buffers( void ) +{ + // --- restore original settings --- + model_order = stored_order; + + + return true; +} + + +/* ----------------------------------------------- + decide order for statistical model + ----------------------------------------------- */ + +INTERN bool decide_model_order( void ) +{ + double cost[ MAX_ORDER + 1 ]; + unsigned char lbyte[ MAX_ORDER + 1 ]; + unsigned char byte; + model_s* model; + int o, p; + int i; + + + // calculate cost for CHECK_BYTES and each order + for ( o = 0; o <= MAX_ORDER; o++ ) { + // preparations + model = INIT_MODEL_S( 256, 256, o ); + memset( lbyte, 0, MAX_ORDER + 1 ); + str_in->rewind(); + cost[ o ] = 0; + // main testing routine + for ( p = 0; p < CHECK_BYTES; p++ ) { + if ( str_in->read( &byte, 1, 1 ) != 1 ) break; + // context shifting + for ( i = o-1; i >= 0; i-- ) + model->shift_context( lbyte[i] ); + // cost count + cost[ o ] += cost_count_ari( model, byte ); + // context update + for ( i = 1; i < o; i++ ) + lbyte[i] = lbyte[i-1]; + lbyte[0] = byte; + } + // clean up + delete( model ); + } + + // rewind (need to start from the beginning) + if ( str_in->rewind() != 0 ) { + sprintf( errormessage, FRD_ERRMSG ); + errorlevel = 2; + return false; + } + + // find the best one + if ( stored_order == -1 ) for ( model_order = 0, o = 1; o <= MAX_ORDER; o++ ) + if ( cost[ model_order ] > cost[ o ] ) model_order = o; + + // check for incompressible files + if ( (cost[ model_order ]/8) >= p ) { + sprintf( errormessage, "file seems to be incompressible" ); + errorlevel = 1; + } + + + return true; +} + + +/* ----------------------------------------------- + encode one file + ----------------------------------------------- */ + +INTERN bool encode_file( void ) +{ + // --- write PAR header --- + str_out->write( (void*) cmp_magic, 1, 2 ); + str_out->write( (void*) &appversion, 1, 1 ); + if ( !write_par_header() ) return false; + + // --- encode file --- + if ( !endecode_file( true ) ) return false; + + // --- get compressed file size --- + cmpfilesize = str_out->getsize(); + + + return true; +} + + +/* ----------------------------------------------- + decode one file + ----------------------------------------------- */ + +INTERN bool decode_file( void ) +{ + unsigned char byte; + + // --- get compressed file size --- + cmpfilesize = str_in->getsize(); + + // --- read PAR header again --- + str_in->read( (void*) &byte, 1, 1 ); // skip byte 0 + str_in->read( (void*) &byte, 1, 1 ); // skip byte 1 + str_in->read( (void*) &byte, 1, 1 ); // skip byte 2 + if ( !read_par_header() ) { + sprintf( errormessage, "this should not have happened :-(" ); + errorlevel = 2; + return false; + } + + // --- decode file --- + if ( !endecode_file( false ) ) return false; + + + return true; +} + +/* ----------------------- End of main functions -------------------------- */ + +/* ----------------------- Begin of other coding functions -------------------------- */ + + +/* ----------------------------------------------- + check par header, extract uncompressed name + ----------------------------------------------- */ +INTERN inline bool check_par_header( void ) +{ + unsigned char hash = 0x00; + unsigned char byte; + char* fn; + int i; + + + for ( i = 0; i < 5; i++ ) { + if ( str_in->read( (void*) &byte, 1, 1 ) != 1 ) return false; + hash = pearson_hash[ byte ^ hash ]; + } + + // fetch file name, followed by 0x00, do hashing + if ( str_in->read( (void*) &byte, 1, 1 ) != 1 ) return false; + if ( byte != 0x00 ) { + uncfilename = ( char* ) calloc( 256 + 1, sizeof( char ) ); // !!! + fn = uncfilename; hash = pearson_hash[ byte ^ hash ]; + for ( (*fn++) = byte, i = 1; i < 256; i++, fn++ ) { + if ( str_in->read( (void*) fn, 1, 1 ) != 1 ) return false; + hash = pearson_hash[ (*fn) ^ hash ]; + if ( (*fn) == 0x00 ) break; + } + if ( i == 256 ) return false; + } else hash = pearson_hash[ hash ]; + + // check hash + if ( str_in->read( (void*) &byte, 1, 1 ) != 1 ) return false; + if ( hash != byte ) return false; + + + // success! + return true; +} + + +/* ----------------------------------------------- + read/check header of compressed file + ----------------------------------------------- */ +INTERN inline bool read_par_header( void ) +{ + unsigned char nbyte[4] = { 0 }; + unsigned char hash = 0x00; + unsigned char byte; + int i; + + + // read model_order, do hashing + model_order = 0; + if ( str_in->read( &model_order, 1, 1 ) != 1 ) return false; + hash = pearson_hash[ model_order ^ hash ]; + + // read number of bytes, do hashing + if ( str_in->read( (void*) nbyte, 1, 4 ) != 4 ) return false; + for ( i = 0; i < 4; i++ ) hash = pearson_hash[ nbyte[i] ^ hash ]; + + // only check file name followed by 0x00, do hashing + for ( i = 0; i < 256; i++ ) { + if ( str_in->read( (void*) &byte, 1, 1 ) != 1 ) return false; + hash = pearson_hash[ byte ^ hash ]; + if ( byte == 0x00 ) break; + } + if ( i == 256 ) return false; + + // check hash + if ( str_in->read( (void*) &byte, 1, 1 ) != 1 ) return false; + if ( hash != byte ) return false; + + // convert number of bytes from little endian + uncfilesize = 0; + uncfilesize |= nbyte[0] << 24; + uncfilesize |= nbyte[1] << 16; + uncfilesize |= nbyte[2] << 8; + uncfilesize |= nbyte[3] << 0; + + + // success! + return true; +} + + +/* ----------------------------------------------- + write header for compressed file + ----------------------------------------------- */ +INTERN inline bool write_par_header( void ) +{ + unsigned char nbyte[4] = { 0 }; + unsigned char hash = 0x00; + unsigned char zero = 0x00; + char* fn; + int i; + + + // convert number of bytes to little endian + nbyte[0] = ( uncfilesize >> 24 ) & 0xFF; + nbyte[1] = ( uncfilesize >> 16 ) & 0xFF; + nbyte[2] = ( uncfilesize >> 8 ) & 0xFF; + nbyte[3] = ( uncfilesize >> 0 ) & 0xFF; + + // write coding parameters, do hashing + str_out->write( &model_order, 1, 1 ); + hash = pearson_hash[ model_order ^ hash ]; + + // write number of bytes, do hashing + str_out->write( (void*) nbyte, 1, 4 ); + for ( i = 0; i < 4; i++ ) hash = pearson_hash[ nbyte[i] ^ hash ]; + + // write uncompressed file name, do hashing + if ( store_name ) { + // get filename without path + if ( strrchr( uncfilename, '/' ) != NULL ) { + fn = strrchr( uncfilename, '/' ) + 1; + if ( strrchr( fn, '\\' ) != NULL ) + fn = strrchr( fn, '\\' ) + 1; + } else if ( strrchr( uncfilename, '\\' ) != NULL ) + fn = strrchr( uncfilename, '\\' ) + 1; + else fn = uncfilename; + // store filename, do hashing + str_out->write( (void*) fn, 1, strlen( fn ) + 1 ); + for ( ; (*fn) != 0x00; fn++ ) + hash = pearson_hash[ (*fn) ^ hash ]; + } else str_out->write( (void*) &zero, 1, 1 ); + hash = pearson_hash[ hash ]; + + // write hash + str_out->write( (void*) &hash, 1, 1 ); + + + // success! + return true; +} + + +/* ----------------------------------------------- + encode or decode file + ----------------------------------------------- */ +INTERN bool endecode_file( bool encoding ) { + // this will either encode or decode one file + // decision is based on the file type + aricoder* coder; + model_s* model; + unsigned char lbyte[ MAX_ORDER + 1 ]; + unsigned char byte; + int p, i; + + + // --- preparations --- + + // init aricoder for encoding/decoding + coder = ( encoding ) ? + new aricoder( str_out, 1 ) : new aricoder( str_in, 0 ); + + // init statistical model + model = INIT_MODEL_S( 256, 256, model_order ); + + // memset last byte + memset( lbyte, 0, MAX_ORDER + 1 ); + + + // --- main encoding/decoding routine --- + + // main routine + for ( p = 0; p < uncfilesize; p++ ) { + // context shifting + for ( i = model_order-1; i >= 0; i-- ) + model->shift_context( lbyte[i] ); + + // actual encoding / decoding + if ( encoding ) { // encoding / loop independent condition + str_in->read( &byte, 1, 1 ); + encode_ari( coder, model, byte ); + } else { // decoding + byte = decode_ari( coder, model ); + str_out->write( &byte, 1, 1 ); + } + + // context update + for ( i = 1; i < model_order; i++ ) + lbyte[i] = lbyte[i-1]; + lbyte[0] = byte; + } + + + // --- cleanup --- + + // free coder and models + delete( coder ); + delete( model ); + + + return true; +} + +/* ----------------------------------------------- + model_s cost count + ----------------------------------------------- */ +INTERN inline double cost_count_ari( model_s* model, int c ) +{ + static symbol s; + static int esc; + double cost = 0; + + do { + esc = model->convert_int_to_symbol( c, &s ); + cost -= log2( (double) (s.high_count - s.low_count) / (double) s.scale ); + } while ( esc ); + model->update_model( c ); + + return cost; +} + +/* ----------------------- End of other coding functions -------------------------- */ + +/* ----------------------- Begin of miscellaneous helper functions -------------------------- */ + + +/* ----------------------------------------------- + displays progress bar on screen + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline void progress_bar( int current, int last ) +{ + int barpos = ( ( current * BARLEN ) + ( last / 2 ) ) / last; + int i; + + + // generate progress bar + fprintf( msgout, "[" ); + #if defined(_WIN32) + for ( i = 0; i < barpos; i++ ) + fprintf( msgout, "\xFE" ); + #else + for ( i = 0; i < barpos; i++ ) + fprintf( msgout, "X" ); + #endif + for ( ; i < BARLEN; i++ ) + fprintf( msgout, " " ); + fprintf( msgout, "]" ); +} +#endif + +/* ----------------------------------------------- + creates filename, callocs memory for it + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline char* create_filename( const char* base, const char* extension ) +{ + int len = strlen( base ) + ( ( extension == NULL ) ? 0 : strlen( extension ) + 1 ) + 1; + char* filename = (char*) calloc( len, sizeof( char ) ); + + // create a filename from base & extension + strcpy( filename, base ); + set_extension( filename, extension ); + + return filename; +} +#endif + +/* ----------------------------------------------- + creates filename, callocs memory for it + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline char* unique_filename( const char* base, const char* extension ) +{ + int len = strlen( base ) + ( ( extension == NULL ) ? 0 : strlen( extension ) + 1 ) + 1; + char* filename = (char*) calloc( len, sizeof( char ) ); + + // create a unique filename using underscores + strcpy( filename, base ); + set_extension( filename, extension ); + while ( file_exists( filename ) ) { + len += sizeof( char ); + filename = (char*) realloc( filename, len ); + add_underscore( filename ); + } + + return filename; +} +#endif + +/* ----------------------------------------------- + changes extension of filename + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline void set_extension( const char* filename, const char* extension ) +{ + char* extstr; + + // find position of extension in filename + extstr = ( strrchr( filename, '.' ) == NULL ) ? + strrchr( filename, '\0' ) : strrchr( filename, '.' ); + + // set new extension + if ( extension != NULL ) { + (*extstr++) = '.'; + strcpy( extstr, extension ); + } + else + (*extstr) = '\0'; +} +#endif + +/* ----------------------------------------------- + adds underscore after filename + ----------------------------------------------- */ +#if !defined(BUILD_LIB) +INTERN inline void add_underscore( char* filename ) +{ + char* tmpname = (char*) calloc( strlen( filename ) + 1, sizeof( char ) ); + char* extstr; + + // copy filename to tmpname + strcpy( tmpname, filename ); + // search extension in filename + extstr = strrchr( filename, '.' ); + + // add underscore before extension + if ( extstr != NULL ) { + (*extstr++) = '_'; + strcpy( extstr, strrchr( tmpname, '.' ) ); + } + else + sprintf( filename, "%s_", tmpname ); + + // free memory + free( tmpname ); +} +#endif + +/* ----------------------------------------------- + checks if a file exists + ----------------------------------------------- */ +INTERN inline bool file_exists( const char* filename ) +{ + // needed for both, executable and library + FILE* fp = fopen( filename, "rb" ); + + if ( fp == NULL ) return false; + else { + fclose( fp ); + return true; + } +} + +/* ----------------------- End of miscellaneous helper functions -------------------------- */ + +/* ----------------------- Begin of developers functions -------------------------- */ + + +#if !defined(BUILD_LIB) && defined(DEV_BUILD) +/* ----------------------------------------------- + Writes error info file + ----------------------------------------------- */ +INTERN bool write_errfile( void ) +{ + FILE* fp; + char* fn; + + + // return immediately if theres no error + if ( errorlevel == 0 ) return true; + + // create filename based on errorlevel + if ( errorlevel == 1 ) { + fn = create_filename( filelist[ file_no ], "wrn.nfo" ); + } + else { + fn = create_filename( filelist[ file_no ], "err.nfo" ); + } + + // open file for output + fp = fopen( fn, "w" ); + if ( fp == NULL ){ + sprintf( errormessage, FWR_ERRMSG ); + errorlevel = 2; + return false; + } + free( fn ); + + // write status and errormessage to file + fprintf( fp, "--> error (level %i) in file \"%s\" <--\n", errorlevel, filelist[ file_no ] ); + fprintf( fp, "\n" ); + // write error specification to file + fprintf( fp, " %s -> %s:\n", get_status( errorfunction ), + ( errorlevel == 1 ) ? "warning" : "error" ); + fprintf( fp, " %s\n", errormessage ); + + // done, close file + fclose( fp ); + + + return true; +} +#endif + +/* ----------------------- End of developers functions -------------------------- */ + +/* ----------------------- End of file -------------------------- */ diff --git a/contrib/preflate/packARI/source/packaridll.h b/contrib/preflate/packARI/source/packaridll.h new file mode 100644 index 0000000..26f654a --- /dev/null +++ b/contrib/preflate/packARI/source/packaridll.h @@ -0,0 +1,37 @@ +// packARIdll.h - function import declarations for the packARI DLL +#define IMPORT __declspec( dllimport ) + +/* ----------------------------------------------- + function declarations: library only functions + ----------------------------------------------- */ + +IMPORT bool parlib_convert_stream2stream( char* msg ); +IMPORT bool parlib_convert_file2file( char* in, char* out, char* msg ); +IMPORT bool parlib_convert_stream2mem( unsigned char** out_file, unsigned int* out_size, char* msg ); +IMPORT void parlib_init_streams( void* in_src, int in_type, int in_size, void* out_dest, int out_type ); +IMPORT void parlib_force_encoding( bool setting ); +IMPORT const char* parlib_version_info( void ); +IMPORT const char* parlib_short_name( void ); + +/* a short reminder about input/output stream types + for the parlib_init_streams() function + + if input is file + ---------------- + in_scr -> name of input file + in_type -> 0 + in_size -> ignore + + if input is memory + ------------------ + in_scr -> array containg data + in_type -> 1 + in_size -> size of data array + + if input is *FILE (f.e. stdin) + ------------------------------ + in_src -> stream pointer + in_type -> 2 + in_size -> ignore + + vice versa for output streams! */ diff --git a/contrib/preflate/packARI/source/packarilib.h b/contrib/preflate/packARI/source/packarilib.h new file mode 100644 index 0000000..caca6ad --- /dev/null +++ b/contrib/preflate/packARI/source/packarilib.h @@ -0,0 +1,41 @@ +// packARIlib.h - function declarations for the packARI library +#if defined BUILD_DLL + #define EXPORT __declspec( dllexport ) +#else + #define EXPORT extern +#endif + +/* ----------------------------------------------- + function declarations: library only functions + ----------------------------------------------- */ + +EXPORT bool parlib_convert_stream2stream( char* msg ); +EXPORT bool parlib_convert_file2file( char* in, char* out, char* msg ); +EXPORT bool parlib_convert_stream2mem( unsigned char** out_file, unsigned int* out_size, char* msg ); +EXPORT void parlib_init_streams( void* in_src, int in_type, int in_size, void* out_dest, int out_type ); +EXPORT void parlib_force_encoding( bool setting ); +EXPORT const char* parlib_version_info( void ); +EXPORT const char* parlib_short_name( void ); + +/* a short reminder about input/output stream types + for the parlib_init_streams() function + + if input is file + ---------------- + in_scr -> name of input file + in_type -> 0 + in_size -> ignore + + if input is memory + ------------------ + in_scr -> array containg data + in_type -> 1 + in_size -> size of data array + + if input is *FILE (f.e. stdin) + ------------------------------ + in_src -> stream pointer + in_type -> 2 + in_size -> ignore + + vice versa for output streams! */ diff --git a/contrib/preflate/packARI/source/paritbl.h b/contrib/preflate/packARI/source/paritbl.h new file mode 100644 index 0000000..da8cff9 --- /dev/null +++ b/contrib/preflate/packARI/source/paritbl.h @@ -0,0 +1,48 @@ +/* ----------------------------------------------- + setting for packARI + ----------------------------------------------- */ + +// !EDIT WITH CAUTION! +// each change may lead to incompatibilities with previous version + +// action defines +#define A_COMPRESS 1 + +// file type defines +#define F_UNK 1 +#define F_PAR 2 + +// compression parameters (tweaking possible) +#define MAX_ORDER 3 +#define CHECK_BYTES ( 1 << 14 ) + +// other setting +#define ANALYSIS_CSV "par_analysis.csv" + + +/* ----------------------------------------------- + pearson hashing table + ----------------------------------------------- */ + +// copied from Table 1 in: +// Pearson, Peter K. (June 1990), "Fast Hashing of Variable-Length Text Strings", +// Communications of the ACM 33 (6): 677, doi:10.1145/78973.78978 +static int pearson_hash[ 256 ] = +{ + 1, 87, 49, 12, 176, 178, 102, 166, 121, 193, 6, 84, 249, 230, 44, 163, + 14, 197, 213, 181, 161, 85, 218, 80, 64, 239, 24, 226, 236, 142, 38, 200, + 110, 177, 104, 103, 141, 253, 255, 50, 77, 101, 81, 18, 45, 96, 31, 222, + 25, 107, 190, 70, 86, 237, 240, 34, 72, 242, 20, 214, 244, 227, 149, 235, + 97, 234, 57, 22, 60, 250, 82, 175, 208, 5, 127, 199, 111, 62, 135, 248, + 174, 169, 211, 58, 66, 154, 106, 195, 245, 171, 17, 187, 182, 179, 0, 243, + 132, 56, 148, 75, 128, 133, 158, 100, 130, 126, 91, 13, 153, 246, 216, 219, + 119, 68, 223, 78, 83, 88, 201, 99, 122, 11, 92, 32, 136, 114, 52, 10, + 138, 30, 48, 183, 156, 35, 61, 26, 143, 74, 251, 94, 129, 162, 63, 152, + 170, 7, 115, 167, 241, 206, 3, 150, 55, 59, 151, 220, 90, 53, 23, 131, + 125, 173, 15, 238, 79, 95, 89, 16, 105, 137, 225, 224, 217, 160, 37, 123, + 118, 73, 2, 157, 46, 116, 9, 145, 134, 228, 207, 212, 202, 215, 69, 229, + 27, 188, 67, 124, 168, 252, 42, 4, 29, 108, 21, 247, 19, 205, 39, 203, + 233, 40, 186, 147, 198, 192, 155, 33, 164, 191, 98, 204, 165, 180, 117, 76, + 140, 36, 210, 172, 41, 54, 159, 8, 185, 232, 113, 196, 231, 47, 146, 120, + 51, 65, 28, 144, 254, 221, 93, 189, 194, 139, 112, 43, 71, 109, 184, 209 +}; diff --git a/contrib/preflate/preflate.h b/contrib/preflate/preflate.h new file mode 100644 index 0000000..a7caaaf --- /dev/null +++ b/contrib/preflate/preflate.h @@ -0,0 +1,21 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_H +#define PREFLATE_H + +#include "preflate_decoder.h" +#include "preflate_reencoder.h" + +#endif /* PREFLATE_H */ diff --git a/contrib/preflate/preflate_block_decoder.cpp b/contrib/preflate/preflate_block_decoder.cpp new file mode 100644 index 0000000..91bbc60 --- /dev/null +++ b/contrib/preflate/preflate_block_decoder.cpp @@ -0,0 +1,196 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "preflate_block_decoder.h" +#include "preflate_block_trees.h" +#include "support/bit_helper.h" + +PreflateBlockDecoder::PreflateBlockDecoder( + BitInputStream& input, + OutputCacheStream& output) + : _input(input) + , _output(output) + , _errorCode(OK) + , _dynamicLitLenDecoder(nullptr, 0, false, 0) + , _dynamicDistDecoder(nullptr, 0, false, 0) { +} + +bool PreflateBlockDecoder::_error(const ErrorCode code) { + _errorCode = code; + return false; +} + +bool PreflateBlockDecoder::readBlock(PreflateTokenBlock &block, bool &last) { + block.uncompressedStartPos = _output.cacheEndPos(); + int32_t earliest_reference = INT32_MAX, curPos = 0; + + if (_input.eof()) { + return false; + } + + last = _readBit() != 0; + unsigned char mode = _readBits(2); + switch (mode) { + default: + return false; + case 0: { + block.type = PreflateTokenBlock::STORED; + if (!_checkLastBitsOfByte()) { + return _error(STORED_BLOCK_PADDING_MISMATCH); + } + _skipToByte(); + size_t len = _readBits(16); + size_t ilen = _readBits(16); + if ((len ^ ilen) != 0xffff) { + return _error(STORED_BLOCK_LEN_MISMATCH); + } + block.uncompressedLen = len; + block.contextLen = 0; + return _input.copyBytesTo(_output, len) == len; + } + case 1: + case 2: + if (mode == 1) { + block.type = PreflateTokenBlock::STATIC_HUFF; + _setupStaticTables(); + } else { + block.type = PreflateTokenBlock::DYNAMIC_HUFF; + if (!_readDynamicTables(block)) { + return false; + } + } + while (true) { + if (_input.eof()) { + return false; + } + unsigned litLen = _litLenDecoder->decode(_input); + if (litLen < 256) { + _writeLiteral(litLen); + block.tokens.push_back(PreflateToken(PreflateToken::LITERAL)); + curPos++; + } else if (litLen == 256) { + block.uncompressedLen = _output.cacheEndPos() - block.uncompressedStartPos; + block.contextLen = -earliest_reference; + return true; + } else if (litLen <= PreflateConstants::L_CODES) { + unsigned lcode = litLen - PreflateConstants::LITERALS - 1; + unsigned len = PreflateConstants::MIN_MATCH + + PreflateConstants::lengthBaseTable[lcode] + + _readBits(PreflateConstants::lengthExtraTable[lcode]); + // todo: handle second version of len 258 + if (len == 258 && lcode != PreflateConstants::L_CODES - PreflateConstants::LITERALS - 2) { + return _error(BADLY_CODED_MAX_LENGTH); + } + unsigned dcode = _distDecoder->decode(_input); + if (dcode > PreflateConstants::D_CODES) { + return false; + } + unsigned dist = 1 + + PreflateConstants::distBaseTable[dcode] + + _readBits(PreflateConstants::distExtraTable[dcode]); + if (dist > _output.cacheEndPos()) { + return false; + } + _writeReference(dist, len); + block.tokens.push_back(PreflateToken(PreflateToken::REFERENCE, len, dist)); + earliest_reference = std::min(earliest_reference, curPos - (int32_t)dist); + curPos += len; + } else { + return false; + } + } + } +} + +void PreflateBlockDecoder::_setupStaticTables() { + _litLenDecoder = PreflateBlockTrees::staticLitLenTreeDecoder(); + _distDecoder = PreflateBlockTrees::staticDistTreeDecoder(); +} + +bool PreflateBlockDecoder::_readDynamicTables(PreflateTokenBlock& block) { + block.nlen = PreflateConstants::LITERALS + 1 + _readBits(5); + block.ndist = 1 + _readBits(5); + block.ncode = 4 + _readBits(4); + if (block.nlen > PreflateConstants::L_CODES || block.ndist > PreflateConstants::D_CODES) { + return false; + } + block.treecodes.clear(); + block.treecodes.reserve(block.nlen + block.ndist + block.ncode); + + unsigned char tcBitLengths[PreflateConstants::BL_CODES]; + unsigned char ldBitLengths[PreflateConstants::LD_CODES]; + memset(tcBitLengths, 0, sizeof(tcBitLengths)); + memset(ldBitLengths, 0, sizeof(ldBitLengths)); + for (unsigned i = 0, n = block.ncode; i < n; ++i) { + unsigned char tc = _readBits(3); + block.treecodes.push_back(tc); + tcBitLengths[PreflateConstants::treeCodeOrderTable[i]] = tc; + } + HuffmanDecoder tcTree(tcBitLengths, PreflateConstants::BL_CODES, true, 7); + if (tcTree.error()) { + return false; + } + for (unsigned i = 0, n = block.nlen + block.ndist; i < n; ++i) { + unsigned char code = tcTree.decode(_input); + if (code > 18) { + return false; + } + block.treecodes.push_back(code); + if (code < 16) { + ldBitLengths[i] = code; + continue; + } + unsigned char len = 0, tocopy = 0; + switch (code) { + case 16: + if (i == 0) { + return false; + } + tocopy = ldBitLengths[i - 1]; + len = 3 + _readBits(2); + break; + case 17: + tocopy = 0; + len = 3 + _readBits(3); + break; + case 18: + tocopy = 0; + len = 11 + _readBits(7); + break; + } + if (i + len > n) { + return false; + } + block.treecodes.push_back(len); + memset(ldBitLengths + i, tocopy, len); + i += len - 1; + } + if (!ldBitLengths[256]) { + return false; + } + _dynamicLitLenDecoder = HuffmanDecoder(ldBitLengths, block.nlen, true, 15); + if (_dynamicLitLenDecoder.error()) { + return false; + } + _litLenDecoder = &_dynamicLitLenDecoder; + + _dynamicDistDecoder = HuffmanDecoder(ldBitLengths + block.nlen, block.ndist, true, 15); + if (_dynamicDistDecoder.error()) { + return false; + } + _distDecoder = &_dynamicDistDecoder; + return true; +} diff --git a/contrib/preflate/preflate_block_decoder.h b/contrib/preflate/preflate_block_decoder.h new file mode 100644 index 0000000..af246a0 --- /dev/null +++ b/contrib/preflate/preflate_block_decoder.h @@ -0,0 +1,83 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_BLOCK_DECODER_H +#define PREFLATE_BLOCK_DECODER_H + +#include "preflate_constants.h" +#include "preflate_hash_chain.h" +#include "preflate_input.h" +#include "preflate_token.h" +#include "support/bitstream.h" +#include "support/huffman_decoder.h" +#include "support/outputcachestream.h" + +class PreflateBlockDecoder { +public: + enum ErrorCode { + OK, + STORED_BLOCK_LEN_MISMATCH, + STORED_BLOCK_PADDING_MISMATCH, + BADLY_CODED_MAX_LENGTH + }; + PreflateBlockDecoder(BitInputStream& input, + OutputCacheStream& output); + + bool readBlock(PreflateTokenBlock&, bool& last); + ErrorCode status() const { + return _errorCode; + } + +private: + bool _error(const ErrorCode); + + unsigned char _readBit() { + return _input.get(1); + } + unsigned _readBits(const unsigned bits) { + return _input.get(bits); + } + void _skipToByte() { + _input.skipToByte(); + } + bool _checkLastBitsOfByte() { + return _input.checkLastBitsOfByteAreZero(); + } + void _writeLiteral(const unsigned char l) { + _output.write(&l, 1); + } + void _writeReference(const size_t dist, const size_t len) { + _output.reserve(len); + if (len <= dist) { + _output.write(_output.cacheEnd() - dist, len); + } else { + const uint8_t* ptr = _output.cacheEnd() - dist; + for (size_t i = 0; i < len; ++i) { + _output.write(&ptr[i], 1); + } + } + } + void _setupStaticTables(); + bool _readDynamicTables(PreflateTokenBlock&); + + BitInputStream& _input; + OutputCacheStream& _output; + ErrorCode _errorCode; + const HuffmanDecoder* _litLenDecoder; + const HuffmanDecoder* _distDecoder; + HuffmanDecoder _dynamicLitLenDecoder; + HuffmanDecoder _dynamicDistDecoder; +}; + +#endif /* PREFLATE_BLOCK_DECODER_H */ diff --git a/contrib/preflate/preflate_block_reencoder.cpp b/contrib/preflate/preflate_block_reencoder.cpp new file mode 100644 index 0000000..a877801 --- /dev/null +++ b/contrib/preflate/preflate_block_reencoder.cpp @@ -0,0 +1,188 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "preflate_block_reencoder.h" +#include "preflate_block_trees.h" +#include "support/bit_helper.h" + +PreflateBlockReencoder::PreflateBlockReencoder( + BitOutputStream& bos, + const std::vector& uncompressedData) + : _output(bos) + , _uncompressedData(uncompressedData) + , _uncompressedDataPos(0) + , _errorCode(OK) + , _dynamicLitLenEncoder(nullptr, 0, false) + , _dynamicDistEncoder(nullptr, 0, false) { +} + +bool PreflateBlockReencoder::_error(const ErrorCode code) { + _errorCode = code; + return false; +} + +void PreflateBlockReencoder::_setupStaticTables() { + _litLenEncoder = PreflateBlockTrees::staticLitLenTreeEncoder(); + _distEncoder = PreflateBlockTrees::staticDistTreeEncoder(); +} + +bool PreflateBlockReencoder::_buildAndWriteDynamicTables(const PreflateTokenBlock& block) { + if (block.ncode < 4 || block.ncode > PreflateConstants::BL_CODES + || block.treecodes.size() < (size_t)block.ncode + || block.nlen < PreflateConstants::LITERALS + 1 + || block.nlen > PreflateConstants::L_CODES + || block.ndist < 1 || block.ndist > PreflateConstants::D_CODES) { + return _error(TREE_OUT_OF_RANGE); + } + unsigned char tcBitLengths[PreflateConstants::BL_CODES]; + unsigned char ldBitLengths[PreflateConstants::LD_CODES]; + memset(tcBitLengths, 0, sizeof(tcBitLengths)); + memset(ldBitLengths, 0, sizeof(ldBitLengths)); + + for (unsigned i = 0, n = block.ncode; i < n; ++i) { + unsigned char tc = block.treecodes[i]; + _output.put(tc, 3); + tcBitLengths[PreflateConstants::treeCodeOrderTable[i]] = tc; + } + HuffmanEncoder tcTree(tcBitLengths, PreflateConstants::BL_CODES, true); + if (tcTree.error()) { + return _error(BAD_CODE_TREE); + } + // unpack tree codes + unsigned o = 0, maxo = block.nlen + block.ndist; + for (auto i = block.treecodes.begin() + block.ncode, e = block.treecodes.end(); i != e; ++i) { + unsigned char code = *i; + if (code > 18) { + return _error(BAD_LD_TREE); + } + tcTree.encode(_output, code); + if (code < 16) { + if (o >= maxo) { + return _error(BAD_LD_TREE); + } + ldBitLengths[o++] = code; + continue; + } + if (i + 1 == e) { + return _error(BAD_LD_TREE); + } + if (code == 16 && o == 0) { + return _error(BAD_LD_TREE); + } + unsigned char len = *++i; + unsigned char tocopy = code == 16 ? ldBitLengths[o - 1] : 0; + static unsigned char repExtraBits[3] = {2, 3, 7}; + static unsigned char repOffset[3] = {3, 3, 11}; + _output.put(len - repOffset[code - 16], repExtraBits[code - 16]); + if (o + len > maxo) { + return _error(BAD_LD_TREE); + } + memset(ldBitLengths + o, tocopy, len); + o += len; + } + if (o != maxo) { + return _error(BAD_LD_TREE); + } + if (!ldBitLengths[256]) { + return _error(BAD_LD_TREE); + } + _dynamicLitLenEncoder = HuffmanEncoder(ldBitLengths, block.nlen, true); + if (_dynamicLitLenEncoder.error()) { + return _error(BAD_LD_TREE); + } + _litLenEncoder = &_dynamicLitLenEncoder; + + _dynamicDistEncoder = HuffmanEncoder(ldBitLengths + block.nlen, block.ndist, true); + if (_dynamicDistEncoder.error()) { + return _error(BAD_LD_TREE); + } + _distEncoder = &_dynamicDistEncoder; + return true; +} + +bool PreflateBlockReencoder::_writeTokens(const std::vector& tokens) { + for (size_t i = 0; i < tokens.size(); ++i) { + PreflateToken token = tokens[i]; + if (token.len == 1) { + if (_uncompressedDataPos >= _uncompressedData.size()) { + return _error(LITERAL_OUT_OF_BOUNDS); + } + unsigned char literal = _uncompressedData[_uncompressedDataPos++]; + _litLenEncoder->encode(_output, literal); + } else { + unsigned lencode = PreflateConstants::LCode(token.len); + _litLenEncoder->encode(_output, PreflateConstants::LITERALS + 1 + lencode); + unsigned lenextra = PreflateConstants::lengthExtraTable[lencode]; + if (lenextra) { + _output.put(token.len - PreflateConstants::MIN_MATCH - PreflateConstants::lengthBaseTable[lencode], lenextra); + } + unsigned distcode = PreflateConstants::DCode(token.dist); + _distEncoder->encode(_output, distcode); + unsigned distextra = PreflateConstants::distExtraTable[distcode]; + if (distextra) { + _output.put(token.dist - 1 - PreflateConstants::distBaseTable[distcode], distextra); + } + _uncompressedDataPos += token.len; + } + } + _litLenEncoder->encode(_output, PreflateConstants::LITERALS); + return true; +} + +bool PreflateBlockReencoder::writeBlock(const PreflateTokenBlock& block, bool last) { + if (status() != OK) { + return false; + } + _output.put(last, 1); // + switch (block.type) { + case PreflateTokenBlock::DYNAMIC_HUFF: + _output.put(2, 2); // + _output.put(block.nlen - PreflateConstants::LITERALS - 1, 5); + _output.put(block.ndist - 1, 5); + _output.put(block.ncode - 4, 4); + if (!_buildAndWriteDynamicTables(block)) { + return false; + } + if (!_writeTokens(block.tokens)) { + return false; + } + break; + case PreflateTokenBlock::STATIC_HUFF: + _output.put(1, 2); // + _setupStaticTables(); + if (!_writeTokens(block.tokens)) { + return false; + } + break; + case PreflateTokenBlock::STORED: + _output.put(0, 2); // + _output.fillByte(); + _output.put(block.uncompressedLen, 16); // + _output.put(~block.uncompressedLen, 16); // + if (_uncompressedDataPos + block.uncompressedLen > _uncompressedData.size()) { + return _error(LITERAL_OUT_OF_BOUNDS); + } + for (unsigned i = 0; i < block.uncompressedLen; ++i) { + unsigned char literal = _uncompressedData[_uncompressedDataPos++]; + _output.put(literal, 8); + } + break; + } + return true; +} +void PreflateBlockReencoder::flush() { + _output.flush(); +} diff --git a/contrib/preflate/preflate_block_reencoder.h b/contrib/preflate/preflate_block_reencoder.h new file mode 100644 index 0000000..e8918be --- /dev/null +++ b/contrib/preflate/preflate_block_reencoder.h @@ -0,0 +1,75 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_BLOCK_REENCODER_H +#define PREFLATE_BLOCK_REENCODER_H + +#include "preflate_constants.h" +#include "preflate_token.h" +#include "support/bitstream.h" +#include "support/huffman_encoder.h" + +class PreflateBlockReencoder { +public: + enum ErrorCode { + OK, + LITERAL_OUT_OF_BOUNDS, + TREE_OUT_OF_RANGE, + BAD_CODE_TREE, + BAD_LD_TREE, + }; + /* enum { + BUFSIZE = 1024 + }; + + std::vector output; + unsigned char buffer[BUFSIZE]; + unsigned bufferpos; + unsigned bitbuffer; + unsigned bitbuffersize;*/ + +/* unsigned short litLenDistCodeStorage[PreflateConstants::LD_CODES]; + unsigned short treeCodeStorage[PreflateConstants::BL_CODES]; + unsigned char litLenDistBitStorage[PreflateConstants::LD_CODES]; + unsigned char treeBitStorage[PreflateConstants::BL_CODES]; + const unsigned short *litLenCode, *distCode, *treeCode; + const unsigned char *litLenBits, *distBits, *treeBits;*/ + + PreflateBlockReencoder(BitOutputStream& bos, const std::vector& uncompressedData); + bool writeBlock(const PreflateTokenBlock&, const bool last); + void flush(); + + ErrorCode status() const { + return _errorCode; + } + +private: + bool _error(const ErrorCode); + + void _setupStaticTables(); + bool _buildAndWriteDynamicTables(const PreflateTokenBlock&); + bool _writeTokens(const std::vector& tokens); + + BitOutputStream& _output; + const std::vector& _uncompressedData; + size_t _uncompressedDataPos; + ErrorCode _errorCode; + + const HuffmanEncoder* _litLenEncoder; + const HuffmanEncoder* _distEncoder; + HuffmanEncoder _dynamicLitLenEncoder; + HuffmanEncoder _dynamicDistEncoder; +}; + +#endif /* PREFLATE_BLOCK_REENCODER_H */ diff --git a/contrib/preflate/preflate_block_trees.cpp b/contrib/preflate/preflate_block_trees.cpp new file mode 100644 index 0000000..6f68d60 --- /dev/null +++ b/contrib/preflate/preflate_block_trees.cpp @@ -0,0 +1,65 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "preflate_block_trees.h" +#include "support/bit_helper.h" + +static HuffmanDecoder* staticLitLenDecoder; +static HuffmanDecoder* staticDistDecoder; +static HuffmanEncoder* staticLitLenEncoder; +static HuffmanEncoder* staticDistEncoder; + +static void setLitLenBitLengths(unsigned char(&a)[288]) { + std::fill(a + 0, a + 144, 8); + std::fill(a + 144, a + 256, 9); + std::fill(a + 256, a + 280, 7); + std::fill(a + 280, a + 288, 8); +} +static void setDistBitLengths(unsigned char(&a)[32]) { + std::fill(a, a + 32, 5); +} + +const HuffmanDecoder* PreflateBlockTrees::staticLitLenTreeDecoder() { + if (!staticLitLenDecoder) { + unsigned char l_lengths[288]; + setLitLenBitLengths(l_lengths); + staticLitLenDecoder = new HuffmanDecoder(l_lengths, 288, true, 15); + } + return staticLitLenDecoder; +} +const HuffmanDecoder* PreflateBlockTrees::staticDistTreeDecoder() { + if (!staticDistDecoder) { + unsigned char d_lengths[32]; + setDistBitLengths(d_lengths); + staticDistDecoder = new HuffmanDecoder(d_lengths, 32, true, 15); + } + return staticDistDecoder; +} +const HuffmanEncoder* PreflateBlockTrees::staticLitLenTreeEncoder() { + if (!staticLitLenEncoder) { + unsigned char l_lengths[288]; + setLitLenBitLengths(l_lengths); + staticLitLenEncoder = new HuffmanEncoder(l_lengths, 288, true); + } + return staticLitLenEncoder; +} +const HuffmanEncoder* PreflateBlockTrees::staticDistTreeEncoder() { + if (!staticDistEncoder) { + unsigned char d_lengths[32]; + setDistBitLengths(d_lengths); + staticDistEncoder = new HuffmanEncoder(d_lengths, 32, true); + } + return staticDistEncoder; +} diff --git a/contrib/preflate/preflate_block_trees.h b/contrib/preflate/preflate_block_trees.h new file mode 100644 index 0000000..35cd72a --- /dev/null +++ b/contrib/preflate/preflate_block_trees.h @@ -0,0 +1,32 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_BLOCK_TREES_H +#define PREFLATE_BLOCK_TREES_H + +#include "preflate_constants.h" +#include "preflate_hash_chain.h" +#include "preflate_input.h" +#include "preflate_token.h" +#include "support/huffman_decoder.h" +#include "support/huffman_encoder.h" + +struct PreflateBlockTrees { + static const HuffmanDecoder* staticLitLenTreeDecoder(); + static const HuffmanDecoder* staticDistTreeDecoder(); + static const HuffmanEncoder* staticLitLenTreeEncoder(); + static const HuffmanEncoder* staticDistTreeEncoder(); +}; + +#endif /* PREFLATE_BLOCK_TREES_H */ diff --git a/contrib/preflate/preflate_checker.cpp b/contrib/preflate/preflate_checker.cpp new file mode 100644 index 0000000..b3259de --- /dev/null +++ b/contrib/preflate/preflate_checker.cpp @@ -0,0 +1,264 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "preflate_block_decoder.h" +#include "preflate_block_reencoder.h" +#include "preflate_checker.h" +#include "preflate_parameter_estimator.h" +#include "preflate_statistical_model.h" +#include "preflate_token_predictor.h" +#include "preflate_tree_predictor.h" +#include "preflate_unpack.h" +#include "support/bitstream.h" +#include "support/memstream.h" +#include "support/outputcachestream.h" + +#include + +bool preflate_checker(const std::vector& deflate_raw) { + printf("Checking raw deflate file of size %d\n", (int)deflate_raw.size()); + + std::vector unpacked_output; + std::vector blocks; + if (!preflate_unpack(unpacked_output, blocks, deflate_raw)) { + printf("inflating error (modified zlib)\n"); + return false; + } + printf("Unpacked data has size %d\n", (int)unpacked_output.size()); + MemStream decIn(deflate_raw); + MemStream decUnc; + BitInputStream decInBits(decIn); + OutputCacheStream decOutCache(decUnc); + std::vector blocks2; + PreflateBlockDecoder bdec(decInBits, decOutCache); + if (bdec.status() != PreflateBlockDecoder::OK) { + return false; + } + bool last; + unsigned i = 0; + do { + PreflateTokenBlock newBlock; + bool ok = bdec.readBlock(newBlock, last); + if (!ok) { + printf("inflating error (preflate)\n"); + return false; + } + if ((last && i + 1 != blocks.size()) + || (!last && i + 1 == blocks.size())) { + return false; + } + if (!isEqual(newBlock, blocks[i])) { + return false; + } + blocks2.push_back(newBlock); + ++i; + } while (!last); + decOutCache.flush(); + if (decUnc.data() != unpacked_output) { + for (unsigned i = 0, n = std::min(decUnc.data().size(), unpacked_output.size()); i < n; ++i) { + if (decUnc.data()[i] != unpacked_output[i]) { + printf("xxx %d\n", i); + } + } + return false; + } + + // Encode + PreflateParameters paramsE = estimatePreflateParameters(unpacked_output, blocks); + printf("prediction parameters: w %d, c %d, m %d, zlib %d, farL3M %d, very far M %d, M2S %d, log2CD %d\n", + paramsE.windowBits, paramsE.compLevel, paramsE.memLevel, + paramsE.zlibCompatible, paramsE.farLen3MatchesDetected, + paramsE.veryFarMatchesDetected, paramsE.matchesToStartDetected, + paramsE.log2OfMaxChainDepthM1); + + PreflateStatisticalModel modelE; + memset(&modelE, 0, sizeof(modelE)); + PreflateTokenPredictor tokenPredictorE(paramsE, unpacked_output); + PreflateTreePredictor treePredictorE(unpacked_output); + for (unsigned i = 0, n = blocks.size(); i < n; ++i) { + tokenPredictorE.analyzeBlock(i, blocks[i]); + if (tokenPredictorE.predictionFailure) { + printf("block %d: compress failed token prediction\n", i); + return false; + } + treePredictorE.analyzeBlock(i, blocks[i]); + if (treePredictorE.predictionFailure) { + printf("block %d: compress failed tree prediction\n", i); + return false; + } + tokenPredictorE.updateModel(&modelE, i); + treePredictorE.updateModel(&modelE, i); + } + + modelE.print(); + + PreflateStatisticalEncoder codecE(modelE); + codecE.encodeHeader(); + codecE.encodeParameters(paramsE); + codecE.encodeModel(); + for (unsigned i = 0, n = blocks.size(); i < n; ++i) { + tokenPredictorE.encodeBlock(&codecE, i); + if (tokenPredictorE.predictionFailure) { + printf("block %d: compress failed token encoding\n", i); + return false; + } + treePredictorE.encodeBlock(&codecE, i); + if (treePredictorE.predictionFailure) { + printf("block %d: compress failed tree encoding\n", i); + return false; + } + tokenPredictorE.encodeEOF(&codecE, i, i + 1 == blocks.size()); + } + std::vector preflate_diff = codecE.encodeFinish(); + printf("Prediction diff has size %d\n", (int)preflate_diff.size()); + + // Decode + PreflateStatisticalDecoder codecD(preflate_diff); + if (!codecD.decodeHeader()) { + printf("header decoding failed\n"); + return false; + } + PreflateParameters paramsD; + if (!codecD.decodeParameters(paramsD)) { + printf("parameter decoding failed\n"); + return false; + } + if (paramsD.strategy != paramsE.strategy) { + printf("parameter decoding failed: strategy mismatch\n"); + return false; + } + if (paramsD.huffStrategy != paramsE.huffStrategy) { + printf("parameter decoding failed: huff strategy mismatch\n"); + return false; + } + if (paramsD.windowBits != paramsE.windowBits) { + printf("parameter decoding failed: windowBits mismatch\n"); + return false; + } + if (paramsD.memLevel != paramsE.memLevel) { + printf("parameter decoding failed: memLevel mismatch\n"); + return false; + } + if (paramsD.compLevel != paramsE.compLevel) { + printf("parameter decoding failed: compLevel mismatch\n"); + return false; + } + if (paramsD.zlibCompatible != paramsE.zlibCompatible + || paramsD.farLen3MatchesDetected != paramsE.farLen3MatchesDetected + || paramsD.veryFarMatchesDetected != paramsE.veryFarMatchesDetected + || paramsD.matchesToStartDetected != paramsE.matchesToStartDetected + || paramsD.log2OfMaxChainDepthM1 != paramsE.log2OfMaxChainDepthM1) { + printf("parameter decoding failed: flag mismatch\n"); + return false; + } + + if (!codecD.decodeModel()) { + printf("model decoding failed\n"); + return false; + } + if (!isEqual(*codecD.model, *codecE.model)) { + printf("decoded model differs from original\n"); + return false; + } + + PreflateTokenPredictor tokenPredictorD(paramsD, unpacked_output); + PreflateTreePredictor treePredictorD(unpacked_output); + + MemStream mem; + BitOutputStream bos(mem); + + PreflateBlockReencoder deflater(bos, unpacked_output); + unsigned blockno = 0; + bool eof = true; + do { + if (blockno >= blocks.size()) { + printf("block number too big: org %d, new %d\n", (int)blocks.size(), blockno); + return false; + } + PreflateTokenBlock block = tokenPredictorD.decodeBlock(&codecD); + if (tokenPredictorD.predictionFailure) { + printf("block %d: token uncompress failed\n", blockno); + return false; + } + if (block.type != blocks[blockno].type) { + printf("block %d: type differs: org %d, new %d\n", blockno, blocks[blockno].type, block.type); + return false; + } + for (unsigned i = 0, n = std::min(block.tokens.size(), blocks[blockno].tokens.size()); i < n; ++i) { + PreflateToken orgToken = blocks[blockno].tokens[i]; + PreflateToken newToken = block.tokens[i]; + if (newToken.len != orgToken.len || newToken.dist != orgToken.dist) { + printf("block %d: generated token %d differs: org(%d,%d), new(%d,%d)\n", + blockno, i, orgToken.len, orgToken.dist, newToken.len, newToken.dist); + return false; + } + } + if (block.tokens.size() != blocks[blockno].tokens.size()) { + printf("block %d: differing token count: org %d, new %d\n", + blockno, (int)blocks[blockno].tokens.size(), (int)block.tokens.size()); + return false; + } + + if (!treePredictorD.decodeBlock(block, &codecD)) { + printf("block %d: tree uncompress failed\n", blockno); + return false; + } + if (treePredictorD.predictionFailure) { + printf("block %d: tree uncompress failed\n", blockno); + return false; + } + if (block.type == PreflateTokenBlock::DYNAMIC_HUFF) { + if (block.nlen != blocks[blockno].nlen) { + printf("block %d: literal/len count differs: org %d, new %d\n", + blockno, blocks[blockno].nlen, block.nlen); + return false; + } + if (block.ndist != blocks[blockno].ndist) { + printf("block %d: dist count differs: org %d, new %d\n", + blockno, blocks[blockno].ndist, block.ndist); + return false; + } + if (block.ncode != blocks[blockno].ncode) { + printf("block %d: tree code count differs: org %d, new %d\n", + blockno, blocks[blockno].ncode, block.ncode); + return false; + } + if (block.treecodes != blocks[blockno].treecodes) { + printf("block %d: generated tree codes differs\n", blockno); + return false; + } + } + eof = tokenPredictorD.decodeEOF(&codecD); + deflater.writeBlock(block, eof); + ++blockno; + } while (!eof); + deflater.flush(); + + std::vector deflate_raw_out = mem.extractData(); + for (unsigned i = 0, n = std::min(deflate_raw.size(), deflate_raw_out.size()); i < n; ++i) { + if (deflate_raw[i] != deflate_raw_out[i]) { + printf("created deflate stream differs at offset %d\n", i); + return false; + } + } + if (deflate_raw.size() != deflate_raw_out.size()) { + printf("created deflate streams differs in size: org %d, new %d\n", + (int)deflate_raw.size(), (int)deflate_raw_out.size()); + return false; + } + printf("Success\n"); + return true; +} diff --git a/contrib/preflate/preflate_checker.h b/contrib/preflate/preflate_checker.h new file mode 100644 index 0000000..f1abc9e --- /dev/null +++ b/contrib/preflate/preflate_checker.h @@ -0,0 +1,22 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_CHECKER_H +#define PREFLATE_CHECKER_H + +#include + +bool preflate_checker(const std::vector& deflate_raw); + +#endif /* PREFLATE_CHECKER_H */ diff --git a/contrib/preflate/preflate_complevel_estimator.cpp b/contrib/preflate/preflate_complevel_estimator.cpp new file mode 100644 index 0000000..fcf7910 --- /dev/null +++ b/contrib/preflate/preflate_complevel_estimator.cpp @@ -0,0 +1,195 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "preflate_complevel_estimator.h" +#include "preflate_constants.h" + +PreflateCompLevelEstimatorState::PreflateCompLevelEstimatorState( + const int wbits, + const int mbits, + const std::vector& unpacked_output_, + const std::vector& blocks_) + : predictor(slowHash, slowPreflateParserSettings[5], wbits, mbits) + , slowHash(unpacked_output_, mbits) + , fastL1Hash(unpacked_output_, mbits) + , fastL2Hash(unpacked_output_, mbits) + , fastL3Hash(unpacked_output_, mbits) + , blocks(blocks_) +{ + memset(&info, 0, sizeof(info)); + info.possibleCompressionLevels = (1 << 10) - (1 << 1); +} + +void PreflateCompLevelEstimatorState::updateHash(const unsigned len) { + if (info.possibleCompressionLevels & (1 << 1)) { + fastL1Hash.updateHash(len); + } + if (info.possibleCompressionLevels & (1 << 2)) { + fastL2Hash.updateHash(len); + } + if (info.possibleCompressionLevels & (1 << 3)) { + fastL3Hash.updateHash(len); + } + slowHash.updateHash(len); +} +void PreflateCompLevelEstimatorState::updateOrSkipSingleFastHash( + PreflateHashChainExt& hash, + const unsigned len, + const PreflateParserConfig& config) { + if (len <= config.max_lazy) { + hash.updateHash(len); + } else { + hash.skipHash(len); + } +} + +void PreflateCompLevelEstimatorState::updateOrSkipHash(const unsigned len) { + if (info.possibleCompressionLevels & (1 << 1)) { + updateOrSkipSingleFastHash(fastL1Hash, len, fastPreflateParserSettings[0]); + } + if (info.possibleCompressionLevels & (1 << 2)) { + updateOrSkipSingleFastHash(fastL2Hash, len, fastPreflateParserSettings[1]); + } + if (info.possibleCompressionLevels & (1 << 3)) { + updateOrSkipSingleFastHash(fastL3Hash, len, fastPreflateParserSettings[2]); + } + slowHash.updateHash(len); +} +bool PreflateCompLevelEstimatorState::checkMatchSingleFastHash( + const PreflateToken& token, + const PreflateHashChainExt& hash, + const PreflateParserConfig& config, + const unsigned hashHead) { + unsigned mdepth = predictor.matchDepth(hash.getHead(hashHead), token, hash); + if (mdepth > config.max_chain) { + return false; + } + return true; +} +void PreflateCompLevelEstimatorState::checkMatch(const PreflateToken& token) { + unsigned hashHead = slowHash.curHash(); + if (info.possibleCompressionLevels & (1 << 1)) { + if (!checkMatchSingleFastHash(token, fastL1Hash, fastPreflateParserSettings[0], hashHead)) { + info.possibleCompressionLevels &= ~(1 << 1); + } + } + if (info.possibleCompressionLevels & (1 << 2)) { + if (!checkMatchSingleFastHash(token, fastL2Hash, fastPreflateParserSettings[1], hashHead)) { + info.possibleCompressionLevels &= ~(1 << 2); + } + } + if (info.possibleCompressionLevels & (1 << 3)) { + if (!checkMatchSingleFastHash(token, fastL3Hash, fastPreflateParserSettings[2], hashHead)) { + info.possibleCompressionLevels &= ~(1 << 3); + } + } + + info.referenceCount++; + + unsigned short mdepth = predictor.matchDepth(slowHash.getHead(hashHead), token, slowHash); + if (mdepth >= 0x8001) { + info.unfoundReferences++; + } else { + info.maxChainDepth = std::max(info.maxChainDepth, mdepth); + } + if (token.dist == predictor.currentInputPos()) { + info.matchToStart = true; + } + if (mdepth == 0) { + info.longestDistAtHop0 = std::max(info.longestDistAtHop0, token.dist); + } else { + info.longestDistAtHop1Plus = std::max(info.longestDistAtHop1Plus, token.dist); + } + if (token.len == 3) { + info.longestLen3Dist = std::max(info.longestLen3Dist, token.dist); + } + if (info.possibleCompressionLevels & ((1 << 10) - (1 << 4))) { + for (unsigned i = 0; i < 6; ++i) { + if (!(info.possibleCompressionLevels & (1 << (4 + i)))) { + continue; + } + const PreflateParserConfig& config = slowPreflateParserSettings[i]; + if (mdepth > config.max_chain) { + info.possibleCompressionLevels &= ~(1 << (4 + i)); + } + } + } +} + +void PreflateCompLevelEstimatorState::checkDump(bool early_out) { + for (unsigned i = 0, n = blocks.size(); i < n; ++i) { + const PreflateTokenBlock& b = blocks[i]; + if (b.type == PreflateTokenBlock::STORED) { + updateHash(b.uncompressedLen); + continue; + } + for (unsigned j = 0, m = b.tokens.size(); j < m; ++j) { + const PreflateToken& t = b.tokens[j]; + if (t.len == 1) { + updateHash(1); + } else { + checkMatch(t); + updateOrSkipHash(t.len); + } + if (early_out && (info.possibleCompressionLevels & (info.possibleCompressionLevels - 1)) == 0) { + return; + } + } + } +} +void PreflateCompLevelEstimatorState::recommend() { + info.recommendedCompressionLevel = 9; + info.veryFarMatches = !(info.longestDistAtHop0 <= predictor.windowSize() - PreflateConstants::MIN_LOOKAHEAD + && info.longestDistAtHop1Plus < predictor.windowSize() - PreflateConstants::MIN_LOOKAHEAD); + info.farLen3Matches = info.longestLen3Dist > 4096; + + info.zlibCompatible = info.possibleCompressionLevels > 1 + && !info.matchToStart + && !info.veryFarMatches + && (!info.farLen3Matches || (info.possibleCompressionLevels & 0xe) != 0); + if (info.unfoundReferences) { + return; + } + + if (info.zlibCompatible && info.possibleCompressionLevels > 1) { + unsigned l = info.possibleCompressionLevels >> 1; + info.recommendedCompressionLevel = 1; + while ((l & 1) == 0) { + info.recommendedCompressionLevel++; + l >>= 1; + } + return; + } + for (int i = 0; i < 6; ++i) { + const PreflateParserConfig& config = slowPreflateParserSettings[i]; + if (info.maxChainDepth <= config.max_chain) { + info.recommendedCompressionLevel = 4 + i; + return; + } + } +} + +PreflateCompLevelInfo estimatePreflateCompLevel( + const int wbits, + const int mbits, + const std::vector& unpacked_output, + const std::vector& blocks, + const bool early_out) { + PreflateCompLevelEstimatorState state(wbits, mbits, unpacked_output, blocks); + state.checkDump(early_out); + state.recommend(); + return state.info; +} diff --git a/contrib/preflate/preflate_complevel_estimator.h b/contrib/preflate/preflate_complevel_estimator.h new file mode 100644 index 0000000..75dd3bb --- /dev/null +++ b/contrib/preflate/preflate_complevel_estimator.h @@ -0,0 +1,68 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_COMPLEVEL_ESTIMATOR_H +#define PREFLATE_COMPLEVEL_ESTIMATOR_H + +#include "preflate_predictor_state.h" +#include "preflate_token.h" + +struct PreflateCompLevelInfo { + unsigned possibleCompressionLevels; + unsigned recommendedCompressionLevel; + bool zlibCompatible; + + unsigned referenceCount; + unsigned unfoundReferences; + unsigned short maxChainDepth; + unsigned short longestLen3Dist; + unsigned short longestDistAtHop0; + unsigned short longestDistAtHop1Plus; + bool matchToStart; + bool veryFarMatches; + bool farLen3Matches; +}; + +struct PreflateCompLevelEstimatorState { + PreflatePredictorState predictor; + PreflateHashChainExt slowHash; + PreflateHashChainExt fastL1Hash; + PreflateHashChainExt fastL2Hash; + PreflateHashChainExt fastL3Hash; + const std::vector& blocks; + PreflateCompLevelInfo info; + + PreflateCompLevelEstimatorState(const int wbits, const int mbits, + const std::vector& unpacked_output, + const std::vector& blocks); + void updateHash(const unsigned len); + void updateOrSkipHash(const unsigned len); + void checkMatch(const PreflateToken& token); + void checkDump(bool early_out); + void recommend(); + +private: + void updateOrSkipSingleFastHash(PreflateHashChainExt&, const unsigned len, const PreflateParserConfig&); + bool checkMatchSingleFastHash(const PreflateToken& token, const PreflateHashChainExt&, const PreflateParserConfig&, + const unsigned hashHead); +}; + +PreflateCompLevelInfo estimatePreflateCompLevel( + const int wbits, + const int mbits, + const std::vector& unpacked_output, + const std::vector& blocks, + const bool early_out); + +#endif /* PREFLATE_COMPLEVEL_ESTIMATOR_H */ diff --git a/contrib/preflate/preflate_constants.cpp b/contrib/preflate/preflate_constants.cpp new file mode 100644 index 0000000..5488270 --- /dev/null +++ b/contrib/preflate/preflate_constants.cpp @@ -0,0 +1,87 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "preflate_block_reencoder.h" +#include "support/bit_helper.h" + +/* tables taken from zlib */ + +const unsigned char PreflateConstants::distCodeTable[512] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, + 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, + 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const unsigned char PreflateConstants::lengthCodeTable[MAX_MATCH - MIN_MATCH + 1 ] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, + 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, + 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +const unsigned char PreflateConstants::lengthBaseTable[LENGTH_CODES] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, + 64, 80, 96, 112, 128, 160, 192, 224, 255 +}; + +const unsigned short PreflateConstants::distBaseTable[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + +const unsigned char PreflateConstants::lengthExtraTable[LENGTH_CODES] = { /* extra bits for each length code */ + 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0 +}; + +const unsigned char PreflateConstants::distExtraTable[D_CODES] = { /* extra bits for each distance code */ + 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 +}; + +const unsigned char PreflateConstants::treeCodeOrderTable[BL_CODES] = { + 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 +}; diff --git a/contrib/preflate/preflate_constants.h b/contrib/preflate/preflate_constants.h new file mode 100644 index 0000000..1a05abd --- /dev/null +++ b/contrib/preflate/preflate_constants.h @@ -0,0 +1,52 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_CONSTANTS_H +#define PREFLATE_CONSTANTS_H + +struct PreflateConstants { + enum { + LENGTH_CODES = 29, + LITERALS = 256, + L_CODES = LITERALS + 1 /* eob */ + LENGTH_CODES, + D_CODES = 30, + LD_CODES = L_CODES + D_CODES, + BL_CODES = 19, + + MIN_MATCH = 3, + MAX_MATCH = 258, + + MAX_BITS = 15, + + MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1, + }; + + static const unsigned char distCodeTable[512]; + static const unsigned char lengthCodeTable[MAX_MATCH - MIN_MATCH + 1]; + static const unsigned char lengthBaseTable[LENGTH_CODES]; + static const unsigned short distBaseTable[D_CODES]; + + static const unsigned char lengthExtraTable[LENGTH_CODES]; + static const unsigned char distExtraTable[D_CODES]; + static const unsigned char treeCodeOrderTable[BL_CODES]; + + static inline unsigned DCode(const unsigned dist) { + return distCodeTable[dist <= 256 ? dist - 1 : 256 + ((dist - 1) >> 7)]; + } + static inline unsigned LCode(const unsigned len) { + return lengthCodeTable[len - MIN_MATCH]; + } +}; + +#endif /* PREFLATE_CONSTANTS_H */ diff --git a/contrib/preflate/preflate_decoder.cpp b/contrib/preflate/preflate_decoder.cpp new file mode 100644 index 0000000..aa89996 --- /dev/null +++ b/contrib/preflate/preflate_decoder.cpp @@ -0,0 +1,162 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "preflate_block_decoder.h" +#include "preflate_decoder.h" +#include "preflate_parameter_estimator.h" +#include "preflate_statistical_model.h" +#include "preflate_token_predictor.h" +#include "preflate_tree_predictor.h" +#include "preflate_unpack.h" +#include "support/bitstream.h" +#include "support/memstream.h" +#include "support/outputcachestream.h" + +bool preflate_decode(std::vector& unpacked_output, + std::vector& preflate_diff, + const std::vector& deflate_raw) { + std::vector blocks; + MemStream decIn(deflate_raw); + MemStream decUnc; + BitInputStream decInBits(decIn); + OutputCacheStream decOutCache(decUnc); + PreflateBlockDecoder bdec(decInBits, decOutCache); + if (bdec.status() != PreflateBlockDecoder::OK) { + return false; + } + bool last; + unsigned i = 0; + do { + PreflateTokenBlock newBlock; + bool ok = bdec.readBlock(newBlock, last); + if (!ok) { + return false; + } + blocks.push_back(newBlock); + ++i; + } while (!last); + decOutCache.flush(); + + unpacked_output = decUnc.extractData(); + + PreflateParameters params = estimatePreflateParameters(unpacked_output, blocks); + PreflateStatisticalModel model; + memset(&model, 0, sizeof(model)); + PreflateTokenPredictor tokenPredictor(params, unpacked_output); + PreflateTreePredictor treePredictor(unpacked_output); + for (unsigned i = 0, n = blocks.size(); i < n; ++i) { + tokenPredictor.analyzeBlock(i, blocks[i]); + treePredictor.analyzeBlock(i, blocks[i]); + if (tokenPredictor.predictionFailure || treePredictor.predictionFailure) { + return false; + } + tokenPredictor.updateModel(&model, i); + treePredictor.updateModel(&model, i); + } + PreflateStatisticalEncoder codec(model); + codec.encodeHeader(); + codec.encodeParameters(params); + codec.encodeModel(); + for (unsigned i = 0, n = blocks.size(); i < n; ++i) { + tokenPredictor.encodeBlock(&codec, i); + treePredictor.encodeBlock(&codec, i); + if (tokenPredictor.predictionFailure || treePredictor.predictionFailure) { + return false; + } + tokenPredictor.encodeEOF(&codec, i, i + 1 == blocks.size()); + } + preflate_diff = codec.encodeFinish(); + return true; +} + +bool preflate_decode(std::vector& unpacked_output, + std::vector& preflate_diff, + uint64_t& deflate_size, + InputStream& deflate_raw, + std::function block_callback) { + deflate_size = 0; + uint64_t deflate_bits = 0; + size_t prevBitPos = 0; + BitInputStream decInBits(deflate_raw); + MemStream decUnc; + OutputCacheStream decOutCache(decUnc); + PreflateBlockDecoder bdec(decInBits, decOutCache); + if (bdec.status() != PreflateBlockDecoder::OK) { + return false; + } + bool last; + unsigned i = 0; + std::vector blocks; + do { + PreflateTokenBlock newBlock; + + bool ok = bdec.readBlock(newBlock, last); + if (!ok) { + return false; + } + blocks.push_back(newBlock); + ++i; + if (decOutCache.cacheSize() >= 512 * 1024) { + decOutCache.flushUpTo(decOutCache.cacheEndPos() - (32 * 1024)); + } + deflate_bits += decInBits.bitPos() - prevBitPos; + prevBitPos = decInBits.bitPos(); + block_callback(); + } while (!last); + decOutCache.flush(); + unpacked_output = decUnc.extractData(); + deflate_size = (deflate_bits + 7) >> 3; + uint8_t remaining_bit_count = (8 - deflate_bits) & 7; + uint8_t remaining_bits = decInBits.get(remaining_bit_count); + + PreflateParameters params = estimatePreflateParameters(unpacked_output, blocks); + PreflateStatisticalModel model; + memset(&model, 0, sizeof(model)); + PreflateTokenPredictor tokenPredictor(params, unpacked_output); + PreflateTreePredictor treePredictor(unpacked_output); + for (unsigned i = 0, n = blocks.size(); i < n; ++i) { + tokenPredictor.analyzeBlock(i, blocks[i]); + treePredictor.analyzeBlock(i, blocks[i]); + if (tokenPredictor.predictionFailure || treePredictor.predictionFailure) { + return false; + } + tokenPredictor.updateModel(&model, i); + treePredictor.updateModel(&model, i); + block_callback(); + } + PreflateStatisticalEncoder codec(model); + codec.encodeHeader(); + codec.encodeParameters(params); + codec.encodeModel(); + for (unsigned i = 0, n = blocks.size(); i < n; ++i) { + tokenPredictor.encodeBlock(&codec, i); + treePredictor.encodeBlock(&codec, i); + if (tokenPredictor.predictionFailure || treePredictor.predictionFailure) { + return false; + } + tokenPredictor.encodeEOF(&codec, i, i + 1 == blocks.size()); + } + if (remaining_bit_count > 0) { + if (remaining_bits != 0) { + codec.encodeValue(1, 1); + codec.encodeValue(remaining_bits, remaining_bit_count); + } else { + codec.encodeValue(0, 1); + } + } + preflate_diff = codec.encodeFinish(); + return true; +} diff --git a/contrib/preflate/preflate_decoder.h b/contrib/preflate/preflate_decoder.h new file mode 100644 index 0000000..3358c1b --- /dev/null +++ b/contrib/preflate/preflate_decoder.h @@ -0,0 +1,33 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_DECODER_H +#define PREFLATE_DECODER_H + +#include +#include +#include "preflate_token.h" +#include "support/stream.h" + +bool preflate_decode(std::vector& unpacked_output, + std::vector& preflate_diff, + const std::vector& deflate_raw); + +bool preflate_decode(std::vector& unpacked_output, + std::vector& preflate_diff, + uint64_t& deflate_size, + InputStream& deflate_raw, + std::function block_callback); + +#endif /* PREFLATE_DECODER_H */ diff --git a/contrib/preflate/preflate_dumper.cpp b/contrib/preflate/preflate_dumper.cpp new file mode 100644 index 0000000..d9f6a60 --- /dev/null +++ b/contrib/preflate/preflate_dumper.cpp @@ -0,0 +1,145 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include "zlib1.2.11.dec/zlib.h" +#include "zlib1.2.11.dec/prefdump.h" +#include "preflate_dumper.h" + +PreflateDumper::PreflateDumper() + : error(false) + , hasOpenBlock(false) + , wbits(0) + , hdr2(0) + , dictid(0) { +} + +PreflateDumper::~PreflateDumper() { +} + +void PreflateDumper::setStreamHeader(int wlen, int zhdr2) { + if (hasOpenBlock) { + error = true; + return; + } + wbits = wlen; + hdr2 = zhdr2; +} +void PreflateDumper::setDictId(unsigned id) { + if (hasOpenBlock) { + error = true; + return; + } + dictid = id; +} +void PreflateDumper::addStoredBlock(int len) { + if (hasOpenBlock) { + error = true; + return; + } + blocks.push_back(PreflateTokenBlock(PreflateTokenBlock::STORED_X, len)); +} +void PreflateDumper::addHuffBlock(bool dynamic) { + if (hasOpenBlock) { + error = true; + return; + } + openBlock.type = dynamic ? PreflateTokenBlock::DYNAMIC_HUFF : PreflateTokenBlock::STATIC_HUFF; + hasOpenBlock = true; +} +void PreflateDumper::addDynamicHuffLengths(int nlen, int ndist, int ncode) { + if (!hasOpenBlock || openBlock.type != PreflateTokenBlock::DYNAMIC_HUFF) { + error = true; + return; + } + openBlock.setHuffLengths(nlen, ndist, ncode); +} +void PreflateDumper::addDynamicHuffTreeCode(int code) { + if (!hasOpenBlock || openBlock.type != PreflateTokenBlock::DYNAMIC_HUFF) { + error = true; + return; + } + openBlock.addTreeCode(code); +} +void PreflateDumper::addLiteral() { + if (!hasOpenBlock) { + error = true; + return; + } + openBlock.tokens.push_back(PreflateToken(PreflateToken::LITERAL)); +} +void PreflateDumper::addReference(int dist, int len) { + if (!hasOpenBlock) { + error = true; + return; + } + openBlock.tokens.push_back(PreflateToken(PreflateToken::REFERENCE, len, dist)); +} +void PreflateDumper::addEOB() { + if (hasOpenBlock) { + blocks.push_back(std::move(openBlock)); + hasOpenBlock = false; + } +} + +void PreflateDumper::addUncompressedData(const unsigned char* data, const unsigned len) { + uncompressed.insert(uncompressed.end(), data, data + len); +} + +// ------------------------------------ + +void prefdump_stream_header(void* dumper, int wlen, int zhdr2) { + if (dumper) { + ((PreflateDumper*)dumper)->setStreamHeader(wlen, zhdr2); + } +} +void prefdump_dictid(void* dumper, uLong dictid) { + if (dumper) { + ((PreflateDumper*)dumper)->setDictId(dictid); + } +} +void prefdump_new_stored_block(void* dumper, int len) { + if (dumper) { + ((PreflateDumper*)dumper)->addStoredBlock(len); + } +} +void prefdump_new_huff_block(void* dumper, int dynamic) { + if (dumper) { + ((PreflateDumper*)dumper)->addHuffBlock(dynamic != 0); + } +} +void prefdump_dyn_huff_lengths(void* dumper, int nlen, int ndist, int ncode) { + if (dumper) { + ((PreflateDumper*)dumper)->addDynamicHuffLengths(nlen, ndist, ncode); + } +} +void prefdump_dyn_huff_tcode(void* dumper, int code) { + if (dumper) { + ((PreflateDumper*)dumper)->addDynamicHuffTreeCode(code); + } +} +void prefdump_literal(void* dumper) { + if (dumper) { + ((PreflateDumper*)dumper)->addLiteral(); + } +} +void prefdump_reference(void* dumper, int dist, int len) { + if (dumper) { + ((PreflateDumper*)dumper)->addReference(dist, len); + } +} +void prefdump_eob(void* dumper) { + if (dumper) { + ((PreflateDumper*)dumper)->addEOB(); + } +} diff --git a/contrib/preflate/preflate_dumper.h b/contrib/preflate/preflate_dumper.h new file mode 100644 index 0000000..9eacc6d --- /dev/null +++ b/contrib/preflate/preflate_dumper.h @@ -0,0 +1,57 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_DUMPER_H +#define PREFLATE_DUMPER_H + +#include +#include "preflate_token.h" + +class PreflateDumper { +public: + PreflateDumper(); + ~PreflateDumper(); + + void setStreamHeader(int wlen, int zhdr2); + void setDictId(unsigned id); + void addStoredBlock(int len); + void addHuffBlock(bool dynamic); + void addDynamicHuffLengths(int nlen, int ndist, int ncode); + void addDynamicHuffTreeCode(int code); + void addLiteral(); + void addReference(int dist, int len); + void addEOB(); + void addUncompressedData(const unsigned char*, const unsigned); + + const std::vector& getBlocks() const { + return blocks; + } + bool hadErrors() const { + return error; + } + const std::vector& uncompressedData() const { + return uncompressed; + } + +//private: + bool error; + bool hasOpenBlock; + PreflateTokenBlock openBlock; + unsigned char wbits, hdr2; + unsigned dictid; + std::vector blocks; + std::vector uncompressed; +}; + +#endif // PREFLATE_DUMPER_H diff --git a/contrib/preflate/preflate_hash_chain.cpp b/contrib/preflate/preflate_hash_chain.cpp new file mode 100644 index 0000000..1c92518 --- /dev/null +++ b/contrib/preflate/preflate_hash_chain.cpp @@ -0,0 +1,108 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "preflate_constants.h" +#include "preflate_hash_chain.h" + +PreflateHashChainExt::PreflateHashChainExt( + const std::vector& input_, + const unsigned char memLevel) + : _input(input_) + , totalShift(-8) { + hashBits = memLevel + 7; + hashShift = (hashBits + PreflateConstants::MIN_MATCH - 1) / PreflateConstants::MIN_MATCH; + hashMask = (1 << hashBits) - 1; + head = new unsigned short[hashMask + 1]; + prev = new unsigned short[1 << 16]; + chainDepth = new unsigned[1 << 16]; + memset(head, 0, sizeof(short) * (hashMask + 1)); + memset(prev, 0, sizeof(short) * (1 << 16)); + memset(chainDepth, 0, sizeof(unsigned) * (1 << 16)); + runningHash = 0; + if (_input.remaining() > 2) { + updateRunningHash(_input.curChar(0)); + updateRunningHash(_input.curChar(1)); + } +} +PreflateHashChainExt::~PreflateHashChainExt() { + delete[] head; + delete[] chainDepth; + delete[] prev; +} + +void PreflateHashChainExt::updateHash(const unsigned l) { + if (l > 0x180) { + unsigned l_ = l; + while (l_ > 0) { + unsigned blk = std::min(l_, 0x180u); + updateHash(blk); + l_ -= blk; + } + return; + } + + const unsigned char* b = _input.curChars(); + unsigned pos = _input.pos(); + if (pos - totalShift >= 0xfe08) { + reshift(); + } + for (unsigned i = 0; i < l; ++i) { + updateRunningHash(b[2 + i]); + unsigned h = runningHash & hashMask; + unsigned p = (pos + i) - totalShift; + chainDepth[p] = chainDepth[head[h]] + 1; + prev[p] = head[h]; + head[h] = p; + } + _input.advance(l); +} +void PreflateHashChainExt::skipHash(const unsigned l) { + const unsigned char* b = _input.curChars(); + unsigned pos = _input.pos(); + if (pos - totalShift >= 0xfe08) { + reshift(); + } + updateRunningHash(b[2]); + unsigned h = runningHash & hashMask; + unsigned p = (pos) - totalShift; + chainDepth[p] = chainDepth[head[h]] + 1; + prev[p] = head[h]; + head[h] = p; + + // Skipped data is not inserted into the hash chain, + // but we must still update the chainDepth, to avoid + // bad analysis results + // -------------------- + for (unsigned i = 1; i < l; ++i) { + unsigned p = (pos + i)-totalShift; + chainDepth[p] = 0xffff8000; + } + // l must be at least 3 + updateRunningHash(b[l]); + updateRunningHash(b[l + 1]); + _input.advance(l); +} +void PreflateHashChainExt::reshift() { + const unsigned short delta = 0x7e00; + for (unsigned i = 0, n = hashMask + 1; i < n; ++i) { + head[i] = std::max(head[i], delta) - delta; + } + for (unsigned i = delta + 8, n = 1 << 16; i < n; ++i) { + prev[i - delta] = std::max(prev[i], delta) - delta; + } + memmove(chainDepth + 8, chainDepth + 8 + delta, (0x10000 - delta) * sizeof(chainDepth[0])); + totalShift += delta; +} diff --git a/contrib/preflate/preflate_hash_chain.h b/contrib/preflate/preflate_hash_chain.h new file mode 100644 index 0000000..4e88403 --- /dev/null +++ b/contrib/preflate/preflate_hash_chain.h @@ -0,0 +1,122 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_HASH_CHAIN_H +#define PREFLATE_HASH_CHAIN_H + +#include +#include "preflate_input.h" + +struct PreflateHashIterator { + const unsigned short* chain; + const unsigned * chainDepth; + const unsigned refPos; + const unsigned maxDist; + unsigned curPos, curDist; + bool isValid; + + PreflateHashIterator( + const unsigned short* chain_, + const unsigned * depth_, + const unsigned refPos_, + const unsigned maxDist_, + unsigned startPos_) + : chain(chain_) + , chainDepth(depth_) + , refPos(refPos_) + , maxDist(maxDist_) + , curPos(startPos_) + , curDist(dist(refPos_, startPos_)) { + isValid = curDist <= maxDist; + } + + inline bool valid() const { + return isValid; + } + inline bool operator !() const { + return !isValid; + } + static inline unsigned dist(const unsigned p1, const unsigned p2) { + return p1 - p2; + } + inline unsigned dist() const { + return curDist; + } + inline unsigned depth() const { + return chainDepth[curPos]; + } + inline bool next() { + curPos = chain[curPos]; + curDist = dist(refPos, curPos); + isValid = curPos > 0 && curDist <= maxDist; + return isValid; + } +}; + +struct PreflateHashChainExt { + PreflateInput _input; + unsigned short* head; + unsigned * chainDepth; + unsigned short* prev; + unsigned char hashBits, hashShift; + unsigned short runningHash, hashMask; + unsigned totalShift; + + PreflateHashChainExt(const std::vector& input_, const unsigned char memLevel); + ~PreflateHashChainExt(); + + unsigned nextHash(const unsigned char b) const { + return ((runningHash << hashShift) ^ b); + } + unsigned nextHash(const unsigned char b1, const unsigned char b2) const { + return ((((runningHash << hashShift) ^ b1) << hashShift) ^ b2); + } + void updateRunningHash(const unsigned char b) { + runningHash = (runningHash << hashShift) ^ b; + } + void reshift(); + unsigned getHead(const unsigned hash) const { + return head[hash & hashMask]; + } + unsigned getNodeDepth(const unsigned node) const { + return chainDepth[node]; + } + + PreflateHashIterator iterateFromHead(const unsigned hash, const unsigned refPos, const unsigned maxDist) const { + return PreflateHashIterator(prev, chainDepth, refPos - totalShift, maxDist, head[hash & hashMask]); + } + PreflateHashIterator iterateFromNode(const unsigned node, const unsigned refPos, const unsigned maxDist) const { + return PreflateHashIterator(prev, chainDepth, refPos - totalShift, maxDist, node); + } + PreflateHashIterator iterateFromPos(const unsigned pos, const unsigned refPos, const unsigned maxDist) const { + return PreflateHashIterator(prev, chainDepth, refPos - totalShift, maxDist, pos - totalShift); + } + const PreflateInput& input() const { + return _input; + } + unsigned curHash() const { + return nextHash(_input.curChar(2)); + } + unsigned curPlus1Hash() const { + return nextHash(_input.curChar(2), _input.curChar(3)); + } + void updateHash(const unsigned l); + void updateHashLong(const unsigned l); + void skipHash(const unsigned l); + +private: + void _updateHashSimple(const unsigned l); +}; + +#endif /* PREFLATE_HASH_CHAIN_H */ diff --git a/contrib/preflate/preflate_info.cpp b/contrib/preflate/preflate_info.cpp new file mode 100644 index 0000000..2ed0597 --- /dev/null +++ b/contrib/preflate/preflate_info.cpp @@ -0,0 +1,55 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "preflate_info.h" + +// ----------------------------------------- + +PreflateStreamInfo extractPreflateInfo(const std::vector& blocks) { + PreflateStreamInfo result; + memset(&result, 0, sizeof(result)); + result.countBlocks = blocks.size(); + for (unsigned i = 0, n = result.countBlocks; i < n; ++i) { + const PreflateTokenBlock& b = blocks[i]; + if (b.type == PreflateTokenBlock::STORED) { + result.countStoredBlocks++; + continue; + } + if (b.type == PreflateTokenBlock::STATIC_HUFF) { + result.countStaticHuffTreeBlocks++; + } + result.tokenCount += b.tokens.size(); + result.maxTokensPerBlock = std::max(result.maxTokensPerBlock, (unsigned)b.tokens.size()); + unsigned blockMaxDist = 0; + for (unsigned j = 0, m = b.tokens.size(); j < m; ++j) { + const PreflateToken& t = b.tokens[j]; + if (t.len == 1) { + result.literalCount++; + } else { + result.referenceCount++; + blockMaxDist = std::max(blockMaxDist, (unsigned)t.dist); + } + } + result.maxDist = std::max(result.maxDist, blockMaxDist); + if (blockMaxDist == 0) { + result.countHuffBlocks++; + } else if (blockMaxDist == 1) { + result.countRLEBlocks++; + } + } + return result; +} + diff --git a/contrib/preflate/preflate_info.h b/contrib/preflate/preflate_info.h new file mode 100644 index 0000000..5e25f64 --- /dev/null +++ b/contrib/preflate/preflate_info.h @@ -0,0 +1,35 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_INFO_H +#define PREFLATE_INFO_H + +#include "preflate_token.h" + +struct PreflateStreamInfo { + unsigned tokenCount; + unsigned literalCount; + unsigned referenceCount; + unsigned maxDist; + unsigned maxTokensPerBlock; + unsigned countBlocks; + unsigned countStoredBlocks; + unsigned countHuffBlocks; + unsigned countRLEBlocks; + unsigned countStaticHuffTreeBlocks; +}; + +PreflateStreamInfo extractPreflateInfo(const std::vector& blocks); + +#endif /* PREFLATE_INFO_H */ \ No newline at end of file diff --git a/contrib/preflate/preflate_input.h b/contrib/preflate/preflate_input.h new file mode 100644 index 0000000..e239960 --- /dev/null +++ b/contrib/preflate/preflate_input.h @@ -0,0 +1,49 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_INPUT_H +#define PREFLATE_INPUT_H + +#include + +class PreflateInput { +public: + PreflateInput(const std::vector& v) + : _data(v.size() > 0 ? &v[0] : nullptr), _size(v.size()), _pos(0) {} + + const unsigned pos() const { + return _pos; + } + + const unsigned char* curChars(int offset = 0) const { + return _data + _pos + offset; + } + const unsigned char curChar(int offset = 0) const { + return _data[_pos + offset]; + } + void advance(const unsigned l) { + _pos += l; + } + const unsigned remaining() const { + return _size - _pos; + } + +private: + const unsigned char* _data; + unsigned _size; + unsigned _pos; +}; + + +#endif /* PREFLATE_INPUT_H */ diff --git a/contrib/preflate/preflate_parameter_estimator.cpp b/contrib/preflate/preflate_parameter_estimator.cpp new file mode 100644 index 0000000..8f9306a --- /dev/null +++ b/contrib/preflate/preflate_parameter_estimator.cpp @@ -0,0 +1,84 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "preflate_complevel_estimator.h" +#include "preflate_constants.h" +#include "preflate_info.h" +#include "preflate_parameter_estimator.h" +#include "preflate_token_predictor.h" +#include "support/bit_helper.h" + +unsigned char estimatePreflateMemLevel(const unsigned maxBlockSize_) { + unsigned maxBlockSize = maxBlockSize_; + unsigned mbits = 0; + while (maxBlockSize > 0) { + ++mbits; maxBlockSize >>= 1; + } + mbits = std::min(std::max(mbits, 7u), 15u); + return mbits - 6; +} + +unsigned char estimatePreflateWindowBits(const unsigned maxDist_) { + unsigned maxDist = maxDist_; + maxDist += PreflateConstants::MIN_LOOKAHEAD; + unsigned wbits = 0; + while (maxDist > 0) { + ++wbits; maxDist >>= 1; + } + wbits = std::min(std::max(wbits, 9u), 15u); + return wbits; +} + +PreflateStrategy estimatePreflateStrategy(const PreflateStreamInfo& info) { + if (info.countStoredBlocks == info.countBlocks) { + return PREFLATE_STORE; + } + if (info.countHuffBlocks == info.countBlocks) { + return PREFLATE_HUFF_ONLY; + } + if (info.countRLEBlocks == info.countBlocks) { + return PREFLATE_RLE_ONLY; + } + return PREFLATE_DEFAULT; +} + +PreflateHuffStrategy estimatePreflateHuffStrategy(const PreflateStreamInfo& info) { + if (info.countStaticHuffTreeBlocks == info.countBlocks) { + return PREFLATE_HUFF_STATIC; + } + if (info.countStaticHuffTreeBlocks == 0) { + return PREFLATE_HUFF_DYNAMIC; + } + return PREFLATE_HUFF_MIXED; +} + +PreflateParameters estimatePreflateParameters(const std::vector& unpacked_output, + const std::vector& blocks) { + PreflateStreamInfo info = extractPreflateInfo(blocks); + + PreflateParameters result; + result.windowBits = estimatePreflateWindowBits(info.maxDist); + result.memLevel = estimatePreflateMemLevel(info.maxTokensPerBlock); + result.strategy = estimatePreflateStrategy(info); + result.huffStrategy = estimatePreflateHuffStrategy(info); + PreflateCompLevelInfo cl = estimatePreflateCompLevel(result.windowBits, result.memLevel, unpacked_output, blocks, false); + result.compLevel = cl.recommendedCompressionLevel; + result.zlibCompatible = cl.zlibCompatible; + result.farLen3MatchesDetected = cl.farLen3Matches; + result.veryFarMatchesDetected = cl.veryFarMatches; + result.matchesToStartDetected = cl.matchToStart; + result.log2OfMaxChainDepthM1 = cl.maxChainDepth == 0 ? 0 : bitLength(cl.maxChainDepth - 1); + return result; +} diff --git a/contrib/preflate/preflate_parameter_estimator.h b/contrib/preflate/preflate_parameter_estimator.h new file mode 100644 index 0000000..177017d --- /dev/null +++ b/contrib/preflate/preflate_parameter_estimator.h @@ -0,0 +1,109 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_PARAMETER_ESTIMATOR_H +#define PREFLATE_PARAMETER_ESTIMATOR_H + +/* deflate has four parameters: +* - strategy: the strategy can usually be guessed by looking on the given deflate stream +* (e.g. only stored blocks -> stored, +* max distance = 0 -> huffman-only, +* max distance = 1 -> rle, +* only fixed huffman trees -> fixed-huffman-tree, +* otherwise default) +* - window bits: known by max distance, less window bits would be impossible, more window +* bits would be pointless +* - mem level: used for hash calculation and number of tokens per block +* the latter can be used to put a lower limit on mem level +* - compression level: parameters for the reference finder +* +* When reencoding a deflate stream, the predictor has to make a token proposal (either to +* encode a literal or a (dist, len) pair. A correction data stream will either accept the +* proposal, or change it to the correct values. The corrected values are then fed to the +* deflate encoder, and to the predictor. +* +* The main problem is to find the missing deflate parameters (compression level and +* mem level) to minimize the number and complexity of required corrections. +* Data streams that were encoded with zlib should get perfect recognition, +* requiring only the detected deflate parameters to be encoded for perfect reconstruction. +* Data streams from other encoders (7zip, kzip, ...) should be reconstructible with minimal +* corrective instructions, similar to reflate. +* +* kzip does not limit block size to < 64k tokens, while zlib enforces it for various reasons +* (and defaults to max 16k tokens). +* Prediction for end-of-block is therefore independent of literal/reference prediction. +* +* Mixing or interpolating the prediction from different parameter packs is +* possible, but not planned right now. +*/ + +#include "preflate_info.h" +#include "preflate_parser_config.h" +#include "preflate_token.h" + +enum PreflateStrategy { + PREFLATE_DEFAULT, + PREFLATE_RLE_ONLY, + PREFLATE_HUFF_ONLY, + PREFLATE_STORE +}; +enum PreflateHuffStrategy { + PREFLATE_HUFF_DYNAMIC, + PREFLATE_HUFF_MIXED, + PREFLATE_HUFF_STATIC, +}; + +struct PreflateParameters { + PreflateStrategy strategy; + PreflateHuffStrategy huffStrategy; + bool zlibCompatible; + unsigned char windowBits; + unsigned char memLevel; + unsigned char compLevel; + // true if matches of len 3 with a distance > 4096 are allowed + // (disallowed by zlib level 4+) + bool farLen3MatchesDetected; + // true if matches of distance >= 32768 - (MAX_MATCH + MIN_MATCH + 1) are allowed + // or > 32768 - (MAX_MATCH + MIN_MATCH + 1) if it's the first node in the hash chain + // (disallowed by zlib) + bool veryFarMatchesDetected; + // true if matches to start of stream are allowed + // (disallowed by zlib) + bool matchesToStartDetected; + // log2 of maximal found chain depth - 1 + // so, 9 to 16 have value 3 + unsigned char log2OfMaxChainDepthM1; + + + bool isFastCompressor() const { + return compLevel >= 1 && compLevel <= 3; + } + bool isSlowCompressor() const { + return compLevel >= 4 && compLevel <= 9; + } + const PreflateParserConfig& config() const { + return isFastCompressor() ? fastPreflateParserSettings[compLevel - 1] + : slowPreflateParserSettings[isSlowCompressor() ? compLevel - 4 : 5]; + } +}; + +unsigned char estimatePreflateMemLevel(const unsigned maxBlockSize); +PreflateStrategy estimatePreflateStrategy(const PreflateStreamInfo&); +PreflateHuffStrategy estimatePreflateHuffStrategy(const PreflateStreamInfo&); +unsigned char estimatePreflateWindowBits(const unsigned maxDist); + +PreflateParameters estimatePreflateParameters(const std::vector& unpacked_output, + const std::vector& blocks); + +#endif /* PREFLATE_PARAMETER_ESTIMATOR_H */ diff --git a/contrib/preflate/preflate_parser_config.cpp b/contrib/preflate/preflate_parser_config.cpp new file mode 100644 index 0000000..5356373 --- /dev/null +++ b/contrib/preflate/preflate_parser_config.cpp @@ -0,0 +1,34 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include "preflate_parser_config.h" + +#include + +// ----------------------------------------- + +/* good lazy nice chain */ +const PreflateParserConfig fastPreflateParserSettings[3] = { + /* 1 */ {4, 4, 8, 4}, /* max speed, no lazy matches */ + /* 2 */ {4, 5, 16, 8}, + /* 3 */ {4, 6, 32, 32}, +}; +const PreflateParserConfig slowPreflateParserSettings[6] = { + /* 4 */ {4, 4, 16, 16}, /* lazy matches */ + /* 5 */ {8, 16, 32, 32}, + /* 6 */ {8, 16, 128, 128}, + /* 7 */ {8, 32, 128, 256}, + /* 8 */ {32, 128, 258, 1024}, + /* 9 */ {32, 258, 258, 4096}, /* max compression */ +}; diff --git a/contrib/preflate/preflate_parser_config.h b/contrib/preflate/preflate_parser_config.h new file mode 100644 index 0000000..d25d731 --- /dev/null +++ b/contrib/preflate/preflate_parser_config.h @@ -0,0 +1,35 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_PARSER_CONFIG +#define PREFLATE_PARSER_CONFIG + +/* Values for max_lazy_match, good_match and max_chain_length, depending on +* the desired pack level (0..9). The values given below have been tuned to +* exclude worst case performance for pathological files. Better values may be +* found for specific files. +*/ +struct PreflateParserConfig { + unsigned char good_length; /* reduce lazy search above this match length */ + unsigned short max_lazy; /* do not perform lazy search above this match length */ + unsigned short nice_length; /* quit search above this match length */ + unsigned short max_chain; +}; + +extern const PreflateParserConfig fastPreflateParserSettings[3]; +extern const PreflateParserConfig slowPreflateParserSettings[6]; + + +#endif +/* PREFLATE_PARSER_CONFIG */ \ No newline at end of file diff --git a/contrib/preflate/preflate_predictor_state.cpp b/contrib/preflate/preflate_predictor_state.cpp new file mode 100644 index 0000000..23a2a93 --- /dev/null +++ b/contrib/preflate/preflate_predictor_state.cpp @@ -0,0 +1,323 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include "preflate_constants.h" +#include "preflate_predictor_state.h" +#include + +PreflatePredictorState::PreflatePredictorState( + const PreflateHashChainExt& hash_, + const PreflateParserConfig& config_, + const int wbits, + const int mbits) + : hash(hash_) + , windowBytes(1 << wbits) + , maxTokenCount((1 << (6 + mbits)) - 1) + , config(config_) { +} + +/* deflate has four parameters: + * - strategy: the strategy can usually be guessed by looking on the given deflate stream + * (e.g. only stored blocks -> stored, + * max distance = 0 -> huffman-only, + * max distance = 1 -> rle, + * only fixed huffman trees -> fixed-huffman-tree, + * otherwise default) + * - window bits: known by max distance, less window bits would be impossible, more window + * bits would be pointless + * - mem level: used for hash calculation and number of tokens per block + * the latter can be used to put a lower limit on mem level + * - compression level: parameters for the reference finder + * + * When reencoding a deflate stream, the predictor has to make a token proposal (either to + * encode a literal or a (dist, len) pair. A correction data stream will either accept the + * proposal, or change it to the correct values. The corrected values are then fed to the + * deflate encoder, and to the predictor. + * + * The main problem is to find the missing deflate parameters (compression level and + * mem level) to minimize the number and complexity of required corrections. + * Data streams that were encoded with zlib should get perfect recognition, + * requiring only the detected deflate parameters to be encoded for perfect reconstruction. + * Data streams from other encoders (7zip, kzip, ...) should be reconstructible with minimal + * corrective instructions, similar to reflate. + * + * kzip does not limit block size to < 64k tokens, while zlib enforces it for various reasons + * (and defaults to max 16k tokens). + * Prediction for end-of-block is therefore independent of literal/reference prediction. + * + * Mixing or interpolating the prediction from different parameter packs is + * possible, but not planned right now. + */ + +unsigned PreflatePredictorState::prefixCompare( + const unsigned char* s1, + const unsigned char* s2, + const unsigned bestLen, + const unsigned maxLen) { + if (s1[bestLen] != s2[bestLen]) { + return 0; + } + if (s1[0] != s2[0] || s1[1] != s2[1] || s1[2] != s2[2]) { + return 0; + } + + const unsigned char* scan = s2 + 2; + const unsigned char* match = s1 + 2; + const unsigned char* scanend = s2 + maxLen - 8; + +/* while (scan < scanend + && *++scan == *++match && *++scan == *++match + && *++scan == *++match && *++scan == *++match + && *++scan == *++match && *++scan == *++match + && *++scan == *++match && *++scan == *++match) { + }*/ + scanend = s2 + maxLen; + while (scan < scanend + && *++scan == *++match) { + } + + return scan - s2; +} + +PreflateToken PreflatePredictorState::match( + const unsigned hashHead, + const unsigned prevLen, + const unsigned offset, + const bool veryFarMatches, + const bool matchesToStart, + const unsigned maxDepth) { + PreflateToken bestMatch(PreflateToken::NONE); + unsigned maxLen = std::min(availableInputSize() - offset, (unsigned)PreflateConstants::MAX_MATCH); + if (maxLen < std::max(prevLen + 1, (unsigned)PreflateConstants::MIN_MATCH)) { + return bestMatch; + } + + unsigned maxDistHop0 = windowSize() - (veryFarMatches ? 0 : PreflateConstants::MIN_LOOKAHEAD); + unsigned maxDistHop1Plus = windowSize() - (veryFarMatches ? 0 : PreflateConstants::MIN_LOOKAHEAD + 1); + unsigned curPos = currentInputPos() + offset; + unsigned maxDistToStart = curPos - (matchesToStart ? 0 : 1); + unsigned curMaxDistHop0 = std::min(maxDistToStart, maxDistHop0); + unsigned curMaxDistHop1Plus = std::min(maxDistToStart, maxDistHop1Plus); + + PreflateHashIterator chainIt = iterateFromNode(hashHead, curPos, curMaxDistHop1Plus); + if (chainIt.dist() > curMaxDistHop0) { + return bestMatch; + } + + const unsigned char* input = inputCursor() + offset; + + unsigned maxChain = maxChainLength();/* max hash chain length */ + unsigned niceLen = maxDepth > 0 ? maxLen : std::min(niceMatchLength(), maxLen); + + if (prevLen >= goodMatchLength()) { + maxChain >>= 2; + } + if (maxDepth > 0) { + maxChain = maxDepth; + } + + unsigned bestLen = prevLen; + + do { + const unsigned char* match = input - chainIt.dist(); + + unsigned matchLength = prefixCompare(match, input, bestLen, maxLen); + if (matchLength > bestLen) { + bestLen = matchLength; + bestMatch = PreflateToken(PreflateToken::REFERENCE, matchLength, chainIt.dist()); + if (bestLen >= niceLen) { + break; + } + } + } while (chainIt.next() && maxChain-- > 1); + return bestMatch; +} + +unsigned short PreflatePredictorState::matchDepth( + const unsigned hashHead, + const PreflateToken& targetReference, + const PreflateHashChainExt& hash) { + unsigned curPos = currentInputPos(); + unsigned curMaxDist = std::min(curPos, windowSize()); + + unsigned startDepth = hash.getNodeDepth(hashHead); + PreflateHashIterator chainIt = hash.iterateFromPos(curPos - targetReference.dist, curPos, curMaxDist); + if (!chainIt.curPos || targetReference.dist > curMaxDist) { + return 0xffffu; + } + unsigned endDepth = chainIt.depth(); + return std::min(startDepth - endDepth, 0xffffu); +} + +PreflateNextMatchInfo PreflatePredictorState::nextMatchInfo( + const unsigned hashHead, + const PreflateToken& targetReference, + const PreflateHashChainExt& hash) { + PreflateNextMatchInfo result; + result.nextChainDepth = (unsigned short)~0u; + result.nextLen = 0; + result.nextDist = 0xffff; + unsigned maxLen = std::min(availableInputSize(), (unsigned)PreflateConstants::MAX_MATCH); + if (maxLen < (unsigned)PreflateConstants::MIN_MATCH) { + return result; + } + + unsigned maxDist = windowSize() - PreflateConstants::MIN_LOOKAHEAD - 1; + unsigned curPos = currentInputPos(); + unsigned curMaxDist = std::min(curPos - 1, maxDist); + unsigned curMaxDistAlt = std::min(curPos - 1, windowSize() - PreflateConstants::MIN_LOOKAHEAD); + + const unsigned char* input = inputCursor(); + unsigned startDepth = hash.getNodeDepth(hashHead); + unsigned maxChainOrg = maxChainLength();/* max hash chain length */ + PreflateHashIterator chainIt = hash.iterateFromPos(curPos - targetReference.dist, curPos, curMaxDist); + if (!chainIt.curPos || (hashHead == chainIt.curPos && chainIt.dist() > curMaxDistAlt) + || (hashHead != chainIt.curPos && chainIt.dist() > curMaxDist)) { + return result; + } + unsigned endDepth = chainIt.depth(); + unsigned maxChain = maxChainOrg - std::min(startDepth - endDepth, 0xffffu);/* max hash chain length */ + + unsigned bestLen = targetReference.len; + + while (maxChain > 0) { + if (!chainIt.next()) { + break; + } + const unsigned char* match = input - chainIt.dist(); + + unsigned matchLength = prefixCompare(match, input, bestLen, maxLen); + if (matchLength > bestLen) { + result.nextLen = matchLength; + result.nextChainDepth = maxChainOrg - maxChain; + result.nextDist = chainIt.dist(); + break; + } + --maxChain; + } + return result; +} + +PreflateRematchInfo PreflatePredictorState::rematchInfo( + const unsigned hashHead, + const PreflateToken& targetReference) { + PreflateRematchInfo result; + result.firstMatchDepth = 0xffff; + result.requestedMatchDepth = 0xffff; + result.condensedHops = 0; + unsigned maxLen = std::min(availableInputSize(), (unsigned)PreflateConstants::MAX_MATCH); + if (maxLen < targetReference.len) { + return result; + } + + unsigned maxDist = windowSize(); + unsigned curPos = currentInputPos(); + unsigned curMaxDist = std::min(curPos, maxDist); + + PreflateHashIterator chainIt = hash.iterateFromNode(hashHead, curPos, curMaxDist); + if (!chainIt) { + return result; + } + const unsigned char* input = inputCursor(); + + unsigned maxChainOrg = 0xffff;/* max hash chain length */ + unsigned maxChain = maxChainOrg;/* max hash chain length */ + + unsigned bestLen = targetReference.len; + + do { + const unsigned char* match = input - chainIt.dist(); + + unsigned matchLength = prefixCompare(match, input, bestLen - 1, bestLen); + if (matchLength >= bestLen) { + result.firstMatchDepth = std::min((unsigned)result.firstMatchDepth, maxChainOrg - maxChain); + result.condensedHops++; + } + if (chainIt.dist() >= targetReference.dist) { + if (chainIt.dist() == targetReference.dist) { + result.requestedMatchDepth = maxChainOrg - maxChain; + } + return result; + } + + chainIt.next(); + } while (!!chainIt && maxChain-- > 1); + return result; +} +unsigned PreflatePredictorState::firstMatch(const unsigned len) { + unsigned maxLen = std::min(availableInputSize(), (unsigned)PreflateConstants::MAX_MATCH); + if (maxLen < std::max(len, (unsigned)PreflateConstants::MIN_MATCH)) { + return 0; + } + + unsigned curPos = currentInputPos(); + unsigned curMaxDist = std::min(curPos, windowSize()); + + unsigned hash = calculateHash(); + + PreflateHashIterator chainIt = iterateFromHead(hash, curPos, curMaxDist); + if (!chainIt) { + return 0; + } + const unsigned char* input = inputCursor(); + + do { + const unsigned char* match = input - chainIt.dist(); + + unsigned matchLength = prefixCompare(match, input, len - 1, len); + if (matchLength >= len) { + return chainIt.dist(); + } + } while (chainIt.next()); + return 0; +} + +unsigned PreflatePredictorState::hopMatch(const PreflateToken& targetReference, const unsigned hops) { + if (hops == 0) { + return targetReference.dist; + } + + unsigned curPos = currentInputPos(); + unsigned errorDist = 0; + unsigned maxLen = std::min(availableInputSize(), (unsigned)PreflateConstants::MAX_MATCH); + if (maxLen < targetReference.len) { + return errorDist; + } + unsigned maxDist = windowSize(); + unsigned curMaxDist = std::min(curPos, maxDist); + + PreflateHashIterator chainIt = iterateFromDist(targetReference.dist, curPos, curMaxDist); + if (!chainIt) { + return 0; + } + + const unsigned char* input = inputCursor(); + + unsigned bestLen = targetReference.len; + for (unsigned todo = hops; todo > 0; ) { + if (!chainIt.next()) { + break; + } + + const unsigned char* match = input - chainIt.dist(); + + unsigned matchLength = prefixCompare(match, input - targetReference.dist, bestLen - 1, bestLen); + if (matchLength >= bestLen) { + if (--todo == 0) { + return chainIt.dist(); + } + } + } + return errorDist; +} diff --git a/contrib/preflate/preflate_predictor_state.h b/contrib/preflate/preflate_predictor_state.h new file mode 100644 index 0000000..67ae4c5 --- /dev/null +++ b/contrib/preflate/preflate_predictor_state.h @@ -0,0 +1,119 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_PREDICTOR_STATE_H +#define PREFLATE_PREDICTOR_STATE_H + +#include + +#include "preflate_input.h" +#include "preflate_hash_chain.h" +#include "preflate_parser_config.h" +#include "preflate_token.h" + +struct PreflatePreviousMatchInfo { + PreflateToken previousMatches[256]; +}; + +struct PreflateNextMatchInfo { + unsigned short nextChainDepth; + unsigned short nextLen; + unsigned short nextDist; +}; + +struct PreflateRematchInfo { + unsigned short firstMatchDepth; + unsigned short firstMatchDist; + unsigned short requestedMatchDepth; + unsigned short condensedHops; +}; + +struct PreflatePredictorState { + const PreflateHashChainExt& hash; + unsigned short windowBytes; + unsigned maxTokenCount; + const PreflateParserConfig& config; + + PreflatePredictorState(const PreflateHashChainExt&, + const PreflateParserConfig&, + const int wbits, + const int mbits); + + unsigned currentInputPos() const { + return hash.input().pos(); + } + const unsigned char* inputCursor() const { + return hash.input().curChars(); + } + unsigned windowSize() const { + return windowBytes; + } + unsigned availableInputSize() const { + return hash.input().remaining(); + } + unsigned maxChainLength() const { + return config.max_chain; + } + unsigned niceMatchLength() const { + return config.nice_length; + } + unsigned goodMatchLength() const { + return config.good_length; + } + unsigned lazyMatchLength() const { + return config.max_lazy; + } + unsigned calculateHash() const { + return hash.curHash(); + } + unsigned calculateHashNext() const { + return hash.curPlus1Hash(); + } + unsigned getCurrentHashHead(const unsigned hashNext) const { + return hash.getHead(hashNext); + } + + PreflateHashIterator iterateFromHead(const unsigned hash_, const unsigned refPos, const unsigned maxDist) const { + return hash.iterateFromHead(hash_, refPos, maxDist); + } + PreflateHashIterator iterateFromNode(const unsigned node_, const unsigned refPos, const unsigned maxDist) const { + return hash.iterateFromNode(node_, refPos, maxDist); + } + PreflateHashIterator iterateFromDist(const unsigned dist_, const unsigned refPos, const unsigned maxDist) const { + return hash.iterateFromPos(refPos - dist_, refPos, maxDist); + } + + static unsigned prefixCompare( + const unsigned char* s1, + const unsigned char* s2, + const unsigned bestLen, + const unsigned maxLen); + + PreflateToken match( + const unsigned hashHead, + const unsigned prevLen, + const unsigned offset, + const bool veryFarMatches, + const bool matchesToStart, + const unsigned maxDepth); + unsigned short matchDepth(const unsigned hashHead, const PreflateToken& targetReference, + const PreflateHashChainExt&); + PreflateNextMatchInfo nextMatchInfo(const unsigned hashHead, const PreflateToken& targetReference, + const PreflateHashChainExt&); + PreflateRematchInfo rematchInfo(const unsigned hashHead, const PreflateToken& targetReference); + unsigned firstMatch(const unsigned len); + unsigned hopMatch(const PreflateToken& token, const unsigned hops); +}; + +#endif /* PREFLATE_PREDICTOR_STATE_H */ diff --git a/contrib/preflate/preflate_reencoder.cpp b/contrib/preflate/preflate_reencoder.cpp new file mode 100644 index 0000000..cf555a8 --- /dev/null +++ b/contrib/preflate/preflate_reencoder.cpp @@ -0,0 +1,106 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "preflate_block_reencoder.h" +#include "preflate_reencoder.h" +#include "preflate_statistical_codec.h" +#include "preflate_token_predictor.h" +#include "preflate_tree_predictor.h" +#include "support/bitstream.h" +#include "support/memstream.h" + +bool preflate_reencode(std::vector& deflate_raw, + const std::vector& preflate_diff, + const std::vector& unpacked_input) { + PreflateStatisticalDecoder codec(preflate_diff); + if (!codec.decodeHeader()) { + return false; + } + PreflateParameters params; + if (!codec.decodeParameters(params)) { + return false; + } + if (!codec.decodeModel()) { + return false; + } + PreflateTokenPredictor tokenPredictor(params, unpacked_input); + PreflateTreePredictor treePredictor(unpacked_input); + + MemStream mem; + BitOutputStream bos(mem); + + PreflateBlockReencoder deflater(bos, unpacked_input); + bool eof = true; + do { + PreflateTokenBlock block = tokenPredictor.decodeBlock(&codec); + if (!treePredictor.decodeBlock(block, &codec)) { + return false; + } + if (tokenPredictor.predictionFailure || treePredictor.predictionFailure) { + return false; + } + eof = tokenPredictor.decodeEOF(&codec); + + deflater.writeBlock(block, eof); + } while (!eof); + deflater.flush(); + deflate_raw = mem.extractData(); + return true; +} +bool preflate_reencode(OutputStream& os, + const std::vector& preflate_diff, + const std::vector& unpacked_input, + std::function block_callback) { + PreflateStatisticalDecoder codec(preflate_diff); + if (!codec.decodeHeader()) { + return false; + } + PreflateParameters params; + if (!codec.decodeParameters(params)) { + return false; + } + if (!codec.decodeModel()) { + return false; + } + PreflateTokenPredictor tokenPredictor(params, unpacked_input); + PreflateTreePredictor treePredictor(unpacked_input); + + BitOutputStream bos(os); + + PreflateBlockReencoder deflater(bos, unpacked_input); + bool eof = true; + do { + PreflateTokenBlock block = tokenPredictor.decodeBlock(&codec); + if (!treePredictor.decodeBlock(block, &codec)) { + return false; + } + if (tokenPredictor.predictionFailure || treePredictor.predictionFailure) { + return false; + } + eof = tokenPredictor.decodeEOF(&codec); + + deflater.writeBlock(block, eof); + block_callback(); + } while (!eof); + uint8_t remaining_bit_count = (8 - bos.bitPos()) & 7; + if (remaining_bit_count > 0) { + bool non_zero_bits = codec.decodeValue(1) != 0; + if (non_zero_bits) { + bos.put(codec.decodeValue(remaining_bit_count), remaining_bit_count); + } + } + deflater.flush(); + return true; +} diff --git a/contrib/preflate/preflate_reencoder.h b/contrib/preflate/preflate_reencoder.h new file mode 100644 index 0000000..080e22d --- /dev/null +++ b/contrib/preflate/preflate_reencoder.h @@ -0,0 +1,29 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_REENCODER_H +#define PREFLATE_REENCODER_H + +#include + +bool preflate_reencode(std::vector& deflate_raw, + const std::vector& preflate_diff, + const std::vector& unpacked_input); + +bool preflate_reencode(OutputStream& os, + const std::vector& preflate_diff, + const std::vector& unpacked_input, + std::function block_callback); + +#endif /* PREFLATE_REENCODER_H */ diff --git a/contrib/preflate/preflate_statistical_codec.cpp b/contrib/preflate/preflate_statistical_codec.cpp new file mode 100644 index 0000000..5fd53b2 --- /dev/null +++ b/contrib/preflate/preflate_statistical_codec.cpp @@ -0,0 +1,789 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "preflate_parameter_estimator.h" +#include "preflate_statistical_codec.h" +#include "preflate_statistical_model.h" +#include "packARI/source/bitops.h" +#include "packARI/source/aricoder.h" +#include "support/array_helper.h" +#include "support/bit_helper.h" +#include + +template +struct PreflateCodecSubModel { + static const unsigned L = N; + PreflateCodecSubModel(const unsigned(&arr)[N]) { + memcpy(bounds, arr, sizeof(arr)); + build(); + } + PreflateCodecSubModel() { + } + void build() { + unsigned backup[N]; + for (unsigned i = 0; i < N; ++i) { + ids[i] = i; + backup[i] = bounds[i]; + } + std::sort(ids, ids + N, [=](unsigned i1, unsigned i2) { + if (backup[i1] != backup[i2]) { + return backup[i1] < backup[i2]; + } + return i1 < i2; + }); + for (unsigned i = 0; i < N; ++i) { + bounds[i] = backup[ids[i]]; + rids[ids[i]] = i; + } + unsigned sum = sumArray(bounds, N), acc, prev; + prev = bounds[0]; + bounds[0] = acc = 0; + for (unsigned i = 0; i < N; ++i) { + if (prev) { + acc += prev; + prev = bounds[i + 1]; + int diff = (((uint64_t)acc) << 16) / sum - bounds[i]; + unsigned diff_bits = bitLength(diff); + const unsigned k = 5; + if (diff > 0 && diff_bits > k) { + diff = diff & (((1 << k) - 1) << (diff_bits - k)); + } +// bounds[i + 1] = (((uint64_t)acc) << 16) / sum; + bounds[i + 1] = bounds[i] + diff; + if (bounds[i + 1] <= bounds[i]) { + bounds[i + 1] = bounds[i] + 1; + } + } else { + prev = bounds[i + 1]; + bounds[i + 1] = bounds[i]; + } + } + if (bounds[N] > 0) { + bounds[N] = 1 << 16; + } + } + void encode(aricoder* codec, const unsigned item) { + symbol s; + s.scale = 1 << 16; + s.low_count = bounds[rids[item]]; + s.high_count = bounds[rids[item] + 1]; + codec->encode(&s); + } + unsigned decode(aricoder* codec) { + symbol s; + s.scale = 1 << 16; + unsigned cnt = codec->decode_count(&s); + for (unsigned i = 0; i < N; ++i) { + if (cnt < bounds[i + 1]) { + s.low_count = bounds[i]; + s.high_count = bounds[i + 1]; + codec->decode(&s); + return ids[i]; + } + } + return 0; + } + bool isEqualTo(const PreflateCodecSubModel& m) const { + for (unsigned i = 0; i < N; ++i) { + if (bounds[i] != m.bounds[i]) { + return false; + } + if (bounds[i + 1] > 0 && ids[i] != m.ids[i]) { + return false; + } + } + if (bounds[N] != m.bounds[N]) { + return false; + } + return true; + } + + unsigned bounds[N + 1]; + unsigned short ids[N], rids[N]; +}; + +template +struct PreflateCodecCorrectionSubModel { + static const unsigned L = N; + PreflateCodecCorrectionSubModel(const unsigned(&arr1)[N + zero], + const unsigned(&arr2)[N]) + : sign() + , pos() + , neg(arr2) { + memcpy(pos.bounds, arr1 + zero, N * sizeof(unsigned)); + pos.build(); + + if (zero) { + sign.bounds[1] = arr1[0]; + } + sign.bounds[0] = sumArray(arr1 + zero, N); + sign.bounds[1 + zero] = sumArray(arr2); + sign.build(); + } + PreflateCodecCorrectionSubModel() { + } + void encode(aricoder* codec, const int value, + const unsigned refvalue, + const unsigned minvalue, + const unsigned maxvalue) { + if (value == 0) { + sign.encode(codec, 1); + return; + } + if (value > 0) { + sign.encode(codec, 0); + if (value >= (int)N) { + pos.encode(codec, N - 1); + PreflateStatisticalEncoder::encodeValue(codec, value - N, bitLength(maxvalue - N - refvalue)); + } else { + pos.encode(codec, value - 1); + } + } else { + sign.encode(codec, 1 + zero); + if (value <= -(int)N) { + neg.encode(codec, N - 1); + PreflateStatisticalEncoder::encodeValue(codec, -value - N, bitLength(refvalue - N - minvalue)); + } else { + neg.encode(codec, -value - 1); + } + } + } + int decode(aricoder* codec, + const unsigned refvalue, + const unsigned minvalue, + const unsigned maxvalue) { + int val = sign.decode(codec); + if (zero && val == 1) { + return 0; + } + if (val == 0) { + val = pos.decode(codec); + if (val >= (int)(N - 1)) { + return PreflateStatisticalDecoder::decodeValue(codec, bitLength(maxvalue - N - refvalue)) + N; + } else { + return val + 1; + } + } else { + val = neg.decode(codec); + if (val >= (int)(N - 1)) { + return -PreflateStatisticalDecoder::decodeValue(codec, bitLength(refvalue - N - minvalue)) - N; + } else { + return -val - 1; + } + } + } + bool isEqualTo(const PreflateCodecCorrectionSubModel& m) const { + return sign.isEqualTo(m.sign) + && pos.isEqualTo(m.pos) + && neg.isEqualTo(m.neg); + } + + PreflateCodecSubModel<2+zero> sign; + PreflateCodecSubModel pos; + PreflateCodecSubModel neg; +}; + +struct PreflateCodecModel { + // Blocks + PreflateCodecSubModel<3> blockType; + PreflateCodecSubModel<2> EOBMisprediction; + // Tokens + PreflateCodecSubModel<2> LITMisprediction; + PreflateCodecSubModel<2> REFMisprediction; + PreflateCodecSubModel<2> LENMisprediction; + PreflateCodecSubModel<2> DISTOnlyMisprediction; + PreflateCodecCorrectionSubModel<6,false> LENCorrection; + PreflateCodecSubModel<4> DISTAfterLenCorrection; + PreflateCodecSubModel<4> DISTOnlyCorrection; + // Trees + PreflateCodecSubModel<2> TCCountMisprediction; + PreflateCodecCorrectionSubModel<3,true> TCBitlengthCorrection; + PreflateCodecSubModel<2> LCountMisprediction; + PreflateCodecSubModel<2> DCountMisprediction; + PreflateCodecSubModel<2> LDTypeMisprediction_B; + PreflateCodecSubModel<2> LDTypeMisprediction_R; + PreflateCodecSubModel<2> LDTypeMisprediction_0s; + PreflateCodecSubModel<2> LDTypeMisprediction_0l; + PreflateCodecSubModel<2>* LDTypeMisprediction[4]; + PreflateCodecSubModel<4> LDTypeReplacement; + PreflateCodecSubModel<2> LDRepeatCountMisprediction; + PreflateCodecCorrectionSubModel<4,true> LDBitlengthCorrection; + + PreflateCodecModel(const PreflateStatisticalModel& model) + : blockType(model.blockType) + , EOBMisprediction(model.EOBMisprediction) + , LITMisprediction(model.LITMisprediction) + , REFMisprediction(model.REFMisprediction) + , LENMisprediction(model.LENMisprediction) + , DISTOnlyMisprediction(model.DISTOnlyMisprediction) + , LENCorrection(model.LENPositiveCorrection, model.LENNegativeCorrection) + , DISTAfterLenCorrection(model.DISTAfterLenCorrection) + , DISTOnlyCorrection(model.DISTOnlyCorrection) + , TCCountMisprediction(model.TCCountMisprediction) + , TCBitlengthCorrection(model.TCBitlengthPositiveCorrection, + model.TCBitlengthNegativeCorrection) + , LCountMisprediction(model.LCountMisprediction) + , DCountMisprediction(model.DCountMisprediction) + , LDTypeMisprediction_B(model.LDTypeMisprediction[0]) + , LDTypeMisprediction_R(model.LDTypeMisprediction[1]) + , LDTypeMisprediction_0s(model.LDTypeMisprediction[2]) + , LDTypeMisprediction_0l(model.LDTypeMisprediction[3]) + , LDTypeMisprediction{&LDTypeMisprediction_B, &LDTypeMisprediction_R, + &LDTypeMisprediction_0s, &LDTypeMisprediction_0l} + , LDTypeReplacement(model.LDTypeReplacement) + , LDRepeatCountMisprediction(model.LDRepeatCountMisprediction) + , LDBitlengthCorrection(model.LDBitlengthPositiveCorrection, + model.LDBitlengthNegativeCorrection) { + } + PreflateCodecModel() + : LDTypeMisprediction {&LDTypeMisprediction_B, &LDTypeMisprediction_R, + &LDTypeMisprediction_0s, &LDTypeMisprediction_0l} { + } + bool isEqualTo(const PreflateCodecModel& m) const { + return blockType.isEqualTo(m.blockType) + && EOBMisprediction.isEqualTo(m.EOBMisprediction) + && LITMisprediction.isEqualTo(m.LITMisprediction) + && REFMisprediction.isEqualTo(m.REFMisprediction) + && LENMisprediction.isEqualTo(m.LENMisprediction) + && DISTOnlyMisprediction.isEqualTo(m.DISTOnlyMisprediction) + && LENCorrection.isEqualTo(m.LENCorrection) + && DISTAfterLenCorrection.isEqualTo(m.DISTAfterLenCorrection) + && DISTOnlyCorrection.isEqualTo(m.DISTOnlyCorrection) + && TCCountMisprediction.isEqualTo(m.TCCountMisprediction) + && TCBitlengthCorrection.isEqualTo(m.TCBitlengthCorrection) + && LCountMisprediction.isEqualTo(m.LCountMisprediction) + && DCountMisprediction.isEqualTo(m.DCountMisprediction) + && LDTypeMisprediction_B.isEqualTo(m.LDTypeMisprediction_B) + && LDTypeMisprediction_R.isEqualTo(m.LDTypeMisprediction_R) + && LDTypeMisprediction_0s.isEqualTo(m.LDTypeMisprediction_0s) + && LDTypeMisprediction_0l.isEqualTo(m.LDTypeMisprediction_0l) + && LDTypeReplacement.isEqualTo(m.LDTypeReplacement) + && LDRepeatCountMisprediction.isEqualTo(m.LDRepeatCountMisprediction) + && LDBitlengthCorrection.isEqualTo(m.LDBitlengthCorrection); + } +}; + +PreflateStatisticalEncoder::PreflateStatisticalEncoder(const PreflateStatisticalModel& model_) { + data = new iostream(nullptr, TYPE_MEMORY, 0, MODE_WRITE); + codec = new aricoder(data, MODE_WRITE); + model = new PreflateCodecModel(model_); +} +PreflateStatisticalEncoder::~PreflateStatisticalEncoder() { + delete model; + delete codec; + delete data; +} + +void PreflateStatisticalEncoder::encode(const PreflateCorrectionType& type, const int value, const unsigned refvalue) { + switch (type) { + // Block + case CORR_BLOCK_TYPE: + model->blockType.encode(codec, value); + break; + case CORR_EOB_MISPREDICTION: + model->EOBMisprediction.encode(codec, value); + break; + // Tokens + case CORR_LIT_MISPREDICTION: + model->LITMisprediction.encode(codec, value); + break; + case CORR_REF_MISPREDICTION: + model->REFMisprediction.encode(codec, value); + break; + case CORR_LEN_MISPREDICTION: + model->LENMisprediction.encode(codec, value); + break; + case CORR_LEN_CORRECTION: + model->LENCorrection.encode(codec, value, refvalue, 3, 258); + break; + case CORR_DIST_AFTER_LEN_CORRECTION: + if (value >= (int)model->DISTAfterLenCorrection.L - 1) { + model->DISTAfterLenCorrection.encode(codec, model->DISTAfterLenCorrection.L - 1); + encodeValue(value - (model->DISTAfterLenCorrection.L - 1), 15); + } else { + model->DISTAfterLenCorrection.encode(codec, value); + } + break; + + case CORR_DIST_ONLY_MISPREDICTION: + model->DISTOnlyMisprediction.encode(codec, value); + break; + case CORR_DIST_ONLY_CORRECTION: + if (value >= (int)model->DISTOnlyCorrection.L - 1) { + model->DISTOnlyCorrection.encode(codec, model->DISTOnlyCorrection.L - 1); + encodeValue(value - (model->DISTOnlyCorrection.L - 1), 15); + } else { + model->DISTOnlyCorrection.encode(codec, value); + } + break; + // Trees + case CORR_L_COUNT_MISPREDICTION: + model->LCountMisprediction.encode(codec, value); + break; + case CORR_D_COUNT_MISPREDICTION: + model->DCountMisprediction.encode(codec, value); + break; + case CORR_LD_TYPE_MISPREDICTION: + model->LDTypeMisprediction[refvalue]->encode(codec, value); + break; + case CORR_LD_TYPE_REPLACEMENT: + model->LDTypeReplacement.encode(codec, value); + break; + case CORR_LD_REPEAT_MISPREDICTION: + model->LDRepeatCountMisprediction.encode(codec, value); + break; + case CORR_LD_BITLENGTH_CORRECTION: + model->LDBitlengthCorrection.encode(codec, value, refvalue, 0, 15); + break; + case CORR_TC_COUNT_MISPREDICTION: + model->TCCountMisprediction.encode(codec, value); + break; + case CORR_TC_BITLENGTH_CORRECTION: + model->TCBitlengthCorrection.encode(codec, value, refvalue, 0, 7); + break; + } +} +void PreflateStatisticalEncoder::encodeValue(aricoder* codec_, const unsigned value, const unsigned maxBits) { + symbol s; + s.scale = 1 << maxBits; + s.low_count = value; + s.high_count = value + 1; + codec_->encode(&s); +} +void PreflateStatisticalEncoder::encodeValue(const unsigned value, const unsigned maxBits) { + encodeValue(codec, value, maxBits); +} + + +struct PreflateCodecModelModel { + PreflateCodecModelModel() { + } + template + void check(const PreflateCodecSubModel& m) { + for (unsigned i = 1; i < N; ++i) { + stat_count++; + if (!m.bounds[i]) { + zero_count++; + } + } + end_stat_count++; + if (!m.bounds[N]) { + end_zero_count++; + } + } + template + void check(const PreflateCodecCorrectionSubModel& m) { + check(m.sign); + check(m.pos); + check(m.neg); + } + void check(const PreflateCodecModel& m) { + zero_count = stat_count = 0; + end_zero_count = end_stat_count = 0; + // Blocks + check(m.blockType); + check(m.EOBMisprediction); + // Tokens + check(m.LITMisprediction); + check(m.REFMisprediction); + check(m.LENMisprediction); + check(m.DISTOnlyMisprediction); + check(m.LENCorrection); + check(m.DISTAfterLenCorrection); + check(m.DISTOnlyCorrection); + // Trees + check(m.TCCountMisprediction); + check(m.TCBitlengthCorrection); + check(m.LCountMisprediction); + check(m.DCountMisprediction); + check(m.LDTypeMisprediction_B); + check(m.LDTypeMisprediction_R); + check(m.LDTypeMisprediction_0s); + check(m.LDTypeMisprediction_0l); + check(m.LDTypeReplacement); + check(m.LDRepeatCountMisprediction); + check(m.LDBitlengthCorrection); + } + + void encodeVal(aricoder* codec, const unsigned val) { + unsigned bits = bitLength(val); + // encode shift + PreflateStatisticalEncoder::encodeValue(codec, bits - 1, 4); + // and precision + if (bits >= 5) { + PreflateStatisticalEncoder::encodeValue(codec, (val >> (bits - 5)) & 0xf, 4); + } else { + PreflateStatisticalEncoder::encodeValue(codec, val & ~(1 << (bits - 1)), bits - 1); + } + } + void encodeId(aricoder* codec, + const unsigned id, const unsigned count) { + unsigned bits = bitLength(count - 1); + PreflateStatisticalEncoder::encodeValue(codec, id, bits); + } + + template + void encode(aricoder* codec, const PreflateCodecSubModel& m) { + // Mark zero values + for (unsigned i = 1; i < N + 1; ++i) { + if (!m.bounds[i]) { + codec->encode(i == N ? &ez : &z); + } else { + codec->encode(i == N ? &enz : &nz); + break; + } + } + // Transmit values + for (unsigned i = 1; i < N; ++i) { + if (m.bounds[i]) { + encodeVal(codec, m.bounds[i] - m.bounds[i - 1]); + } + } + // Transmit ids + for (unsigned i = 0; i < N; ++i) { + if (m.bounds[i + 1]) { + encodeId(codec, m.ids[i], N); + } + } + } + template + void encode(aricoder* codec, const PreflateCodecCorrectionSubModel& m) { + encode(codec, m.sign); + encode(codec, m.pos); + encode(codec, m.neg); + } + void encode(aricoder* codec, const PreflateCodecModel& m) { + PreflateStatisticalEncoder::encodeValue(codec, zero_count, bitLength(stat_count)); + PreflateStatisticalEncoder::encodeValue(codec, end_zero_count, bitLength(end_stat_count)); + + nz.scale = z.scale = stat_count; // current number of statistics + z.low_count = 0; + nz.low_count = z.high_count = zero_count; + nz.high_count = nz.scale; + + enz.scale = ez.scale = end_stat_count; // current number of statistics + ez.low_count = 0; + enz.low_count = ez.high_count = end_zero_count; + enz.high_count = end_stat_count; + + // Blocks + encode(codec, m.blockType); + encode(codec, m.EOBMisprediction); + // Tokens + encode(codec, m.LITMisprediction); + encode(codec, m.REFMisprediction); + encode(codec, m.LENMisprediction); + encode(codec, m.DISTOnlyMisprediction); + encode(codec, m.LENCorrection); + encode(codec, m.DISTAfterLenCorrection); + encode(codec, m.DISTOnlyCorrection); + // Trees + encode(codec, m.TCCountMisprediction); + encode(codec, m.TCBitlengthCorrection); + encode(codec, m.LCountMisprediction); + encode(codec, m.DCountMisprediction); + encode(codec, m.LDTypeMisprediction_B); + encode(codec, m.LDTypeMisprediction_R); + encode(codec, m.LDTypeMisprediction_0s); + encode(codec, m.LDTypeMisprediction_0l); + encode(codec, m.LDTypeReplacement); + encode(codec, m.LDRepeatCountMisprediction); + encode(codec, m.LDBitlengthCorrection); + } + + unsigned decodeVal(aricoder* codec) { + // encode shift + unsigned bits = PreflateStatisticalDecoder::decodeValue(codec, 4) + 1; + // and precision + if (bits >= 5) { + return (PreflateStatisticalDecoder::decodeValue(codec, 4) | 0x10) << (bits - 5); + } else { + return PreflateStatisticalDecoder::decodeValue(codec, bits - 1) | (1 << (bits - 1)); + } + } + unsigned decodeId(aricoder* codec, const unsigned count) { + unsigned bits = bitLength(count - 1); + return PreflateStatisticalDecoder::decodeValue(codec, bits); + } + + template + void decode(aricoder* codec, PreflateCodecSubModel& m) { + // Mark zero values + unsigned i; + m.bounds[0] = 0; + for (i = 1; i < N + 1; ++i) { + symbol* s = i == N ? &enz : &nz; + unsigned cnt = codec->decode_count(s); + if (cnt >= s->low_count) { + codec->decode(s); + break; + } + codec->decode(i == N ? &ez : &z); + m.bounds[i] = 0; + } + if (i < N + 1) { + m.bounds[N] = 1 << 16; + } + // Transmit values + unsigned j = i; + for (; i < N; ++i) { + m.bounds[i] = m.bounds[i - 1] + decodeVal(codec); + } + // Transmit ids + for (i = j - 1; i < N; ++i) { + m.ids[i] = decodeId(codec, N); + } + } + template + void decode(aricoder* codec, PreflateCodecCorrectionSubModel& m) { + decode(codec, m.sign); + decode(codec, m.pos); + decode(codec, m.neg); + } + void decode(aricoder* codec, PreflateCodecModel& m) { + zero_count = PreflateStatisticalDecoder::decodeValue(codec, bitLength(stat_count)); + end_zero_count = PreflateStatisticalDecoder::decodeValue(codec, bitLength(end_stat_count)); + + nz.scale = z.scale = stat_count; // current number of statistics + z.low_count = 0; + nz.low_count = z.high_count = zero_count; + nz.high_count = nz.scale; + + enz.scale = ez.scale = end_stat_count; // current number of statistics + ez.low_count = 0; + enz.low_count = ez.high_count = end_zero_count; + enz.high_count = end_stat_count; + + // Blocks + decode(codec, m.blockType); + decode(codec, m.EOBMisprediction); + // Tokens + decode(codec, m.LITMisprediction); + decode(codec, m.REFMisprediction); + decode(codec, m.LENMisprediction); + decode(codec, m.DISTOnlyMisprediction); + decode(codec, m.LENCorrection); + decode(codec, m.DISTAfterLenCorrection); + decode(codec, m.DISTOnlyCorrection); + // Trees + decode(codec, m.TCCountMisprediction); + decode(codec, m.TCBitlengthCorrection); + decode(codec, m.LCountMisprediction); + decode(codec, m.DCountMisprediction); + decode(codec, m.LDTypeMisprediction_B); + decode(codec, m.LDTypeMisprediction_R); + decode(codec, m.LDTypeMisprediction_0s); + decode(codec, m.LDTypeMisprediction_0l); + decode(codec, m.LDTypeReplacement); + decode(codec, m.LDRepeatCountMisprediction); + decode(codec, m.LDBitlengthCorrection); + } + + unsigned stat_count, zero_count; + unsigned end_stat_count, end_zero_count; + symbol z, nz, ez, enz; +}; + +void PreflateStatisticalEncoder::encodeModel() { + PreflateCodecModelModel modelmodel; + modelmodel.check(*model); + modelmodel.encode(codec, *model); +} + +void PreflateStatisticalEncoder::encodeHeader() { + encodeValue('P', 8); + encodeValue('F', 8); + encodeValue(0x01, 8); +} + +void PreflateStatisticalEncoder::encodeParameters(const PreflateParameters& params) { + encodeValue(params.zlibCompatible, 1); + encodeValue(params.windowBits - 8, 3); + encodeValue(params.memLevel, 4); + encodeValue(params.compLevel, 4); + encodeValue(params.strategy, 2); + encodeValue(params.huffStrategy, 2); + encodeValue(params.farLen3MatchesDetected, 1); + encodeValue(params.veryFarMatchesDetected, 1); + encodeValue(params.matchesToStartDetected, 1); + encodeValue(params.log2OfMaxChainDepthM1, 4); +} +std::vector PreflateStatisticalEncoder::encodeFinish() { + delete codec; + codec = nullptr; + std::vector result(data->getptr(), data->getptr() + data->getsize()); + delete data; + data = nullptr; +// delete model; +// model = nullptr; + return result; +} + + +PreflateStatisticalDecoder::PreflateStatisticalDecoder(const std::vector& x) : storage(x) { + data = new iostream(&storage[0], TYPE_MEMORY, storage.size(), MODE_READ); + codec = new aricoder(data, MODE_READ); + model = nullptr; +} +PreflateStatisticalDecoder::~PreflateStatisticalDecoder() { + delete model; + delete codec; + delete data; +} + +bool PreflateStatisticalDecoder::decodeHeader() { + if (decodeValue(8) != 'P') { + return false; + } + if (decodeValue(8) != 'F') { + return false; + } + if (decodeValue(8) != 0x01) { + return false; + } + return true; +} +bool PreflateStatisticalDecoder::decodeParameters(PreflateParameters& params) { + params.zlibCompatible = decodeValue(1) != 0; + params.windowBits = decodeValue(3) + 8; + params.memLevel = decodeValue(4); + params.compLevel = decodeValue(4); + + unsigned n = decodeValue(2); + switch (n) { + case PREFLATE_DEFAULT: + params.strategy = PREFLATE_DEFAULT; + break; + case PREFLATE_RLE_ONLY: + params.strategy = PREFLATE_RLE_ONLY; + break; + case PREFLATE_HUFF_ONLY: + params.strategy = PREFLATE_HUFF_ONLY; + break; + case PREFLATE_STORE: + params.strategy = PREFLATE_STORE; + break; + } + n = decodeValue(2); + switch (n) { + case PREFLATE_HUFF_DYNAMIC: + params.huffStrategy = PREFLATE_HUFF_DYNAMIC; + break; + case PREFLATE_HUFF_MIXED: + params.huffStrategy = PREFLATE_HUFF_MIXED; + break; + case PREFLATE_HUFF_STATIC: + params.huffStrategy = PREFLATE_HUFF_STATIC; + break; + } + params.farLen3MatchesDetected = decodeValue(1) != 0; + params.veryFarMatchesDetected = decodeValue(1) != 0; + params.matchesToStartDetected = decodeValue(1) != 0; + params.log2OfMaxChainDepthM1 = decodeValue(4); + return params.compLevel >= 1 && params.compLevel <= 9 + && params.memLevel >= 1 && params.memLevel <= 9 + && params.windowBits >= 8 && params.windowBits <= 15; +} +void PreflateStatisticalDecoder::decodeFinish() { + delete codec; + codec = nullptr; + delete data; + data = nullptr; + delete model; + model = nullptr; + storage.clear(); +} + +int PreflateStatisticalDecoder::decode(const PreflateCorrectionType& type, const unsigned refvalue) { + switch (type) { + // Block + case CORR_BLOCK_TYPE: + return model->blockType.decode(codec); + case CORR_EOB_MISPREDICTION: + return model->EOBMisprediction.decode(codec); + // Tokens + case CORR_LIT_MISPREDICTION: + return model->LITMisprediction.decode(codec); + case CORR_REF_MISPREDICTION: + return model->REFMisprediction.decode(codec); + case CORR_LEN_MISPREDICTION: + return model->LENMisprediction.decode(codec); + case CORR_LEN_CORRECTION: + return model->LENCorrection.decode(codec, refvalue, 3, 258); + case CORR_DIST_AFTER_LEN_CORRECTION: { + unsigned val = model->DISTAfterLenCorrection.decode(codec); + if (val >= model->DISTAfterLenCorrection.L - 1) { + return decodeValue(15) + (model->DISTAfterLenCorrection.L - 1); + } else { + return val; + } + } + case CORR_DIST_ONLY_MISPREDICTION: + return model->DISTOnlyMisprediction.decode(codec); + case CORR_DIST_ONLY_CORRECTION: { + unsigned val = model->DISTOnlyCorrection.decode(codec); + if (val >= model->DISTOnlyCorrection.L - 1) { + return decodeValue(15) + (model->DISTOnlyCorrection.L - 1); + } else { + return val; + } + } + // Trees + case CORR_L_COUNT_MISPREDICTION: + return model->LCountMisprediction.decode(codec); + case CORR_D_COUNT_MISPREDICTION: + return model->DCountMisprediction.decode(codec); + case CORR_LD_TYPE_MISPREDICTION: + return model->LDTypeMisprediction[refvalue]->decode(codec); + case CORR_LD_TYPE_REPLACEMENT: + return model->LDTypeReplacement.decode(codec); + case CORR_LD_REPEAT_MISPREDICTION: + return model->LDRepeatCountMisprediction.decode(codec); + case CORR_LD_BITLENGTH_CORRECTION: + return model->LDBitlengthCorrection.decode(codec, refvalue, 0, 15); + case CORR_TC_COUNT_MISPREDICTION: + return model->TCCountMisprediction.decode(codec); + case CORR_TC_BITLENGTH_CORRECTION: + return model->TCBitlengthCorrection.decode(codec, refvalue, 0, 7); + default: + return 0; + } +} +unsigned PreflateStatisticalDecoder::decodeValue(aricoder* codec_, const unsigned maxBits) { + symbol s; + s.scale = 1 << maxBits; + unsigned cnt = codec_->decode_count(&s); + s.low_count = cnt; + s.high_count = cnt + 1; + codec_->decode(&s); + return cnt; +} +unsigned PreflateStatisticalDecoder::decodeValue(const unsigned maxBits) { + return decodeValue(codec, maxBits); +} + +bool PreflateStatisticalDecoder::decodeModel() { + delete model; + model = new PreflateCodecModel; + PreflateCodecModelModel modelmodel; + modelmodel.check(*model); + modelmodel.decode(codec, *model); + return true; +} + +bool isEqual(const PreflateCodecModel& m1, const PreflateCodecModel& m2) { + return m1.isEqualTo(m2); +} diff --git a/contrib/preflate/preflate_statistical_codec.h b/contrib/preflate/preflate_statistical_codec.h new file mode 100644 index 0000000..5b2f656 --- /dev/null +++ b/contrib/preflate/preflate_statistical_codec.h @@ -0,0 +1,90 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_STATISTICAL_CODEC_H +#define PREFLATE_STATISTICAL_CODEC_H + +#include + +struct PreflateParameters; + +class iostream; +class aricoder; + +enum PreflateCorrectionType { + // Block + CORR_BLOCK_TYPE, + CORR_EOB_MISPREDICTION, + // Tokens + CORR_LIT_MISPREDICTION, + CORR_REF_MISPREDICTION, + CORR_LEN_MISPREDICTION, + CORR_LEN_CORRECTION, + CORR_DIST_AFTER_LEN_CORRECTION, + CORR_DIST_ONLY_MISPREDICTION, + CORR_DIST_ONLY_CORRECTION, + // Trees + CORR_L_COUNT_MISPREDICTION, + CORR_D_COUNT_MISPREDICTION, + CORR_LD_TYPE_MISPREDICTION, + CORR_LD_TYPE_REPLACEMENT, + CORR_LD_REPEAT_MISPREDICTION, + CORR_LD_BITLENGTH_CORRECTION, + CORR_TC_COUNT_MISPREDICTION, + CORR_TC_BITLENGTH_CORRECTION, +}; + +enum Codec { ENCODER, DECODER }; + +struct PreflateStatisticalModel; +struct PreflateCodecModel; + +struct PreflateStatisticalEncoder { + PreflateStatisticalEncoder(const PreflateStatisticalModel&); + ~PreflateStatisticalEncoder(); + + void encodeHeader(); + void encodeParameters(const PreflateParameters&); + void encodeModel(); + void encode(const PreflateCorrectionType& type, const int value, const unsigned refvalue = 0); + void encodeValue(const unsigned value, const unsigned maxBits); + static void encodeValue(aricoder* codec, const unsigned value, const unsigned maxBits); + std::vector encodeFinish(); + + iostream* data; + aricoder* codec; + PreflateCodecModel* model; +}; + +struct PreflateStatisticalDecoder { + PreflateStatisticalDecoder(const std::vector&); + ~PreflateStatisticalDecoder(); + + bool decodeHeader(); + bool decodeParameters(PreflateParameters&); + bool decodeModel(); + int decode(const PreflateCorrectionType& type, const unsigned refvalue = 0); + unsigned decodeValue(const unsigned maxBits); + void decodeFinish(); + static unsigned decodeValue(aricoder*, const unsigned maxBits); + + std::vector storage; + iostream* data; + aricoder* codec; + PreflateCodecModel* model; +}; + +bool isEqual(const PreflateCodecModel&, const PreflateCodecModel&); + +#endif /* PREFLATE_STATISTICAL_CODEC_H */ diff --git a/contrib/preflate/preflate_statistical_model.cpp b/contrib/preflate/preflate_statistical_model.cpp new file mode 100644 index 0000000..b82b5fa --- /dev/null +++ b/contrib/preflate/preflate_statistical_model.cpp @@ -0,0 +1,91 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include "preflate_statistical_model.h" +#include "support/array_helper.h" +#include + +void printFlagStatistics(const char *txt, unsigned(&flag)[2]) { + if (flag[1]) { + printf("%s %g%% (%d)", txt, flag[1] * 100.0 / (flag[0] + flag[1]), flag[0] + flag[1]); + } +} +void printArrayStatistics(const char *txt, const char* txt2, unsigned data[], unsigned size, unsigned sum, int offset) { + bool on = false; + for (unsigned i = 0; i < size; ++i) { + if (data[i]) { + on = true; + if (i + 1 == size && txt2) { + printf("%s %g%%", txt2, data[i] * 100.0 / sum); + } else { + printf("%s%d %g%%", txt, i + offset, data[i] * 100.0 / sum); + } + } + } + if (on) { + printf(" (%d)", sum); + } +} + +void PreflateStatisticalModel::print() { + printFlagStatistics(", EOB MP", EOBMisprediction); + printFlagStatistics(", !LIT MP", LITMisprediction); + printFlagStatistics(", !REF MP", REFMisprediction); + printFlagStatistics(", !LEN MP", LENMisprediction); + printFlagStatistics(", !DIST MP", DISTOnlyMisprediction); + unsigned sum; + if (LENMisprediction) { + sum = sumArray(LENPositiveCorrection) + + sumArray(LENNegativeCorrection); + printArrayStatistics(" L+", " L+?", LENPositiveCorrection, 6, sum, 1); + printArrayStatistics(" L-", " L-?", LENNegativeCorrection, 6, sum, 1); + } + sum = sumArray(DISTAfterLenCorrection); + if (sum) { + printArrayStatistics(" L->D+", " L->D+?", DISTAfterLenCorrection, 4, sum, 0); + } + sum = sumArray(DISTOnlyCorrection); + if (sum) { + printArrayStatistics(" ->D+", " L->D+?", DISTOnlyCorrection, 4, sum, 0); + } + + printFlagStatistics(", !CT SZ MP", TCCountMisprediction); + printFlagStatistics(", !L SZ MP", LCountMisprediction); + printFlagStatistics(", !D SZ MP", DCountMisprediction); + printFlagStatistics(", !T B MP", LDTypeMisprediction[0]); + printFlagStatistics(", !T R MP", LDTypeMisprediction[1]); + printFlagStatistics(", !T 0s MP", LDTypeMisprediction[2]); + printFlagStatistics(", !T 0l MP", LDTypeMisprediction[3]); + sum = sumArray(LDTypeReplacement); + if (LDTypeReplacement[0]) { + printf(" ->T B %g", LDTypeReplacement[0] * 100.0 / sum); + } + if (LDTypeReplacement[1]) { + printf(" ->T R %g", LDTypeReplacement[1] * 100.0 / sum); + } + if (LDTypeReplacement[2]) { + printf(" ->T 0s %g", LDTypeReplacement[2] * 100.0 / sum); + } + if (LDTypeReplacement[3]) { + printf(" ->T 0l %g", LDTypeReplacement[3] * 100.0 / sum); + } + sum = sumArray(TCBitlengthPositiveCorrection) + sumArray(TCBitlengthNegativeCorrection); + printArrayStatistics(", C BL+", ", C BL+?", TCBitlengthPositiveCorrection, 4, sum, 0); + printArrayStatistics(", C BL-", ", C BL-?", TCBitlengthNegativeCorrection, 3, sum, 1); + printFlagStatistics(" LD R MP", LDRepeatCountMisprediction); + sum = sumArray(LDBitlengthPositiveCorrection) + sumArray(LDBitlengthNegativeCorrection); + printArrayStatistics(", LD BL+", ", LD BL+?", LDBitlengthPositiveCorrection, 5, sum, 0); + printArrayStatistics(", LD BL-", ", LD BL-?", LDBitlengthNegativeCorrection, 4, sum, 1); + printf("\n"); +} \ No newline at end of file diff --git a/contrib/preflate/preflate_statistical_model.h b/contrib/preflate/preflate_statistical_model.h new file mode 100644 index 0000000..5d5b873 --- /dev/null +++ b/contrib/preflate/preflate_statistical_model.h @@ -0,0 +1,52 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_STATISTICAL_MODEL_H +#define PREFLATE_STATISTICAL_MODEL_H + +//#include "packARI/source/bitops.h" +//#include "packARI/source/aricoder.h" + +struct PreflateStatisticalModel { + // Blocks + unsigned blockType[3]; // stored, dynamic huff, static huff + unsigned EOBMisprediction[2]; // no, yes + // Tokens + unsigned LITMisprediction[2]; // no, yes + unsigned REFMisprediction[2]; // no, yes + unsigned LENMisprediction[2]; // no, yes + unsigned LENPositiveCorrection[6]; // +1, +2, +3, +4, +5, +x (bytes) + unsigned LENNegativeCorrection[6]; // -1, -2, -3, -4, -5, -x (bytes) + unsigned DISTAfterLenCorrection[4]; // +0, +1, +2, +x (hops) + unsigned DISTOnlyMisprediction[2]; // no, yes + unsigned DISTOnlyCorrection[4]; // +0, +1, +2, +x (hops) + // Trees + unsigned TCCountMisprediction[2]; // no, yes + unsigned TCBitlengthPositiveCorrection[4]; // 0, +1, +2, +x + unsigned TCBitlengthNegativeCorrection[3]; // -1, -2, -x + unsigned LCountMisprediction[2]; // no, yes + unsigned DCountMisprediction[2]; // no, yes + unsigned LDTypeMisprediction[4][2]; // types: BL,REP,REPZS,REPZL; no, yes + unsigned LDTypeReplacement[4]; // types: BL,REP,REPZS,REPZL; replacement type + unsigned LDRepeatCountMisprediction[2]; // no, yes + unsigned LDBitlengthPositiveCorrection[5]; // 0, +1, +2, +3, +x + unsigned LDBitlengthNegativeCorrection[4]; // -1, -2, -3, -x, + + void print(); +}; + +// iostream data; +// aricoder ; + +#endif /* PREFLATE_STATISTICAL_MODEL_H */ diff --git a/contrib/preflate/preflate_token.cpp b/contrib/preflate/preflate_token.cpp new file mode 100644 index 0000000..f4460df --- /dev/null +++ b/contrib/preflate/preflate_token.cpp @@ -0,0 +1,43 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include "preflate_token.h" + +bool isEqual(const PreflateTokenBlock& b1, const PreflateTokenBlock& b2) { + if (b1.type != b2.type) { + return false; + } +// if (b1.uncompressedLen != b2.uncompressedLen) { +// return false; +// } + if (b1.type != PreflateTokenBlock::STORED) { + if (b1.type == PreflateTokenBlock::DYNAMIC_HUFF) { + if (b1.ncode != b2.ncode || b1.nlen != b2.nlen || b1.ndist != b2.ndist) { + return false; + } + if (b1.treecodes != b2.treecodes) { + return false; + } + } + if (b1.tokens.size() != b2.tokens.size()) { + return false; + } + for (unsigned i = 0, n = b1.tokens.size(); i < n; ++i) { + if (b1.tokens[i].len != b2.tokens[i].len || b1.tokens[i].dist != b2.tokens[i].dist) { + return false; + } + } + } + return true; +} diff --git a/contrib/preflate/preflate_token.h b/contrib/preflate/preflate_token.h new file mode 100644 index 0000000..d7632be --- /dev/null +++ b/contrib/preflate/preflate_token.h @@ -0,0 +1,84 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_TOKEN_H +#define PREFLATE_TOKEN_H + +#include +#include + +/* len: 1 for literal, >= 3 for reference */ +struct PreflateToken { + enum typeLit { + LITERAL + }; + enum typeRef { + REFERENCE + }; + enum typeNon { + NONE + }; + unsigned short len; + unsigned short dist; + + PreflateToken(typeNon n) : len(0), dist(0) {} + PreflateToken(typeLit l) : len(1), dist(0) {} + PreflateToken(typeRef r, unsigned short l, unsigned short d) : len(l), dist(d) {} +}; + +struct PreflateTokenBlock { + enum Type { + STORED, DYNAMIC_HUFF, STATIC_HUFF + }; + enum StoredBlockType { + STORED_X + }; + enum HuffBlockType { + DYNAMIC_HUFF_X, STATIC_HUFF_X + }; + + Type type; + uint64_t uncompressedStartPos; + uint64_t uncompressedLen; + int32_t contextLen; // prefix size required to handle all references + unsigned short nlen, ndist, ncode; + std::vector treecodes; + std::vector tokens; + + PreflateTokenBlock() + : type(STORED) + , uncompressedLen(0) {} + PreflateTokenBlock(StoredBlockType, int len_) + : type(STORED) + , uncompressedLen(len_) {} + PreflateTokenBlock(HuffBlockType t) + : type(t == DYNAMIC_HUFF_X ? DYNAMIC_HUFF : STATIC_HUFF) + , uncompressedLen(0) {} + void setHuffLengths(int nlen_, int ndist_, int ncode_) { + nlen = nlen_; + ndist = ndist_; + ncode = ncode_; + } + void addTreeCode(int code) { + treecodes.push_back(code); + } + void addToken(const PreflateToken& token) { + tokens.push_back(token); + } +}; + +bool isEqual(const PreflateTokenBlock&, const PreflateTokenBlock&); + + +#endif /* PREFLATE_TOKEN_H */ diff --git a/contrib/preflate/preflate_token_predictor.cpp b/contrib/preflate/preflate_token_predictor.cpp new file mode 100644 index 0000000..b4cf186 --- /dev/null +++ b/contrib/preflate/preflate_token_predictor.cpp @@ -0,0 +1,447 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "preflate_constants.h" +#include "preflate_statistical_model.h" +#include "preflate_token_predictor.h" +#include "support/bit_helper.h" + +PreflateTokenPredictor::PreflateTokenPredictor( + const PreflateParameters& params_, + const std::vector& dump) + : state(hash, params_.config(), params_.windowBits, params_.memLevel) + , hash(dump, params_.memLevel) + , params(params_) + , predictionFailure(false) + , fast(params_.isFastCompressor()) + , prevLen(0) + , pendingToken(PreflateToken::NONE) + , emptyBlockAtEnd(false) { + + if (state.availableInputSize() >= 2) { + hash.updateRunningHash(state.inputCursor()[0]); + hash.updateRunningHash(state.inputCursor()[1]); + } +} + +bool PreflateTokenPredictor::predictEOB() { + return state.availableInputSize() == 0 || currentTokenCount == state.maxTokenCount; +} +void PreflateTokenPredictor::commitToken(const PreflateToken& t) { + if (fast && t.len > state.lazyMatchLength()) { + hash.skipHash(t.len); + } else { + hash.updateHash(t.len); + } +} +# define TOO_FAR 4096 +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +PreflateToken PreflateTokenPredictor::predictToken() { + if (state.currentInputPos() == 0 || state.availableInputSize() < PreflateConstants::MIN_MATCH) { + return PreflateToken(PreflateToken::LITERAL); + } + unsigned hash = state.calculateHash(); + unsigned head = state.getCurrentHashHead(hash); + PreflateToken match(PreflateToken::NONE); + + if (pendingToken.len > 1) { + match = pendingToken; + } else { + match = state.match(head, prevLen, 0, + params.veryFarMatchesDetected, + params.matchesToStartDetected, + params.zlibCompatible ? 0 : (1 << params.log2OfMaxChainDepthM1)); + } + prevLen = 0; + pendingToken = PreflateToken(PreflateToken::NONE); + if (match.len < PreflateConstants::MIN_MATCH) { + return PreflateToken(PreflateToken::LITERAL); + } + if (fast) { + return match; + } + if (match.len == 3 && match.dist > TOO_FAR) { + return PreflateToken(PreflateToken::LITERAL); + } + + if (match.len < state.lazyMatchLength() && state.availableInputSize() >= (unsigned)match.len + 2) { + unsigned hashNext = state.calculateHashNext(); + unsigned headNext = state.getCurrentHashHead(hashNext); + PreflateToken matchNext = state.match(headNext, match.len, 1, + params.veryFarMatchesDetected, + params.matchesToStartDetected, + params.zlibCompatible ? 0 : (2 << params.log2OfMaxChainDepthM1)); + if (((hashNext ^ hash) & this->hash.hashMask) == 0) { + unsigned maxSize = std::min(state.availableInputSize() - 1, (unsigned)PreflateConstants::MAX_MATCH); + unsigned rle = 1; + const unsigned char *c = state.inputCursor(); + unsigned char b = c[0]; + while (rle < maxSize && c[1 + rle] == b) { + ++rle; + } + if (rle >= matchNext.len) { + matchNext.len = rle; + matchNext.dist = 1; + } + } + if (matchNext.len > match.len) { + prevLen = match.len; + pendingToken = matchNext; + if (!params.zlibCompatible) { + prevLen = 0; + pendingToken = PreflateToken(PreflateToken::NONE); + } + return PreflateToken(PreflateToken::LITERAL); + } + } + + return match; +} +bool PreflateTokenPredictor::repredictReference(PreflateToken& token) { + if (state.currentInputPos() == 0 || state.availableInputSize() < PreflateConstants::MIN_MATCH) { + return false; + } + unsigned hash = state.calculateHash(); + unsigned head = state.getCurrentHashHead(hash); + PreflateToken match = state.match(head, /*prevLen*/0, 0, + params.veryFarMatchesDetected, + params.matchesToStartDetected, + (2 << params.log2OfMaxChainDepthM1)); + prevLen = 0; + pendingToken = PreflateToken(PreflateToken::NONE); + if (match.len < PreflateConstants::MIN_MATCH) { + return false; + } + token = match; + return true; +} +PreflateRematchInfo PreflateTokenPredictor::repredictMatch(const PreflateToken& token) { + unsigned hash = state.calculateHash(); + unsigned head = state.getCurrentHashHead(hash); + PreflateRematchInfo i = state.rematchInfo(head, token); + return i; +} +unsigned PreflateTokenPredictor::recalculateDistance(const PreflateToken& token, const unsigned hops) { + return state.hopMatch(token, hops); +} + +void PreflateTokenPredictor::analyzeBlock( + const unsigned blockno, + const PreflateTokenBlock& block) { + currentTokenCount = 0; + prevLen = 0; + pendingToken = PreflateToken(PreflateToken::NONE); + if (blockno != analysisResults.size() || predictionFailure) { + return; + } + analysisResults.push_back(BlockAnalysisResult()); + BlockAnalysisResult& analysis = analysisResults[blockno]; + + analysis.type = block.type; + analysis.tokenCount = block.tokens.size(); + analysis.tokenInfo.resize(analysis.tokenCount); + analysis.blockSizePredicted = true; + analysis.inputEOF = false; + + if (analysis.type == PreflateTokenBlock::STORED) { + analysis.tokenCount = block.uncompressedLen; + hash.updateHash(block.uncompressedLen); + analysis.inputEOF = state.availableInputSize() == 0; + return; + } + + for (unsigned i = 0, n = block.tokens.size(); i < n; ++i) { + PreflateToken targetToken = block.tokens[i]; + if (targetToken.len > 258) { + predictionFailure = true; + return; + } + if (predictEOB()) { + analysis.blockSizePredicted = false; + } + PreflateToken predictedToken = predictToken(); + + if (targetToken.len == 1) { + if (predictedToken.len > 1) { + analysis.tokenInfo[currentTokenCount] = 2; // badly predicted LIT + } else { + analysis.tokenInfo[currentTokenCount] = 0; // perfectly predicted LIT + } + } else { + if (predictedToken.len == 1) { + analysis.tokenInfo[currentTokenCount] = 3; // badly predicted REF + if (!repredictReference(predictedToken)) { + predictionFailure = true; + return; + } + } else { + analysis.tokenInfo[currentTokenCount] = 1; // well predicted REF + } + PreflateRematchInfo rematch; + if (predictedToken.len != targetToken.len) { + analysis.tokenInfo[currentTokenCount] += 4; // bad LEN prediction, adds two corrective actions + analysis.correctives.push_back(predictedToken.len); + analysis.correctives.push_back(targetToken.len - predictedToken.len); + rematch = repredictMatch(targetToken); + + if (rematch.requestedMatchDepth >= 0xffff) { + predictionFailure = true; + return; + } + analysis.correctives.push_back(rematch.condensedHops - 1); + } else { + if (targetToken.dist != predictedToken.dist) { + analysis.tokenInfo[currentTokenCount] += 8; // bad DIST ONLY prediction, adds one corrective action + rematch = repredictMatch(targetToken); + + if (rematch.requestedMatchDepth >= 0xffff) { + predictionFailure = true; + return; + } + analysis.correctives.push_back(rematch.condensedHops - 1); + } + } + } + commitToken(targetToken); + ++currentTokenCount; + } + if (!predictEOB()) { + analysis.blockSizePredicted = false; + } + analysis.inputEOF = state.availableInputSize() == 0; +} + +void PreflateTokenPredictor::encodeBlock( + PreflateStatisticalEncoder* codec, + const unsigned blockno) { + BlockAnalysisResult& analysis = analysisResults[blockno]; + + codec->encode(CORR_BLOCK_TYPE, analysis.type); + + if (analysis.type == PreflateTokenBlock::STORED) { + codec->encodeValue(analysis.tokenCount, 16); + return; + } + + codec->encode(CORR_EOB_MISPREDICTION, !analysis.blockSizePredicted); + if (!analysis.blockSizePredicted) { + unsigned blocksizeBits = bitLength(analysis.tokenCount); + codec->encodeValue(blocksizeBits, 5); + if (blocksizeBits >= 2) { + codec->encodeValue(analysis.tokenCount, blocksizeBits); + } + } + + unsigned correctivePos = 0; + for (unsigned i = 0, n = analysis.tokenCount; i < n; ++i) { + unsigned char info = analysis.tokenInfo[i]; + switch (info & 3) { + case 0: // well predicted LIT + codec->encode(CORR_LIT_MISPREDICTION, 0); + continue; + case 2: // badly predicted LIT + codec->encode(CORR_REF_MISPREDICTION, 1); + continue; + case 1: // well predicted REF + codec->encode(CORR_REF_MISPREDICTION, 0); + break; + case 3: // badly predicted REF + codec->encode(CORR_LIT_MISPREDICTION, 1); + break; + } + codec->encode(CORR_LEN_MISPREDICTION, (info & 4) != 0); + if (info & 4) { + int pred = analysis.correctives[correctivePos++]; + int diff = analysis.correctives[correctivePos++]; + int hops = analysis.correctives[correctivePos++]; + codec->encode(CORR_LEN_CORRECTION, diff, pred); + codec->encode(CORR_DIST_AFTER_LEN_CORRECTION, hops); + } else { + codec->encode(CORR_DIST_ONLY_MISPREDICTION, (info & 8) != 0); + if (info & 8) { + int hops = analysis.correctives[correctivePos++]; + codec->encode(CORR_DIST_ONLY_CORRECTION, hops); + } + } + } +} +void PreflateTokenPredictor::encodeEOF( + PreflateStatisticalEncoder* codec, + const unsigned blockno, + const bool lastBlock) { + BlockAnalysisResult& analysis = analysisResults[blockno]; + + if (analysis.inputEOF) { + codec->encodeValue(!lastBlock, 1); + } else { + // If we still have input left, this shouldn't be the last block + if (lastBlock) { + predictionFailure = true; + } + } +} + +void PreflateTokenPredictor::updateModel( + PreflateStatisticalModel* model, + const unsigned blockno) { + BlockAnalysisResult& analysis = analysisResults[blockno]; + + model->blockType[analysis.type]++; + + if (analysis.type == PreflateTokenBlock::STORED) { + return; + } + + model->EOBMisprediction[!analysis.blockSizePredicted]++; + + unsigned correctivePos = 0; + for (unsigned i = 0, n = analysis.tokenCount; i < n; ++i) { + unsigned char info = analysis.tokenInfo[i]; + switch (info & 3) { + case 0: // well predicted LIT + model->LITMisprediction[0]++; + continue; + case 2: // badly predicted LIT + model->REFMisprediction[1]++; + continue; + case 1: // well predicted REF + model->REFMisprediction[0]++; + break; + case 3: // badly predicted REF + model->LITMisprediction[1]++; + break; + } + model->LENMisprediction[(info & 4) != 0]++; + if (info & 4) { + /*int pred = analysis.correctives[*/correctivePos++/*]*/; + int diff = analysis.correctives[correctivePos++]; + int hops = analysis.correctives[correctivePos++]; + if (diff > 0) { + model->LENPositiveCorrection[std::min(5, diff - 1)]++; + } else { + model->LENNegativeCorrection[std::min(5, -diff - 1)]++; + } + model->DISTAfterLenCorrection[std::min(3, hops)]++; + } else { + model->DISTOnlyMisprediction[(info & 8) != 0]++; + if (info & 8) { + int hops = analysis.correctives[correctivePos++]; + model->DISTOnlyCorrection[std::min(3, hops)]++; + } + } + } +} + +PreflateTokenBlock PreflateTokenPredictor::decodeBlock( + PreflateStatisticalDecoder* codec) { + PreflateTokenBlock block; + currentTokenCount = 0; + prevLen = 0; + pendingToken = PreflateToken(PreflateToken::NONE); + unsigned blocksize = 0; + bool checkEOB = true; + unsigned bt = codec->decode(CORR_BLOCK_TYPE); + switch (bt) { + case PreflateTokenBlock::STORED: + block.type = PreflateTokenBlock::STORED; + block.uncompressedLen = codec->decodeValue(16); + hash.updateHash(block.uncompressedLen); + return block; + case PreflateTokenBlock::STATIC_HUFF: + block.type = PreflateTokenBlock::STATIC_HUFF; + break; + case PreflateTokenBlock::DYNAMIC_HUFF: + block.type = PreflateTokenBlock::DYNAMIC_HUFF; + break; + } + + if (codec->decode(CORR_EOB_MISPREDICTION)) { + unsigned blocksizeBits = codec->decodeValue(5); + if (blocksizeBits >= 2) { + blocksize = codec->decodeValue(blocksizeBits); + } else { + blocksize = blocksizeBits; + } + block.tokens.reserve(blocksize); + checkEOB = false; + } else { + block.tokens.reserve(1 << (6 + params.memLevel)); + } + while ((checkEOB && !predictEOB()) + || (!checkEOB && currentTokenCount < blocksize)) { + PreflateToken predictedToken = predictToken(); + if (predictedToken.len == 1) { + unsigned notok = codec->decode(CORR_LIT_MISPREDICTION); + if (!notok) { + block.tokens.push_back(predictedToken); + commitToken(predictedToken); + ++currentTokenCount; + continue; + } + if (!repredictReference(predictedToken)) { + predictionFailure = true; + return PreflateTokenBlock(); + } + } else { + unsigned notok = codec->decode(CORR_REF_MISPREDICTION); + if (notok) { + predictedToken.len = 1; + predictedToken.dist = 0; + block.tokens.push_back(predictedToken); + commitToken(predictedToken); + ++currentTokenCount; + continue; + } + } + bool lennotok = codec->decode(CORR_LEN_MISPREDICTION); + if (lennotok) { + int lendiff = codec->decode(CORR_LEN_CORRECTION, predictedToken.len); + int hops = codec->decode(CORR_DIST_AFTER_LEN_CORRECTION); + predictedToken.len += lendiff; + predictedToken.dist = state.firstMatch(predictedToken.len); + if (hops) { + predictedToken.dist = recalculateDistance(predictedToken, hops); + } + if (predictedToken.len < 3 || predictedToken.len > 258 + || predictedToken.dist == 0) { + predictionFailure = true; + return PreflateTokenBlock(); + } + } else { + bool distnotok = codec->decode(CORR_DIST_ONLY_MISPREDICTION); + if (distnotok) { + int hops = codec->decode(CORR_DIST_ONLY_CORRECTION); + if (hops) { + predictedToken.dist = recalculateDistance(predictedToken, hops); + } + if (predictedToken.dist == 0) { + predictionFailure = true; + return PreflateTokenBlock(); + } + } + } + block.tokens.push_back(predictedToken); + commitToken(predictedToken); + ++currentTokenCount; + } + return block; +} +bool PreflateTokenPredictor::decodeEOF(PreflateStatisticalDecoder* codec) { + if (state.availableInputSize() == 0) { + return codec->decodeValue(1) == 0; + } + return false; +} diff --git a/contrib/preflate/preflate_token_predictor.h b/contrib/preflate/preflate_token_predictor.h new file mode 100644 index 0000000..b647fc6 --- /dev/null +++ b/contrib/preflate/preflate_token_predictor.h @@ -0,0 +1,72 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_TOKEN_PREDICTOR_H +#define PREFLATE_TOKEN_PREDICTOR_H + +#include + +#include "preflate_parameter_estimator.h" +#include "preflate_predictor_state.h" +#include "preflate_statistical_codec.h" + +struct PreflateStatisticalModel; +struct PreflateStatisticalCodec; + +struct PreflateTokenPredictor { + PreflatePredictorState state; + PreflateHashChainExt hash; + PreflateParameters params; + bool predictionFailure; + bool fast; + unsigned prevLen; + PreflateToken pendingToken; + unsigned currentTokenCount; + bool emptyBlockAtEnd; + + struct BlockAnalysisResult { + PreflateTokenBlock::Type type; + unsigned tokenCount; + bool blockSizePredicted; + bool inputEOF; + bool lastBlock; + std::vector tokenInfo; + std::vector correctives; + }; + std::vector analysisResults; + + PreflateTokenPredictor(const PreflateParameters& params, + const std::vector& dump); + void analyzeBlock(const unsigned blockno, + const PreflateTokenBlock& block); + void updateModel(PreflateStatisticalModel*, + const unsigned blockno); + void encodeBlock(PreflateStatisticalEncoder*, + const unsigned blockno); + void encodeEOF(PreflateStatisticalEncoder*, + const unsigned blockno, + const bool lastBlock); + + PreflateTokenBlock decodeBlock(PreflateStatisticalDecoder*); + bool decodeEOF(PreflateStatisticalDecoder*); + + bool predictEOB(); + PreflateToken predictToken(); + bool repredictReference(PreflateToken& token); + PreflateRematchInfo repredictMatch(const PreflateToken&); + unsigned recalculateDistance(const PreflateToken&, const unsigned hops); + void commitToken(const PreflateToken&); +}; + +#endif /* PREFLATE_TOKEN_PREDICTOR_H */ diff --git a/contrib/preflate/preflate_tree_predictor.cpp b/contrib/preflate/preflate_tree_predictor.cpp new file mode 100644 index 0000000..f7dee3f --- /dev/null +++ b/contrib/preflate/preflate_tree_predictor.cpp @@ -0,0 +1,675 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "preflate_constants.h" +#include "preflate_statistical_codec.h" +#include "preflate_statistical_model.h" +#include "preflate_tree_predictor.h" + +PreflateTreePredictor::PreflateTreePredictor( + const std::vector& dump) + : input(dump) + , curPos(0) + , predictionFailure(false) { +} + +struct FreqIdxPair { + unsigned freq; + unsigned idx; +}; +struct TreeNode { + unsigned parent; + unsigned idx; +}; + +/* =========================================================================== +* Compares to subtrees, using the tree depth as tie breaker when +* the subtrees have equal frequency. This minimizes the worst case length. +*/ +bool pq_smaller(const FreqIdxPair& p1, const FreqIdxPair& p2, const unsigned char* nodeDepth) { + return p1.freq < p2.freq || (p1.freq == p2.freq && nodeDepth[p1.idx] <= nodeDepth[p2.idx]); +} + +/* =========================================================================== +* Restore the heap property by moving down the tree starting at node k, +* exchanging a node with the smallest of its two sons if necessary, stopping +* when the heap property is re-established (each father smaller than its +* two sons). +*/ +void pq_downheap(FreqIdxPair* ptr, const unsigned index, const unsigned len, const unsigned char* depth) { + unsigned k = index; + FreqIdxPair v = ptr[k]; + unsigned j = k * 2 + 1; /* left son of k */ + while (j < len) { + /* Set j to the smallest of the two sons: */ + if (j + 1 < len && pq_smaller(ptr[j + 1], ptr[j], depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (pq_smaller(v, ptr[j], depth)) break; + + /* Exchange v with the smallest son */ + ptr[k] = ptr[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j = k * 2 + 1; + } + ptr[k] = v; +} + +void pq_makeheap(FreqIdxPair* ptr, const unsigned len, const unsigned char* depth) { + for (unsigned n = (len - 1) / 2 + 1; n > 0; n--) { + pq_downheap(ptr, n - 1, len, depth); + } +} + +FreqIdxPair pq_remove(FreqIdxPair* ptr, unsigned& len, const unsigned char* depth) { + FreqIdxPair result = ptr[0]; + ptr[0] = ptr[--len]; + pq_downheap(ptr, 0, len, depth); + return result; +} + +unsigned PreflateTreePredictor::calcBitLengths( + unsigned char* symBitLen, + const unsigned* symFreq, + const unsigned symCount, + const unsigned maxBits, + const unsigned minMaxCode) { + FreqIdxPair toSort[PreflateConstants::L_CODES]; + TreeNode nodes[PreflateConstants::L_CODES * 2 + 1]; + unsigned char nodeBitLen[PreflateConstants::L_CODES * 2 + 1]; + unsigned char nodeDepth[PreflateConstants::L_CODES * 2 + 1]; + memset(nodeBitLen, 0, sizeof(nodeBitLen)); + memset(nodeDepth, 0, sizeof(nodeDepth)); + unsigned maxCode = 0, len = 0, nodeCount = 0, nodeId = symCount; + for (unsigned i = 0; i < symCount; ++i) { + if (symFreq[i]) { + toSort[len++] = FreqIdxPair {symFreq[i], maxCode = i}; + } + } + if (len < 2) { + memset(symBitLen, 0, symCount); + symBitLen[maxCode] = 1; + symBitLen[maxCode < 2 ? ++maxCode : 0] = 1; + return std::max(minMaxCode, maxCode + 1); + } + + pq_makeheap(toSort, len, nodeDepth); + while (len > 1) { + FreqIdxPair least1 = pq_remove(toSort, len, nodeDepth); + FreqIdxPair least2 = toSort[0]; + toSort[0] = FreqIdxPair {least1.freq + least2.freq, nodeId}; + nodes[nodeCount++] = TreeNode {nodeId, least1.idx}; + nodes[nodeCount++] = TreeNode {nodeId, least2.idx}; + nodeDepth[nodeId] = std::max(nodeDepth[least1.idx], nodeDepth[least2.idx]) + 1; + // note? original code put new entry at top of heap, and moved it downwards + // while push_heap pushes it upwards + pq_downheap(toSort, 0, len, nodeDepth); + nodeId++; + } + unsigned overflow = 0; + unsigned bl_count[16]; + memset(bl_count, 0, sizeof(bl_count)); + unsigned orgNodeCount = nodeCount; + while (nodeCount-- > 0) { + unsigned char newLen = nodeBitLen[nodes[nodeCount].parent] + 1; + if (newLen > maxBits) { + newLen = maxBits; + ++overflow; + } + unsigned idx = nodes[nodeCount].idx; + nodeBitLen[idx] = newLen; + if (idx < symCount) { + bl_count[newLen]++; + } + } + + if (overflow) { + unsigned bits; + do { + for (bits = maxBits - 1; bl_count[bits] == 0; bits--) { + } + bl_count[bits]--; /* move one leaf down the tree */ + bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + bl_count[maxBits]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + for (bits = maxBits, nodeCount = orgNodeCount; nodeCount > 0; ) { + --nodeCount; + unsigned idx = nodes[nodeCount].idx; + if (idx >= symCount) { + continue; + } + while (bl_count[bits] == 0) { + bits--; + } + nodeBitLen[idx] = bits; + bl_count[bits]--; + } + } + memcpy(symBitLen, nodeBitLen, symCount); + return std::max(minMaxCode, maxCode + 1); +} + +TreeCodeType PreflateTreePredictor::predictCodeType(const unsigned char* symBitLen, + const unsigned symCount, + const bool first) { + unsigned char code = symBitLen[0]; + if (code == 0) { + unsigned char curlen = 1; + unsigned char maxCurLen = std::min(symCount, 11u); + while (curlen < maxCurLen && symBitLen[curlen] == 0) { + ++curlen; + } + if (curlen >= 11) { + return TCT_REPZL; + } + if (curlen >= 3) { + return TCT_REPZS; + } + return TCT_BITS; + } + if (!first && code == symBitLen[-1]) { + unsigned char curlen = 1; + unsigned char maxCurLen = std::min(symCount, 3u); + while (curlen < maxCurLen && symBitLen[curlen] == code) { + ++curlen; + } + if (curlen >= 3) { + return TCT_REP; + } + } + return TCT_BITS; +} +unsigned char PreflateTreePredictor::predictCodeData(const unsigned char* symBitLen, + const TreeCodeType type, + const unsigned symCount, + const bool first) { + unsigned char code = symBitLen[0]; + switch (type) { + default: + case TCT_BITS: + return code; + case TCT_REP: + { + unsigned char curlen = 3; + unsigned char maxCurLen = std::min(symCount, 6u); + while (curlen < maxCurLen && symBitLen[curlen] == code) { + ++curlen; + } + return curlen; + } + case TCT_REPZS: + case TCT_REPZL: + { + unsigned char curlen = type == TCT_REPZS ? 3 : 11; + unsigned char maxCurLen = std::min(symCount, type == TCT_REPZS ? 10u : 138u); + while (curlen < maxCurLen && symBitLen[curlen] == 0) { + ++curlen; + } + return curlen; + } + } +} + + +void PreflateTreePredictor::predictLDTrees( + BlockAnalysisResult& analysis, + unsigned* frequencies, + const unsigned char* symBitLen, + const unsigned symLCount, + const unsigned symDCount, + const unsigned char* targetCodes, + const unsigned targetCodeSize) { + memset(frequencies, 0, sizeof(unsigned) * PreflateConstants::BL_CODES); + const unsigned char* ptr = symBitLen; + const unsigned char* code = targetCodes; + unsigned codeSize = targetCodeSize; + unsigned count1 = symLCount; + unsigned count2 = symDCount; + bool first = true; + while (codeSize > 0) { + TreeCodeType targetTreeCodeType; + switch (code[0]) { + case 16: targetTreeCodeType = TCT_REP; break; + case 17: targetTreeCodeType = TCT_REPZS; break; + case 18: targetTreeCodeType = TCT_REPZL; break; + default: targetTreeCodeType = TCT_BITS; break; + } + if (codeSize < 2 && targetTreeCodeType != TCT_BITS) { + predictionFailure = true; + return; + } + TreeCodeType predictedTreeCodeType = predictCodeType(ptr, count1, first); + unsigned char info = predictedTreeCodeType | ((targetTreeCodeType != predictedTreeCodeType) << 2); + if (targetTreeCodeType != predictedTreeCodeType) { + analysis.correctives.push_back(targetTreeCodeType); + } + unsigned char targetTreeCodeData = code[targetTreeCodeType != TCT_BITS]; + unsigned l = 1 + (targetTreeCodeType != TCT_BITS); + code += l; + codeSize -= l; + unsigned char predictedTreeCodeData = predictCodeData(ptr, targetTreeCodeType, count1, first); + first = false; + if (targetTreeCodeType != TCT_BITS) { + if (targetTreeCodeData != predictedTreeCodeData) { + info |= 8; + analysis.correctives.push_back(targetTreeCodeData); + } + } else { + analysis.correctives.push_back(predictedTreeCodeData); + analysis.correctives.push_back(targetTreeCodeData - predictedTreeCodeData); + } + if (targetTreeCodeType != TCT_BITS) { + frequencies[targetTreeCodeType + 15]++; + l = targetTreeCodeData; + } else { + frequencies[targetTreeCodeData]++; + l = 1; + } + ptr += l; + if (count1 > l) { + count1 -= l; + } else { + count1 += count2; + count2 = 0; + first = true; + if (count1 >= l) { + count1 -= l; + } else { + predictionFailure = true; + return; + } + } + analysis.tokenInfo.push_back(info); + } + analysis.tokenInfo.push_back(0xff); + if (count1 + count2 != 0) { + predictionFailure = true; + } +} + +void PreflateTreePredictor::collectTokenStatistics( + unsigned Lcodes[], + unsigned Dcodes[], + unsigned& Lcount, + unsigned& Dcount, + const PreflateTokenBlock& block) { + memset(Lcodes, 0, sizeof(unsigned) * PreflateConstants::L_CODES); + memset(Dcodes, 0, sizeof(unsigned) * PreflateConstants::D_CODES); + Lcount = 0; + Dcount = 0; + for (unsigned i = 0, n = block.tokens.size(); i < n; ++i) { + PreflateToken targetToken = block.tokens[i]; + if (targetToken.len == 1) { + Lcodes[input.curChar()]++; + Lcount++; + input.advance(1); + } else { + Lcodes[PreflateConstants::LITERALS + 1 + PreflateConstants::LCode(targetToken.len)]++; + Lcount++; + Dcodes[PreflateConstants::DCode(targetToken.dist)]++; + Dcount++; + input.advance(targetToken.len); + } + } + Lcodes[256] = 1; +} +unsigned PreflateTreePredictor::buildLBitlenghs( + unsigned char bitLengths[], + unsigned Lcodes[]) { + return calcBitLengths(bitLengths, Lcodes, PreflateConstants::L_CODES, 15, PreflateConstants::LITERALS + 1); +} +unsigned PreflateTreePredictor::buildDBitlenghs( + unsigned char bitLengths[], + unsigned Dcodes[]) { + return calcBitLengths(bitLengths, Dcodes, PreflateConstants::D_CODES, 15, 0); +} +unsigned PreflateTreePredictor::buildTCBitlengths( + unsigned char (&simpleCodeTree)[PreflateConstants::BL_CODES], + unsigned (&BLfreqs)[PreflateConstants::BL_CODES]) { + memset(simpleCodeTree, 0, sizeof(simpleCodeTree)); + calcBitLengths(simpleCodeTree, BLfreqs, PreflateConstants::BL_CODES, 7, 0); + unsigned predictedCTreeSize = PreflateConstants::BL_CODES; + while (predictedCTreeSize > 4 + && simpleCodeTree[PreflateConstants::treeCodeOrderTable[predictedCTreeSize - 1]] == 0) { + --predictedCTreeSize; + } + return predictedCTreeSize; +} + +void PreflateTreePredictor::analyzeBlock( + const unsigned blockno, + const PreflateTokenBlock& block) { + if (blockno != analysisResults.size() || predictionFailure) { + return; + } + analysisResults.push_back(BlockAnalysisResult()); + BlockAnalysisResult& analysis = analysisResults[blockno]; + analysis.blockType = block.type; + if (analysis.blockType != PreflateTokenBlock::DYNAMIC_HUFF) { + return; + } + + unsigned Lcodes[PreflateConstants::L_CODES], Dcodes[PreflateConstants::D_CODES]; + unsigned Lcount = 0, Dcount = 0; + collectTokenStatistics(Lcodes, Dcodes, Lcount, Dcount, block); + + unsigned char bitLengths[PreflateConstants::LD_CODES]; + memset(bitLengths, 0, sizeof(bitLengths)); + unsigned predictedLTreeSize = buildLBitlenghs(bitLengths, Lcodes); + analysis.tokenInfo.push_back(predictedLTreeSize != block.nlen); + if (predictedLTreeSize != block.nlen) { + analysis.correctives.push_back(block.nlen); + } + predictedLTreeSize = block.nlen; + + unsigned predictedDTreeSize = buildDBitlenghs(bitLengths + predictedLTreeSize, Dcodes); + analysis.tokenInfo.push_back(predictedDTreeSize != block.ndist); + if (predictedDTreeSize != block.ndist) { + analysis.correctives.push_back(block.ndist); + } + predictedDTreeSize = block.ndist; + + unsigned BLfreqs[PreflateConstants::BL_CODES]; + const unsigned char* targetCodes = &block.treecodes[0]; + unsigned targetCodeSize = block.treecodes.size(); + predictLDTrees(analysis, BLfreqs, bitLengths, predictedLTreeSize, predictedDTreeSize, targetCodes + block.ncode, targetCodeSize - block.ncode); + + unsigned char simpleCodeTree[PreflateConstants::BL_CODES]; + unsigned predictedCTreeSize = buildTCBitlengths(simpleCodeTree, BLfreqs); + analysis.tokenInfo.push_back(block.ncode); + analysis.tokenInfo.push_back(predictedCTreeSize != block.ncode); + predictedCTreeSize = block.ncode; + for (unsigned i = 0; i < predictedCTreeSize; ++i) { + unsigned predictedBL = simpleCodeTree[PreflateConstants::treeCodeOrderTable[i]]; + analysis.correctives.push_back(predictedBL); + analysis.correctives.push_back(targetCodes[i] - predictedBL); + } +} +void PreflateTreePredictor::encodeBlock( + PreflateStatisticalEncoder* codec, + const unsigned blockno) { + BlockAnalysisResult& analysis = analysisResults[blockno]; + if (analysis.blockType != PreflateTokenBlock::DYNAMIC_HUFF) { + return; + } + + unsigned infoPos = 0, correctivePos = 0; + unsigned char info = analysis.tokenInfo[infoPos++]; + codec->encode(CORR_L_COUNT_MISPREDICTION, info); + if (info) { + codec->encodeValue(analysis.correctives[correctivePos++] - PreflateConstants::LITERALS - 1, 5); + } + info = analysis.tokenInfo[infoPos++]; + codec->encode(CORR_D_COUNT_MISPREDICTION, info); + if (info) { + codec->encodeValue(analysis.correctives[correctivePos++], 5); + } + + while ((info = analysis.tokenInfo[infoPos++]) != 0xff) { + unsigned type = (info & 3); + codec->encode(CORR_LD_TYPE_MISPREDICTION, (info & 4) != 0, type); + if (info & 4) { + unsigned newType = analysis.correctives[correctivePos++]; + codec->encode(CORR_LD_TYPE_REPLACEMENT, newType, type); + type = newType; + } + if (type != TCT_BITS) { + codec->encode(CORR_LD_REPEAT_MISPREDICTION, (info & 8) != 0); + if (info & 8) { + unsigned newRepeat = analysis.correctives[correctivePos++]; + switch (type) { + case TCT_REP: + codec->encodeValue(newRepeat - 3, 2); + break; + case TCT_REPZS: + codec->encodeValue(newRepeat - 3, 3); + break; + case TCT_REPZL: + codec->encodeValue(newRepeat - 11, 7); + break; + } + } + } else { + unsigned bl_pred = analysis.correctives[correctivePos++]; + int bl_diff = analysis.correctives[correctivePos++]; + codec->encode(CORR_LD_BITLENGTH_CORRECTION, bl_diff, bl_pred); + } + } + unsigned blcount = analysis.tokenInfo[infoPos++]; + info = analysis.tokenInfo[infoPos++]; + codec->encode(CORR_TC_COUNT_MISPREDICTION, info); + if (info) { + codec->encodeValue(blcount - 4, 4); + } + for (unsigned i = 0; i < blcount; ++i) { + int bl_pred = analysis.correctives[correctivePos++]; + int bl_diff = analysis.correctives[correctivePos++]; + codec->encode(CORR_TC_BITLENGTH_CORRECTION, bl_diff, bl_pred); + } +} + +void PreflateTreePredictor::updateModel( + PreflateStatisticalModel* model, + const unsigned blockno) { + BlockAnalysisResult& analysis = analysisResults[blockno]; + if (analysis.blockType != PreflateTokenBlock::DYNAMIC_HUFF) { + return; + } + + unsigned infoPos = 0, correctivePos = 0; + unsigned char info = analysis.tokenInfo[infoPos++]; + model->LCountMisprediction[info]++; + if (info) { + correctivePos++; + } + info = analysis.tokenInfo[infoPos++]; + model->DCountMisprediction[info]++; + if (info) { + correctivePos++; + } + + while ((info = analysis.tokenInfo[infoPos++]) != 0xff) { + unsigned type = (info & 3); + model->LDTypeMisprediction[type][(info & 4) != 0]++; + if (info & 4) { + unsigned newType = analysis.correctives[correctivePos++]; + model->LDTypeReplacement[newType]++; + type = newType; + } + if (type != TCT_BITS) { + model->LDRepeatCountMisprediction[(info & 8) != 0]++; + if (info & 8) { + correctivePos++; + } + } else { + /*unsigned bl_pred = analysis.correctives[*/correctivePos++/*]*/; + int bl_diff = analysis.correctives[correctivePos++]; + if (bl_diff >= 0) { + model->LDBitlengthPositiveCorrection[std::min(4, bl_diff)]++; + } else { + model->LDBitlengthNegativeCorrection[std::min(3, -bl_diff - 1)]++; + } + } + } + unsigned blcount = analysis.tokenInfo[infoPos++]; + info = analysis.tokenInfo[infoPos++]; + model->TCCountMisprediction[info]++; + for (unsigned i = 0; i < blcount; ++i) { + /*int bl_pred = analysis.correctives[*/correctivePos++/*]*/; + int bl_diff = analysis.correctives[correctivePos++]; + if (bl_diff >= 0) { + model->TCBitlengthPositiveCorrection[std::min(3, bl_diff)]++; + } else { + model->TCBitlengthNegativeCorrection[std::min(2, -bl_diff - 1)]++; + } + } +} + + +unsigned PreflateTreePredictor::reconstructLDTrees( + PreflateStatisticalDecoder* codec, + unsigned* frequencies, + unsigned char* targetCodes, + const unsigned targetCodeSize, + const unsigned char* symBitLen, + const unsigned symLCount, + const unsigned symDCount) { + memset(frequencies, 0, sizeof(unsigned) * PreflateConstants::BL_CODES); + const unsigned char* ptr = symBitLen; + unsigned osize = 0; + unsigned count1 = symLCount; + unsigned count2 = symDCount; + bool first = true; + while (count1 + count2 > 0) { + TreeCodeType predictedTreeCodeType = predictCodeType(ptr, count1, first); + if (codec->decode(CORR_LD_TYPE_MISPREDICTION, predictedTreeCodeType)) { + unsigned newType = codec->decode(CORR_LD_TYPE_REPLACEMENT, predictedTreeCodeType); + switch (newType) { + case TCT_BITS: + predictedTreeCodeType = TCT_BITS; + break; + case TCT_REP: + predictedTreeCodeType = TCT_REP; + break; + case TCT_REPZS: + predictedTreeCodeType = TCT_REPZS; + break; + case TCT_REPZL: + predictedTreeCodeType = TCT_REPZL; + break; + } + } + unsigned char predictedTreeCodeData = predictCodeData(ptr, predictedTreeCodeType, count1, first); + first = false; + if (predictedTreeCodeType != TCT_BITS) { + if (codec->decode(CORR_LD_REPEAT_MISPREDICTION)) { + switch (predictedTreeCodeType) { + case TCT_REP: + predictedTreeCodeData = codec->decodeValue(2) + 3; + break; + case TCT_REPZS: + predictedTreeCodeData = codec->decodeValue(3) + 3; + break; + case TCT_REPZL: + predictedTreeCodeData = codec->decodeValue(7) + 11; + break; + case TCT_BITS: + // unreachable + break; + } + } + } else { + int bl_diff = codec->decode(CORR_LD_BITLENGTH_CORRECTION, predictedTreeCodeData); + predictedTreeCodeData += bl_diff; + } + unsigned l; + if (predictedTreeCodeType != TCT_BITS) { + frequencies[predictedTreeCodeType + 15]++; + l = predictedTreeCodeData; + if (osize + 2 > targetCodeSize) { + predictionFailure = true; + break; + } + targetCodes[osize++] = predictedTreeCodeType + 15; + targetCodes[osize++] = predictedTreeCodeData; + } else { + frequencies[predictedTreeCodeData]++; + l = 1; + if (osize >= targetCodeSize) { + predictionFailure = true; + break; + } + targetCodes[osize++] = predictedTreeCodeData; + } + ptr += l; + if (count1 > l) { + count1 -= l; + } else { + count1 += count2; + count2 = 0; + first = true; + if (count1 >= l) { + count1 -= l; + } else { + predictionFailure = true; + break; + } + } + } + if (count1 + count2 != 0) { + predictionFailure = true; + } + return predictionFailure ? 0 : osize; +} + +bool PreflateTreePredictor::decodeBlock( + PreflateTokenBlock& block, + PreflateStatisticalDecoder* codec) { + if (block.type != PreflateTokenBlock::DYNAMIC_HUFF) { + return true; + } + + unsigned Lcodes[PreflateConstants::L_CODES], Dcodes[PreflateConstants::D_CODES]; + unsigned Lcount = 0, Dcount = 0; + collectTokenStatistics(Lcodes, Dcodes, Lcount, Dcount, block); + + unsigned char bitLengths[PreflateConstants::LD_CODES]; + memset(bitLengths, 0, sizeof(bitLengths)); + unsigned predictedLTreeSize = buildLBitlenghs(bitLengths, Lcodes); + if (codec->decode(CORR_L_COUNT_MISPREDICTION)) { + predictedLTreeSize = codec->decodeValue(5) + PreflateConstants::LITERALS + 1; + } + block.nlen = predictedLTreeSize; + + unsigned predictedDTreeSize = buildDBitlenghs(bitLengths + predictedLTreeSize, Dcodes); + if (codec->decode(CORR_D_COUNT_MISPREDICTION)) { + predictedDTreeSize = codec->decodeValue(5); + } + block.ndist = predictedDTreeSize; + + unsigned BLfreqs[PreflateConstants::BL_CODES]; + unsigned char compressedLDtrees[PreflateConstants::LD_CODES]; + unsigned targetCodeSize = reconstructLDTrees(codec, BLfreqs, compressedLDtrees, PreflateConstants::LD_CODES, + bitLengths, predictedLTreeSize, predictedDTreeSize); + if (predictionFailure) { + return false; + } + + unsigned char simpleCodeTree[PreflateConstants::BL_CODES]; + unsigned predictedCTreeSize = buildTCBitlengths(simpleCodeTree, BLfreqs); + if (codec->decode(CORR_TC_COUNT_MISPREDICTION)) { + predictedCTreeSize = codec->decodeValue(4) + 4; + } + block.ncode = predictedCTreeSize; + unsigned char shuffledCodeTree[PreflateConstants::BL_CODES]; + for (unsigned i = 0; i < predictedCTreeSize; ++i) { + unsigned predictedBL = simpleCodeTree[PreflateConstants::treeCodeOrderTable[i]]; + int bl_diff = codec->decode(CORR_TC_BITLENGTH_CORRECTION, predictedBL); + shuffledCodeTree[i] = predictedBL + bl_diff; + } + block.treecodes.reserve(predictedCTreeSize + targetCodeSize); + block.treecodes.insert(block.treecodes.end(), shuffledCodeTree, shuffledCodeTree + predictedCTreeSize); + block.treecodes.insert(block.treecodes.end(), compressedLDtrees, compressedLDtrees + targetCodeSize); + return true; +} diff --git a/contrib/preflate/preflate_tree_predictor.h b/contrib/preflate/preflate_tree_predictor.h new file mode 100644 index 0000000..0343801 --- /dev/null +++ b/contrib/preflate/preflate_tree_predictor.h @@ -0,0 +1,99 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_TREE_PREDICTOR_H +#define PREFLATE_TREE_PREDICTOR_H + +#include + +#include "preflate_constants.h" +#include "preflate_input.h" +#include "preflate_parameter_estimator.h" + +struct PreflateStatisticalModel; +struct PreflateStatisticalCodec; + +enum TreeCodeType { + TCT_BITS = 0, TCT_REP = 1, TCT_REPZS = 2, TCT_REPZL = 3 +}; + +struct PreflateTreePredictor { + PreflateInput input; + unsigned curPos; + bool predictionFailure; + + struct BlockAnalysisResult { + PreflateTokenBlock::Type blockType; + std::vector tokenInfo; + std::vector correctives; + }; + std::vector analysisResults; + + void collectTokenStatistics( + unsigned LcodeFrequencies[], + unsigned DcodeFrequencies[], + unsigned& Lcount, + unsigned& Dcount, + const PreflateTokenBlock& block); + unsigned buildLBitlenghs( + unsigned char bitLengths[], + unsigned Lcodes[]); + unsigned buildDBitlenghs( + unsigned char bitLengths[], + unsigned Dcodes[]); + unsigned buildTCBitlengths( + unsigned char (&bitLengths)[PreflateConstants::BL_CODES], + unsigned (&BLfreqs)[PreflateConstants::BL_CODES]); + + + unsigned calcBitLengths(unsigned char* symBitLen, + const unsigned* symFreq, + const unsigned symCount, + const unsigned maxBits, + const unsigned minMaxCode); + + TreeCodeType predictCodeType(const unsigned char* symBitLen, + const unsigned symCount, + const bool first); + unsigned char predictCodeData(const unsigned char* symBitLen, + const TreeCodeType type, + const unsigned symCount, + const bool first); + void predictLDTrees(BlockAnalysisResult& analysis, + unsigned* frequencies, + const unsigned char* symBitLen, + const unsigned symLCount, + const unsigned symDCount, + const unsigned char* targetCodes, + const unsigned targetCodeSize); + unsigned reconstructLDTrees(PreflateStatisticalDecoder* codec, + unsigned* frequencies, + unsigned char* targetCodes, + unsigned targetCodeSize, + const unsigned char* symBitLen, + const unsigned symLCount, + const unsigned symDCount); + + PreflateTreePredictor(const std::vector& dump); + void analyzeBlock(const unsigned blockno, + const PreflateTokenBlock& block); + void updateModel(PreflateStatisticalModel*, + const unsigned blockno); + void encodeBlock(PreflateStatisticalEncoder*, + const unsigned blockno); + + bool decodeBlock(PreflateTokenBlock& block, PreflateStatisticalDecoder*); +}; + +#endif /* PREFLATE_TREE_PREDICTOR_H */ diff --git a/contrib/preflate/preflate_unpack.cpp b/contrib/preflate/preflate_unpack.cpp new file mode 100644 index 0000000..af889a9 --- /dev/null +++ b/contrib/preflate/preflate_unpack.cpp @@ -0,0 +1,69 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "preflate_dumper.h" +#include "preflate_unpack.h" +#include "zlib1.2.11.dec/zlib.h" + +void* zalloc(void*, uInt items, uInt size) { + return malloc(items * size); +} +void zfree(void*, void* addr) { + free(addr); +} + +bool preflate_unpack(std::vector& unpacked_output, + std::vector& blocks, + const std::vector& deflate_raw) { + z_stream inf; /* zlib deflate and inflate states */ + inf.zalloc = zalloc; + inf.zfree = zfree; + inf.opaque = Z_NULL; + inf.avail_in = deflate_raw.size(); + inf.next_in = const_cast(deflate_raw.data()); + + PreflateDumper dumper; + inf.dumper = &dumper; + int ret = inflateInit2(&inf, -15); + if (ret != Z_OK) { + return false; + } + std::vector tmp(64 * 1024); + inf.avail_out = tmp.size(); + inf.next_out = tmp.data(); + bool failure = false; + + do { + /* decompress */ + inf.avail_out = tmp.size(); + inf.next_out = tmp.data(); + ret = inflate(&inf, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_DATA_ERROR || ret == Z_NEED_DICT || ret == Z_MEM_ERROR + || ret == Z_BUF_ERROR) { + return false; + } + dumper.uncompressed.insert(dumper.uncompressed.end(), tmp.begin(), tmp.end() - inf.avail_out); + } while (ret != Z_STREAM_END); + + inflateEnd(&inf); + + if (failure || dumper.hadErrors()) { + return false; + } + + unpacked_output = std::move(dumper.uncompressed); + blocks = std::move(dumper.blocks); + return true; +} diff --git a/contrib/preflate/preflate_unpack.h b/contrib/preflate/preflate_unpack.h new file mode 100644 index 0000000..76d19f2 --- /dev/null +++ b/contrib/preflate/preflate_unpack.h @@ -0,0 +1,25 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef PREFLATE_UNPACK_H +#define PREFLATE_UNPACK_H + +#include +#include "preflate_token.h" + +bool preflate_unpack(std::vector& unpacked_output, + std::vector& blocks, + const std::vector& deflate_raw); + +#endif /* PREFLATE_UNPACK_H */ diff --git a/contrib/preflate/support/arithmetic_coder.cpp b/contrib/preflate/support/arithmetic_coder.cpp new file mode 100644 index 0000000..5e54afc --- /dev/null +++ b/contrib/preflate/support/arithmetic_coder.cpp @@ -0,0 +1,212 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "arithmetic_coder.h" +#include "array_helper.h" +#include "bit_helper.h" + +ArithmeticEncoder::ArithmeticEncoder(BitOutputStream& bos) + : _bos(bos) + , _low(0) + , _high(0x7fffffff) + , _e3cnt(0) {} + +void ArithmeticEncoder::_writeE3(const unsigned w) { + while (_e3cnt > 0) { + uint32_t todo = std::min(_e3cnt, 16u); + _bos.put(w, todo); + _e3cnt -= todo; + } +} + +void ArithmeticEncoder::flush() { + if (_low < 0x20000000) { // case a.) + _bos.put(2, 2); // write 0, 1, E3 + _writeE3(~0u); + } else { + _bos.put(1, 1); + } +} + +void ArithmeticEncoder::_normalize() { + // write determinated bits + // this is the case if _low features 1 bits + // or _high features 0 bits + uint32_t lh = ~_low & _high; + if ((lh & 0x40000000) == 0) { + unsigned w = (_low & 0x40000000) != 0; + _bos.put(w, 1); + _writeE3(w - 1); + if ((lh & 0x20000000) == 0) { + unsigned l = bitLeadingZeroes((lh << 2) + 3); + if (l <= 16) { + _bos.putReverse(_low >> (30 - l), l); + } else { + _bos.putReverse(_low >> (30 - 16), 16); + _bos.putReverse(_low >> (30 - l), l - 16); + } + _low = (_low << (l + 1)) & 0x7fffffff; + _high = (((_high + 1) << (l + 1)) - 1) & 0x7fffffff; + } else { + _low = (_low << 1) & 0x7fffffff; + _high = ((_high << 1) + 1) & 0x7fffffff; + } + } + + // count indeterminated bits + lh = ~_low | _high; + if ((lh & 0x20000000) == 0) { + // low starts with 01, high starts with 10 + unsigned l = bitLeadingZeroes((lh << 2) + 3); + _e3cnt += l; + _low = (_low << l) & 0x3fffffff; + _high = ((((_high + 1) << l) - 1) & 0x3fffffff) + | 0x40000000; + } +} + +ArithmeticDecoder::ArithmeticDecoder(BitInputStream& bis) + : _bis(bis) + , _value(0) + , _low(0) + , _high(0x7fffffff) { + _value = _bis.getReverse(16) << 15; + _value |= _bis.getReverse(15); +} +void ArithmeticDecoder::_normalize() { + // skip determinated bits + // this is the case if _low features 1 bits + // or _high features 0 bits + uint32_t lh = ~_low & _high; + if ((lh & 0x40000000) == 0) { + //unsigned w = (_low & 0x40000000) != 0; + if ((lh & 0x20000000) == 0) { + unsigned l = bitLeadingZeroes((lh << 2) + 3); + _low = (_low << (l + 1)) & 0x7fffffff; + _high = (((_high + 1) << (l + 1)) - 1) & 0x7fffffff; + if (l <= 15) { + _value = ((_value << (l + 1)) + _bis.getReverse(l + 1)) & 0x7fffffff; + } else { + _value = ((_value << 16) + _bis.getReverse(16)) & 0x7fffffff; + _value = ((_value << (l - 15)) + _bis.getReverse(l - 15)) & 0x7fffffff; + } + } else { + _low = (_low << 1) & 0x7fffffff; + _high = ((_high << 1) + 1) & 0x7fffffff; + _value = ((_value << 1) + _bis.get(1)) & 0x7fffffff; + } + } + + // count indeterminated bits + lh = ~_low | _high; + if ((lh & 0x20000000) == 0) { + // low starts with 01, high starts with 10 + unsigned l = bitLeadingZeroes((lh << 2) + 3); + _low = (_low << l) & 0x3fffffff; + _high = ((((_high + 1) << l) - 1) & 0x3fffffff) + | 0x40000000; + if (l <= 16) { + _value = ((_value << l) + _bis.getReverse(l)) & 0x7fffffff; + } else { + _value = ((_value << 16) + _bis.getReverse(16)) & 0x7fffffff; + _value = ((_value << (l - 16)) + _bis.getReverse(l - 16)) & 0x7fffffff; + } + } +} + +bool modelCheckFixed(unsigned bounds[], unsigned short ids[], unsigned short rids[], + const unsigned N) { + unsigned idx = N; + for (unsigned i = 0; i < N; ++i) { + if (bounds[i]) { + if (idx != N) { + return false; + } + idx = i; + } + } + ids[N - 1] = idx; + rids[idx] = N - 1; + bounds[idx] = 0; + bounds[N] = 1 << 16; + return true; +} + +void modelSortBounds(unsigned bounds[], unsigned short ids[], unsigned short rids[], + unsigned backup[], const unsigned N) { + for (unsigned i = 0; i < N; ++i) { + ids[i] = i; + backup[i] = bounds[i]; + } + std::sort(ids, ids + N, [=](unsigned i1, unsigned i2) { + if (backup[i1] != backup[i2]) { + return backup[i1] < backup[i2]; + } + return i1 < i2; + }); + for (unsigned i = 0; i < N; ++i) { + bounds[i] = backup[ids[i]]; + rids[ids[i]] = i; + } +} + +void modelRecreateBounds(unsigned bounds[], const unsigned N) { + unsigned sum = sumArray(bounds, N), acc, prev; + prev = bounds[0]; + bounds[0] = acc = 0; + for (unsigned i = 0; i < N; ++i) { + if (prev) { + acc += prev; + prev = bounds[i + 1]; + int diff = (((uint64_t)acc) << 16) / sum - bounds[i]; + unsigned diff_bits = bitLength(diff); + const unsigned k = 5; + if (diff > 0 && diff_bits > k) { + diff = diff & (((1 << k) - 1) << (diff_bits - k)); + } + bounds[i + 1] = bounds[i] + diff; + if (bounds[i + 1] <= bounds[i]) { + bounds[i + 1] = bounds[i] + 1; + } + } else { + prev = bounds[i + 1]; + bounds[i + 1] = bounds[i]; + } + } + if (bounds[N] > 0) { + bounds[N] = 1 << 16; + } +} + +void ACFixedScaleBinaryModel::build() { + if (bounds[0] == 0 || bounds[1] == 0) { + _fixed = true; + ids[1] = bounds[0] == 0; + rids[ids[1]] = 1; + bounds[1] = bounds[0] = 0; + bounds[2] = 1 << 16; + return; + } + ids[0] = 0; + ids[1] = 1; + if (bounds[1] < bounds[0]) { + std::swap(ids[0], ids[1]); + std::swap(bounds[0], bounds[1]); + } + rids[ids[0]] = 0; + rids[ids[1]] = 1; + + modelRecreateBounds(bounds, 2); +} diff --git a/contrib/preflate/support/arithmetic_coder.h b/contrib/preflate/support/arithmetic_coder.h new file mode 100644 index 0000000..6e5d818 --- /dev/null +++ b/contrib/preflate/support/arithmetic_coder.h @@ -0,0 +1,224 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef ARITHMETIC_CODER_H +#define ARITHMETIC_CODER_H + +#include +#include +#include "bitstream.h" +#include "const_division.h" + +class ArithmeticEncoder { +public: + ArithmeticEncoder(BitOutputStream& bos); + void flush(); + void encode(const uint32_t scale, const uint32_t low, const uint32_t high) { + // update steps, low count, high count + uint32_t step = ((_high - _low) + 1) / scale; + _high = _low + step * high - 1; + _low += step * low; + _normalize(); + } + void encodeShiftScale(const uint32_t shift, const uint32_t low, const uint32_t high) { + // update steps, low count, high count + uint32_t step = ((_high - _low) + 1) >> shift; + _high = _low + step * high - 1; + _low += step * low; + _normalize(); + } + void encode(const udivider_t<32>& scale, const uint32_t low, const uint32_t high) { + // update steps, low count, high count + uint32_t step = divide((_high - _low) + 1, scale); + _high = _low + step * high - 1; + _low += step * low; + _normalize(); + } + +private: + void _normalize(); + void _writeE3(const unsigned w); + + BitOutputStream& _bos; + + // arithmetic coding variables + uint32_t _low; + uint32_t _high; + uint32_t _e3cnt; +}; + +class ArithmeticDecoder { +public: + ArithmeticDecoder(BitInputStream& bis); + unsigned decode(const uint32_t scale, const unsigned bounds[], const unsigned N) { + uint32_t step = ((_high - _low) + 1) / scale; + return _decode(step, bounds, N); + } + unsigned decodeShiftScale(const uint32_t shift, const unsigned bounds[], const unsigned N) { + uint32_t step = ((_high - _low) + 1) >> shift; + return _decode(step, bounds, N); + } + unsigned decode(const udivider_t<32>& scale, const unsigned bounds[], const unsigned N) { + uint32_t step = divide((_high - _low) + 1, scale); + return _decode(step, bounds, N); + } + + unsigned decodeBinary(const uint32_t scale, const unsigned bounds[]) { + uint32_t step = ((_high - _low) + 1) / scale; + return _decodeBinary(step, bounds); + } + unsigned decodeBinaryShiftScale(const uint32_t shift, const unsigned bounds[]) { + uint32_t step = ((_high - _low) + 1) >> shift; + return _decodeBinary(step, bounds); + } + unsigned decodeBinary(const udivider_t<32>& scale, const unsigned bounds[]) { + uint32_t step = divide((_high - _low) + 1, scale); + return _decodeBinary(step, bounds); + } + +private: + unsigned _findIndex(const unsigned bounds[], + const unsigned N, + const unsigned val) { + for (unsigned i = 0; i < N; ++i) { + if (val < bounds[i + 1]) { + return i; + } + } + return N - 1; + } + unsigned _decode(const uint32_t step, const unsigned bounds[], const unsigned N) { + uint32_t val = (_value - _low) / step; + unsigned result = _findIndex(bounds, N, val); + _high = _low + step * bounds[result + 1] - 1; + _low += step * bounds[result]; + _normalize(); + return result; + } + unsigned _decodeBinary(const uint32_t step, const unsigned bounds[]) { + unsigned result = (_value >= _low + bounds[1] * step); + _high = _low + step * bounds[result + 1] - 1; + _low += step * bounds[result]; + _normalize(); + return result; + } + void _normalize(); + + BitInputStream& _bis; + + // arithmetic coding variables + uint32_t _value; + uint32_t _low; + uint32_t _high; +}; + +bool modelCheckFixed(unsigned bounds[], unsigned short ids[], unsigned short rids[], + const unsigned N); +void modelSortBounds(unsigned bounds[], unsigned short ids[], unsigned short rids[], + unsigned backup[], const unsigned N); +void modelRecreateBounds(unsigned bounds[], const unsigned N); + +template +struct ACModelBase { + static const unsigned L = N; + bool isEqualTo(const ACModelBase& m) const { + for (unsigned i = 0; i < N; ++i) { + if (bounds[i] != m.bounds[i]) { + return false; + } + if (bounds[i + 1] > 0 && ids[i] != m.ids[i]) { + return false; + } + } + if (bounds[N] != m.bounds[N]) { + return false; + } + return true; + } + + unsigned bounds[N + 1]; + unsigned short ids[N], rids[N]; + bool _fixed; +}; + +struct ACFixedScaleBinaryModel : public ACModelBase<2> { + ACFixedScaleBinaryModel() {} + ACFixedScaleBinaryModel(const unsigned(&arr)[2]) { + memcpy(this->bounds, arr, sizeof(arr)); + build(); + } + void build(); + void encode(ArithmeticEncoder* encoder, const unsigned item) { + if (!this->_fixed) { + unsigned pos = this->rids[item]; + encoder->encodeShiftScale(16, this->bounds[pos], this->bounds[pos + 1]); + } + } +#if 0 + unsigned decode(aricoder* codec) { + symbol s; + s.scale = 1 << 16; + unsigned cnt = codec->decode_count(&s); + for (unsigned i = 0; i < N; ++i) { + if (cnt < bounds[i + 1]) { + s.low_count = bounds[i]; + s.high_count = bounds[i + 1]; + codec->decode(&s); + return ids[i]; + } + } + return 0; + } +#endif +}; + +template +struct ACFixedScaleModel : public ACModelBase { + ACFixedScaleModel() {} + ACFixedScaleModel(const unsigned(&arr)[N]) { + memcpy(this->bounds, arr, sizeof(arr)); + build(); + } + void build() { + unsigned backup[N]; + if (!(this->_fixed = modelCheckFixed(this->bounds, this->ids, this->rids, N))) { + modelSortBounds(this->bounds, this->ids, this->rids, backup, N); + modelRecreateBounds(this->bounds, N); + } + } + void encode(ArithmeticEncoder* encoder, const unsigned item) { + if (!this->_fixed) { + unsigned pos =this->rids[item]; + encoder->encodeShiftScale(16, this->bounds[pos], this->bounds[pos + 1]); + } + } +#if 0 + unsigned decode(aricoder* codec) { + symbol s; + s.scale = 1 << 16; + unsigned cnt = codec->decode_count(&s); + for (unsigned i = 0; i < N; ++i) { + if (cnt < bounds[i + 1]) { + s.low_count = bounds[i]; + s.high_count = bounds[i + 1]; + codec->decode(&s); + return this->ids[i]; + } + } + return 0; + } +#endif +}; + +#endif /* ARITHMETIC_CODER_H */ diff --git a/contrib/preflate/support/array_helper.cpp b/contrib/preflate/support/array_helper.cpp new file mode 100644 index 0000000..ae38d81 --- /dev/null +++ b/contrib/preflate/support/array_helper.cpp @@ -0,0 +1,23 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include "array_helper.h" + +unsigned sumArray(const unsigned* data, const unsigned n) { + unsigned sum = 0; + for (unsigned i = 0; i < n; ++i) { + sum += data[i]; + } + return sum; +} diff --git a/contrib/preflate/support/array_helper.h b/contrib/preflate/support/array_helper.h new file mode 100644 index 0000000..e2400ab --- /dev/null +++ b/contrib/preflate/support/array_helper.h @@ -0,0 +1,25 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef ARRAY_HELPER_H +#define ARRAY_HELPER_H + +unsigned sumArray(const unsigned* data, const unsigned n); + +template +inline unsigned sumArray(const unsigned (&data)[N]) { + return sumArray(data, N); +} + +#endif /* ARRAY_HELPER_H */ diff --git a/contrib/preflate/support/bit_helper.cpp b/contrib/preflate/support/bit_helper.cpp new file mode 100644 index 0000000..fb1606f --- /dev/null +++ b/contrib/preflate/support/bit_helper.cpp @@ -0,0 +1,59 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include "bit_helper.h" + +unsigned bitLength(unsigned value) { + unsigned l = 0; + while (value > 0) { + l++; + value >>= 1; + } + return l; +} + +static unsigned char reverse4[16] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; +static unsigned bitReverse8(const unsigned value) { + return (reverse4[value & 0x0f] << 4) | reverse4[(value >> 4) & 0x0f]; +} +static unsigned bitReverse16(const unsigned value) { + return (bitReverse8(value & 0xff) << 8) | bitReverse8(value >> 8); +} +static unsigned bitReverse32(const unsigned value) { + return (bitReverse16(value & 0xffff) << 16) | bitReverse16(value >> 16); +} +unsigned bitReverse(const unsigned value, const unsigned bits) { + if (bits <= 8) { + return bitReverse8(value) >> (8 - bits); + } + if (bits <= 16) { + return bitReverse16(value) >> (16 - bits); + } + return bitReverse32(value) >> (32 - bits); +} + +static unsigned char leading4[16] = {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}; +unsigned bitLeadingZeroes(const unsigned value_) { + if (value_ == 0) { + return 32; + } + unsigned value = value_; + unsigned result = 0; + while ((value & 0xf0000000) == 0) { + value <<= 4; + result += 4; + } + return result + leading4[value >> 28]; +} + diff --git a/contrib/preflate/support/bit_helper.h b/contrib/preflate/support/bit_helper.h new file mode 100644 index 0000000..ccee6db --- /dev/null +++ b/contrib/preflate/support/bit_helper.h @@ -0,0 +1,22 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef BIT_HELPER_H +#define BIT_HELPER_H + +unsigned bitLength(unsigned value); +unsigned bitReverse(const unsigned value, const unsigned bits); +unsigned bitLeadingZeroes(const unsigned value); + +#endif /* BIT_HELPER_H */ diff --git a/contrib/preflate/support/bitstream.cpp b/contrib/preflate/support/bitstream.cpp new file mode 100644 index 0000000..a8ff360 --- /dev/null +++ b/contrib/preflate/support/bitstream.cpp @@ -0,0 +1,120 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "bitstream.h" + +BitInputStream::BitInputStream(InputStream& is) + : _input(is) + , _bufPos(0) + , _bufSize(0) + , _bufFastLimit(0) + , _eof(false) + , _bits(0) + , _bitsRemaining(0) + , _totalBitPos(0) +{} + +void BitInputStream::_fillBytes() { + // free space in bit buffer + if (_bufPos >= _bufFastLimit) { + if (!_eof) { + unsigned remaining = _bufSize - _bufPos; + memcpy(_buffer + PRE_BUF_EXTRA - remaining, + _buffer + _bufPos, remaining); + _bufPos = PRE_BUF_EXTRA - remaining; + _bufSize = PRE_BUF_EXTRA + _input.read(_buffer + PRE_BUF_EXTRA, BUF_SIZE); + _bufFastLimit = std::max(_bufPos, _bufSize - PRE_BUF_EXTRA); + _eof = _bufSize != PRE_BUF_EXTRA + BUF_SIZE; + } + } +} +void BitInputStream::_fill() { + // free space in bit buffer + if (_bufPos >= _bufFastLimit) { + if (!_eof) { + _fillBytes(); + } + while (_bitsRemaining <= BITS - 8 && _bufPos < _bufSize) { + _bits |= ((size_t)_buffer[_bufPos++]) << _bitsRemaining; + _bitsRemaining += 8; + } + return; + } + while (_bitsRemaining <= BITS - 8) { + _bits |= ((size_t)_buffer[_bufPos++]) << _bitsRemaining; + _bitsRemaining += 8; + } +} +size_t BitInputStream::copyBytesTo(OutputStream& output, const size_t len) { + if (_bitsRemaining & 7) { + return 0; + } + uint8_t a[sizeof(_bits)]; + size_t l = 0; + while (_bitsRemaining > 0 && l < len) { + a[l++] = _bits & 0xff; + _bitsRemaining -= 8; + _bits >>= 8; + _totalBitPos += 8; + } + size_t w = output.write(a, l); + if (w != l) { + return w; + } + while (l < len) { + unsigned todo = std::min(len - l, (size_t)(_bufSize - _bufPos)); + w = output.write(_buffer + _bufPos, todo); + _totalBitPos += 8 * w; + _bufPos += w; + l += w; + if (w != todo) { + return l; + } + _fillBytes(); + } + return l; +} + +BitOutputStream::BitOutputStream(OutputStream& output) + : _output(output) + , _bufPos(0) + , _bits(0) + , _bitPos(0) {} + +void BitOutputStream::_flush() { + while (_bitPos >= 8) { + _buffer[_bufPos++] = _bits & 0xff; + _bits >>= 8; + _bitPos -= 8; + } + if (_bufPos >= BUF_SIZE) { + _output.write(_buffer, BUF_SIZE); + memcpy(_buffer, _buffer + BUF_SIZE, _bufPos - BUF_SIZE); + _bufPos -= BUF_SIZE; + } +} +void BitOutputStream::flush() { + _flush(); + + if (_bitPos > 0) { + _buffer[_bufPos++] = _bits & 0xff; + _bits = 0; + _bitPos = 0; + } + + _output.write(_buffer, _bufPos); + _bufPos = 0; +} diff --git a/contrib/preflate/support/bitstream.h b/contrib/preflate/support/bitstream.h new file mode 100644 index 0000000..e393cfd --- /dev/null +++ b/contrib/preflate/support/bitstream.h @@ -0,0 +1,126 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef BITSTREAM_H +#define BITSTREAM_H + +#include +#include "bit_helper.h" +#include "stream.h" + +// Huffman decoder for little endian +class BitInputStream { +public: + BitInputStream(InputStream&); + + bool eof() const { + return _eof && _bufPos == _bufSize && !_bitsRemaining; + } + + size_t bitPos() const { + return _totalBitPos; + } + + size_t peek(const unsigned n) { + if (_bitsRemaining < n) { + _fill(); + } + return _bits & ((1 << n) - 1); + } + void skip(const unsigned n) { + _bitsRemaining -= std::min(n, _bitsRemaining); + _bits >>= n; + _totalBitPos += n; + } + size_t get(const unsigned n) { + size_t v = peek(n); + skip(n); + return v; + } + size_t getReverse(const unsigned n) { + return bitReverse(get(n), n); + } + void skipToByte() { + skip(_bitsRemaining & 7); + } + bool checkLastBitsOfByteAreZero() { + return peek(_bitsRemaining & 7) == 0; + } + void fastFill(const unsigned n) { + if (_bitsRemaining < n) { + _fill(); + } + } + size_t fastPeek(const unsigned n) { + return _bits & ((1 << n) - 1); + } + size_t fastGet(const unsigned n) { + size_t v = fastPeek(n); + skip(n); + return v; + } + size_t copyBytesTo(OutputStream& output, const size_t len); + +private: + void _fillBytes(); + void _fill(); + + enum { BUF_SIZE = 1024, PRE_BUF_EXTRA = 16, BITS = sizeof(size_t)*8 }; + + InputStream& _input; + unsigned char _buffer[PRE_BUF_EXTRA + BUF_SIZE]; + unsigned _bufPos, _bufSize, _bufFastLimit; + bool _eof; + size_t _bits; + unsigned _bitsRemaining; + size_t _totalBitPos; +}; + +class BitOutputStream { +public: + BitOutputStream(OutputStream&); + + void put(const size_t value, const unsigned n) { + if (_bitPos + n > BITS) { + _flush(); + } + _bits |= (value & ((1 << n) - 1)) << _bitPos; + _bitPos += n; + } + void putReverse(const size_t value, const unsigned n) { + put(bitReverse(value, n), n); + } + void fillByte() { + _bitPos = (_bitPos + 7) & ~7; + } + void flush(); + unsigned bitPos() const { + return _bitPos; + } + +private: + void _flush(); + + enum { + BUF_SIZE = 1024, BUF_EXTRA = 64, BITS = sizeof(size_t) * 8 + }; + + OutputStream& _output; + unsigned char _buffer[BUF_SIZE + BUF_EXTRA]; + unsigned _bufPos; + size_t _bits; + unsigned _bitPos; +}; + +#endif /* BITSTREAM_H */ diff --git a/contrib/preflate/support/const_division.cpp b/contrib/preflate/support/const_division.cpp new file mode 100644 index 0000000..52b9679 --- /dev/null +++ b/contrib/preflate/support/const_division.cpp @@ -0,0 +1,114 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include "bit_helper.h" +#include "const_division.h" + +// Based on "N-Bit Unsigned Division Via N-Bit Multiply-Add" +// by Robison + +template +udivider_t build_udivider(const typename divider_uint_t::type d) { + typedef typename divider_uint_t::type T1; + typedef typename divider_uint_t::type T2; + udivider_t result; + result.shift = bitLength(d) - 1; + if ((d & (d - 1)) == 0) { + result.magic1 = result.magic2 = ~(T2)0; + } else { + T2 shm = 1 << result.shift; + T2 t = (((T1)shm) << N) / d; + T2 r = t * d + d; + if (r <= shm) { + result.magic1 = t + 1; + result.magic2 = 0; + } else { + result.magic1 = t; + result.magic2 = t; + } + } + return result; +} + +udivider_t<16> build_udivider_16(const uint16_t d) { + return build_udivider<16>(d); +} +udivider_t<32> build_udivider_32(const uint32_t d) { + return build_udivider<32>(d); +} + +template +ucdivider_t build_ucdivider(const typename divider_uint_t::type d) { + typedef typename divider_uint_t::type T1; + typedef typename divider_uint_t::type T2; + ucdivider_t result; + result.ctrl = bitLength(d) - 1; + if ((d & (d - 1)) == 0) { + result.magic = ~(T2)0; + result.ctrl |= 0x80; + } else { + T2 shm = 1 << result.ctrl; + T2 t = (((T1)shm) << N) / d; + T2 r = t * d + d; + if (r <= shm) { + result.magic = t + 1; + } else { + result.magic = t; + result.ctrl |= 0x80; + } + } + return result; +} + +ucdivider_t<16> build_ucdivider_16(const uint16_t d) { + return build_ucdivider<16>(d); +} +ucdivider_t<32> build_ucdivider_32(const uint32_t d) { + return build_ucdivider<32>(d); +} + +template +sdivider_t build_sdivider(const typename divider_int_t::type d_) { + sdivider_t result; + udivider_t uresult = build_udivider(d_ < 0 ? -d_ : d_); + result.magic1 = uresult.magic1; + result.magic2 = uresult.magic2; + result.shift = uresult.shift; + result.sign = d_ < 0 ? -1 : 0; + return result; +} +sdivider_t<16> build_sdivider_16(const int16_t d) { + return build_sdivider<16>(d); +} +sdivider_t<32> build_sdivider_32(const int32_t d) { + return build_sdivider<32>(d); +} + +template +scdivider_t build_scdivider(const typename divider_int_t::type d_) { + scdivider_t result; + ucdivider_t uresult = build_ucdivider(d_ < 0 ? -d_ : d_); + result.magic = uresult.magic; + result.ctrl = uresult.ctrl; + if (d_ < 0) { + result.ctrl |= 0x40; + } + return result; +} +scdivider_t<16> build_scdivider_16(const int16_t d) { + return build_scdivider<16>(d); +} +scdivider_t<32> build_scdivider_32(const int32_t d) { + return build_scdivider<32>(d); +} diff --git a/contrib/preflate/support/const_division.h b/contrib/preflate/support/const_division.h new file mode 100644 index 0000000..0d197db --- /dev/null +++ b/contrib/preflate/support/const_division.h @@ -0,0 +1,170 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef CONST_DIVISION_H +#define CONST_DIVISION_H + +#include + +template struct divider_int_t; +template struct divider_uint_t; +template <> struct divider_int_t<16> { + typedef int16_t type; +}; +template <> struct divider_int_t<32> { + typedef int32_t type; +}; +template <> struct divider_uint_t<16> { + typedef uint16_t type; +}; +template <> struct divider_uint_t<32> { + typedef uint32_t type; +}; +template <> struct divider_uint_t<64> { + typedef uint64_t type; +}; + + +template +struct udivider_t { + typename divider_uint_t::type magic1; // factor + typename divider_uint_t::type magic2; // addend + uint8_t shift; +}; + +template +struct ucdivider_t { + typename divider_uint_t::type magic; // factor/addend + uint8_t ctrl; // bits 0..3/4/5 - shift, bit 7 - add required +}; + +// If it wasn't for +/-1, the signed dividers wouldn't +// need the add-term (magic2), as they could just +// use a factor (magic1) with one more bit precision. +template +struct sdivider_t { + typename divider_uint_t::type magic1; // factor + typename divider_uint_t::type magic2; // addend + uint8_t shift; + int8_t sign; // -1 if negative, 0 otherwise +}; + +template +struct scdivider_t { + typename divider_uint_t::type magic; + uint8_t ctrl; // bits 0..3/4/5 - shift, bit 6 - negative, bit 7 - add required +}; + +udivider_t<16> build_udivider_16(const uint16_t d); +udivider_t<32> build_udivider_32(const uint32_t d); + +ucdivider_t<16> build_ucdivider_16(const uint16_t d); +ucdivider_t<32> build_ucdivider_32(const uint32_t d); + +sdivider_t<16> build_sdivider_16(const int16_t d); +sdivider_t<32> build_sdivider_32(const int32_t d); + +scdivider_t<16> build_scdivider_16(const int16_t d); +scdivider_t<32> build_scdivider_32(const int32_t d); + +template +inline typename divider_uint_t::type +divide_template(const typename divider_uint_t::type dividend, + const udivider_t& divisor) { + typedef typename divider_uint_t::type T1; + typedef typename divider_uint_t::type T2; + T1 t = ((T1)dividend) * divisor.magic1 + divisor.magic2; + T2 u = (T2)(t >> N2); + return u >> divisor.shift; +} +template +inline typename divider_uint_t::type +divide_template(const typename divider_uint_t::type dividend, + const ucdivider_t& divisor) { + typedef typename divider_uint_t::type T1; + typedef typename divider_uint_t::type T2; + T1 t = ((T1)dividend) * divisor.magic + + (divisor.ctrl & 0x80 ? divisor.magic : 0); + T2 u = (T2)(t >> N2); + return u >> (divisor.ctrl & (N2 - 1)); +} +template +inline typename divider_int_t::type +divide_template(const typename divider_int_t::type dividend, + const sdivider_t& divisor) { + typedef typename divider_uint_t::type T1; + typedef typename divider_uint_t::type T2; + T2 s = dividend < 0 ? -1 : 0; + T1 t = ((T1)(T2)((dividend ^ s) - s)) * divisor.magic1 + + divisor.magic2; + T2 u = (T2)(t >> N2) >> divisor.shift; + s ^= divisor.sign; + return (u ^ s) - s; +} +template +inline typename divider_int_t::type +divide_template(const typename divider_int_t::type dividend, + const scdivider_t& divisor) { + typedef typename divider_uint_t::type T1; + typedef typename divider_uint_t::type T2; + + T2 s = dividend < 0 ? -1 : 0; + T1 t = ((T1)(T2)((dividend ^ s) - s)) * divisor.magic + + (divisor.ctrl & 0x80 ? divisor.magic : 0); + T2 u = (T2)(t >> N2) >> (divisor.ctrl & (N2 - 1)); + s ^= (divisor.ctrl & 0x40 ? -1 : 0); + return (u ^ s) - s; +} + +inline uint16_t divide(const uint16_t dividend, const udivider_t<16>& divisor) { + return divide_template<16, 16>(dividend, divisor); +} +inline uint32_t divide(const uint32_t dividend, const udivider_t<16>& divisor) { + return divide_template<32, 16>(dividend, divisor); +} +inline uint32_t divide(const uint32_t dividend, const udivider_t<32>& divisor) { + return divide_template<32, 32>(dividend, divisor); +} + +inline uint16_t divide(const uint16_t dividend, const ucdivider_t<16>& divisor) { + return divide_template<16, 16>(dividend, divisor); +} +inline uint32_t divide(const uint32_t dividend, const ucdivider_t<16>& divisor) { + return divide_template<32, 16>(dividend, divisor); +} +inline uint32_t divide(const uint32_t dividend, const ucdivider_t<32>& divisor) { + return divide_template<32, 32>(dividend, divisor); +} + +inline int16_t divide(const int16_t dividend, const sdivider_t<16>& divisor) { + return divide_template<16, 16>(dividend, divisor); +} +inline int32_t divide(const int32_t dividend, const sdivider_t<16>& divisor) { + return divide_template<32, 16>(dividend, divisor); +} +inline int32_t divide(const int32_t dividend, const sdivider_t<32>& divisor) { + return divide_template<32, 32>(dividend, divisor); +} + +inline int16_t divide(const int16_t dividend, const scdivider_t<16>& divisor) { + return divide_template<16, 16>(dividend, divisor); +} +inline int32_t divide(const int32_t dividend, const scdivider_t<16>& divisor) { + return divide_template<32, 16>(dividend, divisor); +} +inline int32_t divide(const int32_t dividend, const scdivider_t<32>& divisor) { + return divide_template<32, 32>(dividend, divisor); +} + +#endif /* CONST_DIVISION_H */ diff --git a/contrib/preflate/support/filestream.cpp b/contrib/preflate/support/filestream.cpp new file mode 100644 index 0000000..fc65eee --- /dev/null +++ b/contrib/preflate/support/filestream.cpp @@ -0,0 +1,40 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include +#include "filestream.h" + +FileStream::FileStream(FILE* f) : _f(f) {} + +bool FileStream::eof() const { + return feof(_f); +} +size_t FileStream::read(unsigned char* buffer, const size_t size) { + return fread(buffer, 1, size, _f); +} + +size_t FileStream::write(const unsigned char* buffer, const size_t size) { + return fwrite(buffer, 1, size, _f); +} + +uint64_t FileStream::tell() const { + return _ftelli64(_f); +} +uint64_t FileStream::seek(const uint64_t newPos) { + uint64_t oldPos = tell(); + _fseeki64(_f, newPos, SEEK_SET); + return oldPos; +} diff --git a/contrib/preflate/support/filestream.h b/contrib/preflate/support/filestream.h new file mode 100644 index 0000000..d12d0d2 --- /dev/null +++ b/contrib/preflate/support/filestream.h @@ -0,0 +1,38 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef FILESTREAM_H +#define FILESTREAM_H + +#include +#include +#include "stream.h" + +class FileStream : public SeekableInputOutputStream { +public: + FileStream(FILE* f); + + virtual bool eof() const; + virtual size_t read(unsigned char* buffer, const size_t size); + + virtual size_t write(const unsigned char* buffer, const size_t size); + + virtual uint64_t tell() const; + virtual uint64_t seek(const uint64_t newPos); + +private: + FILE* _f; +}; + +#endif /* FILESTREAM_H */ diff --git a/contrib/preflate/support/huffman_decoder.cpp b/contrib/preflate/support/huffman_decoder.cpp new file mode 100644 index 0000000..47dbaec --- /dev/null +++ b/contrib/preflate/support/huffman_decoder.cpp @@ -0,0 +1,110 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "huffman_decoder.h" +#include "huffman_helper.h" +#include "bit_helper.h" + +HuffmanDecoder::HuffmanDecoder( + const unsigned char* symbolBitLengths, + const size_t symbolCount, + const bool disableZeroBitSymbols, + const unsigned char maxBitsPerTable +) : _error(false) { + if (!_constructTables(symbolBitLengths, symbolCount, disableZeroBitSymbols, maxBitsPerTable)) { + _constructErrorTable(); + } +} + +size_t HuffmanDecoder::_decodeDeeper( + BitInputStream& bis, + const size_t tableId_ +) const { + bis.skip(_table0.peekBits); + size_t tableId = tableId_; + do { + const Table* table = &_tables[tableId]; + size_t v = bis.peek(table->peekBits); + signed short w = table->lookup[v]; + if (w >= 0) { + bis.skip(w & 0xf); + return w >> 4; + } + bis.skip(table->peekBits); + tableId = ~w; + } while (true); +} +bool HuffmanDecoder::_constructTables( + const unsigned char* symbolBitLengths, + const size_t symbolCount, + const bool disableZeroBitSymbols, + const unsigned char maxBitsPerTable +) { + if (maxBitsPerTable < 1 || maxBitsPerTable > 15) { + return false; + } + unsigned nextCode[HuffmanHelper::MAX_BL + 2]; + unsigned char minLength, maxLength; + if (!HuffmanHelper::countSymbols(nextCode, minLength, maxLength, + symbolBitLengths, symbolCount, + disableZeroBitSymbols)) { + return false; + } + + _table0.peekBits = std::min((unsigned char)(maxLength - 1), maxBitsPerTable); + _table0.lookup.resize(1 << _table0.peekBits); + std::fill(_table0.lookup.begin(), _table0.lookup.end(), 0); + + unsigned char minL = disableZeroBitSymbols ? 2 : 1; + + for (unsigned i = 0; i < symbolCount; ++i) { + unsigned char l = (unsigned char)(symbolBitLengths[i] + 1); + if (l < minL) { + continue; + } + unsigned char k = l - 1, maxK = maxLength - 1; + unsigned code = bitReverse(nextCode[l]++, k); + Table* t = &_table0; + while (k > t->peekBits) { + k -= t->peekBits; + maxK -= t->peekBits; + unsigned subbits = code & ((1 << t->peekBits) - 1); + code >>= t->peekBits; + signed short v = t->lookup[subbits]; + if (v >= 0) { + unsigned newTableId = _tables.size(); + t->lookup[subbits] = ~newTableId; + _tables.push_back(Table()); + t = &_tables[newTableId]; + t->peekBits = std::min(maxK, maxBitsPerTable); + t->lookup.resize(1 << t->peekBits); + std::fill(t->lookup.begin(), t->lookup.end(), 0); + } else { + t = &_tables[~v]; + } + } + do { + t->lookup[code] = (i << 4) | k; + code += 1 << k; + } while (code < t->lookup.size()); + } + return true; +} +void HuffmanDecoder::_constructErrorTable() { + _error = true; + _table0.peekBits = 0; + _table0.lookup.resize(1); + _table0.lookup[0] = 0; +} diff --git a/contrib/preflate/support/huffman_decoder.h b/contrib/preflate/support/huffman_decoder.h new file mode 100644 index 0000000..264ebe6 --- /dev/null +++ b/contrib/preflate/support/huffman_decoder.h @@ -0,0 +1,62 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef HUFFMAN_DECODER_H +#define HUFFMAN_DECODER_H + +#include +#include "bitstream.h" + +// Huffman decoder +class HuffmanDecoder { +public: + HuffmanDecoder(const unsigned char* symbolBitLengths, + const size_t symbolCount, + const bool disableZeroBitSymbols, + const unsigned char maxBitsPerTable); + + bool error() const { + return _error; + } + + size_t decode(BitInputStream& bis) const { + size_t v = bis.peek(_table0.peekBits); + signed short w = _table0.lookup[v]; + if (w >= 0) { + bis.skip(w & 0xf); + return w >> 4; + } + return _decodeDeeper(bis, ~w); + } + +private: + size_t _decodeDeeper(BitInputStream& bis, const size_t tableId) const; + bool _constructTables(const unsigned char* symbolBitLengths, + const size_t symbolCount, + const bool disableZeroBitSymbols, + const unsigned char maxBitsPerTable); + void _constructErrorTable(); + +private: + struct Table { + unsigned char peekBits; + std::vector lookup; + }; + + Table _table0; + std::vector _tables; + bool _error; +}; + +#endif /* HUFFMAN_DECODER_H */ diff --git a/contrib/preflate/support/huffman_encoder.cpp b/contrib/preflate/support/huffman_encoder.cpp new file mode 100644 index 0000000..caec63c --- /dev/null +++ b/contrib/preflate/support/huffman_encoder.cpp @@ -0,0 +1,64 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "huffman_encoder.h" +#include "huffman_helper.h" +#include "bit_helper.h" + +HuffmanEncoder::HuffmanEncoder( + const unsigned char* symbolBitLengths, + const unsigned symbolCount, + const bool disableZeroBitSymbols +) : _error(false) { + if (!_constructTables(symbolBitLengths, symbolCount, disableZeroBitSymbols)) { + _constructErrorTable(symbolCount); + } +} + +bool HuffmanEncoder::_constructTables( + const unsigned char* symbolBitLengths, + const unsigned symbolCount, + const bool disableZeroBitSymbols +) { + unsigned nextCode[HuffmanHelper::MAX_BL + 2]; + unsigned char minLength, maxLength; + if (!HuffmanHelper::countSymbols(nextCode, minLength, maxLength, + symbolBitLengths, symbolCount, + disableZeroBitSymbols)) { + return false; + } + + unsigned char minL = disableZeroBitSymbols ? 2 : 1; + + _lookup.resize(symbolCount); + for (unsigned i = 0; i < symbolCount; ++i) { + unsigned char l = (unsigned char)(symbolBitLengths[i] + 1); + if (l < minL) { + _lookup[i] = 0; + continue; + } + unsigned char k = l - 1; + unsigned code = bitReverse(nextCode[l]++, k); + _lookup[i] = (code << 5) | k; + } + return true; +} +void HuffmanEncoder::_constructErrorTable( + const unsigned symbolCount +) { + _error = true; + _lookup.resize(symbolCount); + std::fill(_lookup.begin(), _lookup.end(), 0); +} diff --git a/contrib/preflate/support/huffman_encoder.h b/contrib/preflate/support/huffman_encoder.h new file mode 100644 index 0000000..a499846 --- /dev/null +++ b/contrib/preflate/support/huffman_encoder.h @@ -0,0 +1,48 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef HUFFMAN_ENCODER_H +#define HUFFMAN_ENCODER_H + +#include +#include "bitstream.h" + +// Huffman decoder +class HuffmanEncoder { +public: + HuffmanEncoder(const unsigned char* symbolBitLengths, + const unsigned symbolCount, + const bool disableZeroBitSymbols); + + bool error() const { + return _error; + } + + void encode(BitOutputStream& bos, const unsigned symbol) const { + unsigned v = _lookup[symbol]; + bos.put(v >> 5, v & 0x1f); + } + +private: + bool _constructTables(const unsigned char* symbolBitLengths, + const unsigned symbolCount, + const bool disableZeroBitSymbols); + void _constructErrorTable(const unsigned symbolCount); + +private: + std::vector _lookup; + bool _error; +}; + +#endif /* HUFFMAN_ENCODER_H */ diff --git a/contrib/preflate/support/huffman_helper.cpp b/contrib/preflate/support/huffman_helper.cpp new file mode 100644 index 0000000..b3638f5 --- /dev/null +++ b/contrib/preflate/support/huffman_helper.cpp @@ -0,0 +1,74 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "huffman_helper.h" +#include "bit_helper.h" + +bool HuffmanHelper::countSymbols( + unsigned(&nextCode)[MAX_BL + 2], + unsigned char& minLength, + unsigned char& maxLength, + const unsigned char* symbolBitLengths, + const unsigned symbolCount, + const bool disableZeroBitSymbols +) { + if (symbolCount < 1 || symbolCount >= 1024) { + return false; + } + unsigned short blCount[MAX_BL + 2]; + + // Count symbol frequencies + memset(blCount, 0, sizeof(blCount)); + for (unsigned i = 0; i < symbolCount; ++i) { + unsigned char l = (unsigned char)(symbolBitLengths[i] + 1); + if (l > MAX_BL + 1) { + return false; + } + blCount[l]++; + } + for (minLength = 1; minLength <= MAX_BL + 1; ++minLength) { + if (blCount[minLength]) { + break; + } + } + for (maxLength = MAX_BL + 1; maxLength >= minLength; --maxLength) { + if (blCount[maxLength]) { + break; + } + } + if (minLength > maxLength) { + return false; + } + // Remove deleted symbols + blCount[0] = 0; + if (disableZeroBitSymbols) { + blCount[1] = 0; + } + + // Calculate start codes + unsigned code = 0; + for (unsigned i = minLength; i <= maxLength; ++i) { + code = (code + blCount[i - 1]) << 1; + nextCode[i] = code; + } + + if (minLength == maxLength && blCount[maxLength] == 1) { + return true; + } + + // Check that we don't have holes + return nextCode[maxLength] + blCount[maxLength] == (unsigned)(1 << (maxLength - 1)); +} diff --git a/contrib/preflate/support/huffman_helper.h b/contrib/preflate/support/huffman_helper.h new file mode 100644 index 0000000..39d33f7 --- /dev/null +++ b/contrib/preflate/support/huffman_helper.h @@ -0,0 +1,34 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef HUFFMAN_HELPER_H +#define HUFFMAN_HELPER_H + +#include + +// Huffman decoder +class HuffmanHelper { +public: + enum { + MAX_BL = 25 + }; + static bool countSymbols(unsigned(&nextCode)[MAX_BL + 2], + unsigned char& minLength, + unsigned char& maxLength, + const unsigned char* symbolBitLengths, + const unsigned symbolCount, + const bool disableZeroBitSymbols); +}; + +#endif /* HUFFMAN_HELPER_H */ diff --git a/contrib/preflate/support/memstream.cpp b/contrib/preflate/support/memstream.cpp new file mode 100644 index 0000000..9ef158f --- /dev/null +++ b/contrib/preflate/support/memstream.cpp @@ -0,0 +1,51 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include +#include "memstream.h" + +MemStream::MemStream() : _pos(0) {} +MemStream::MemStream(const std::vector& content) + : _data(content) + , _pos(0) {} + +bool MemStream::eof() const { + return _pos == _data.size(); +} +size_t MemStream::read(unsigned char* buffer, const size_t size) { + size_t toCopy = std::min(size, _data.size() - _pos); + memcpy(buffer, _data.data() + _pos, toCopy); + _pos += toCopy; + return toCopy; +} + +size_t MemStream::write(const unsigned char* buffer, const size_t size) { + size_t remaining = _data.size() - _pos; + if (size > remaining) { + _data.resize(_pos + size); + } + memcpy(_data.data() + _pos, buffer, size); + _pos += size; + return size; +} + +uint64_t MemStream::tell() const { + return _pos; +} +uint64_t MemStream::seek(const uint64_t newPos) { + size_t oldPos = _pos; + _pos = std::min(newPos, (uint64_t)_data.size()); + return oldPos; +} diff --git a/contrib/preflate/support/memstream.h b/contrib/preflate/support/memstream.h new file mode 100644 index 0000000..0e2ed87 --- /dev/null +++ b/contrib/preflate/support/memstream.h @@ -0,0 +1,47 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef MEMSTREAM_H +#define MEMSTREAM_H + +#include +#include +#include "stream.h" + +class MemStream : public SeekableInputOutputStream { +public: + MemStream(); + MemStream(const std::vector& content); + + virtual bool eof() const; + virtual size_t read(unsigned char* buffer, const size_t size); + + virtual size_t write(const unsigned char* buffer, const size_t size); + + virtual uint64_t tell() const; + virtual uint64_t seek(const uint64_t newPos); + + const std::vector& data() const { + return _data; + } + std::vector extractData() { + return std::move(_data); + } + +private: + std::vector _data; + size_t _pos; +}; + +#endif /* MEMSTREAM_H */ diff --git a/contrib/preflate/support/outputcachestream.cpp b/contrib/preflate/support/outputcachestream.cpp new file mode 100644 index 0000000..d3d2996 --- /dev/null +++ b/contrib/preflate/support/outputcachestream.cpp @@ -0,0 +1,29 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "outputcachestream.h" + +OutputCacheStream::OutputCacheStream(OutputStream& os) + : _os(os) + , _cacheStartPos(0) {} +OutputCacheStream::~OutputCacheStream() { +} + +void OutputCacheStream::flushUpTo(const uint64_t newStartPos) { + size_t toWrite = std::min(newStartPos - _cacheStartPos, (uint64_t)_cache.size()); + size_t written = _os.write(_cache.data(), toWrite); + _cacheStartPos += written; + _cache.erase(_cache.begin(), _cache.begin() + written); +} diff --git a/contrib/preflate/support/outputcachestream.h b/contrib/preflate/support/outputcachestream.h new file mode 100644 index 0000000..d95c236 --- /dev/null +++ b/contrib/preflate/support/outputcachestream.h @@ -0,0 +1,67 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef OUTPUTCACHESTREAM_H +#define OUTPUTCACHESTREAM_H + +#include +#include +#include "stream.h" + +class OutputCacheStream : public OutputStream { +public: + OutputCacheStream(OutputStream& os); + ~OutputCacheStream(); + + size_t write(const unsigned char* buffer, const size_t size) { +/* if (size == 1) { + _cache.push_back(*buffer); + return 1; + }*/ + _cache.insert(_cache.end(), buffer, buffer + size); + return size; + } + void reserve(const size_t len) { + size_t cap = _cache.capacity(); + if (_cache.size() + len > cap) { + _cache.reserve(cap + std::max(cap >> 1, len)); + } + } + void flush() { + flushUpTo(cacheEndPos()); + } + void flushUpTo(const uint64_t newStartPos); + uint64_t cacheStartPos() const { + return _cacheStartPos; + } + uint64_t cacheEndPos() const { + return _cacheStartPos + _cache.size(); + } + const unsigned char* cacheData(const uint64_t pos) const { + return _cache.data() + (ptrdiff_t)(pos - _cacheStartPos); + } + const unsigned char* cacheEnd() const { + return _cache.data() + _cache.size(); + } + const size_t cacheSize() const { + return _cache.size(); + } + +private: + OutputStream& _os; + std::vector _cache; + uint64_t _cacheStartPos; +}; + +#endif /* OUTPUTCACHESTREAM_H */ diff --git a/contrib/preflate/support/stream.h b/contrib/preflate/support/stream.h new file mode 100644 index 0000000..f41f0c6 --- /dev/null +++ b/contrib/preflate/support/stream.h @@ -0,0 +1,45 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef STREAM_H +#define STREAM_H + +#include + +class InputStream { +public: + virtual bool eof() const = 0; + virtual size_t read(unsigned char* buffer, const size_t size) = 0; +}; + +class OutputStream { +public: + virtual size_t write(const unsigned char* buffer, const size_t size) = 0; +}; + +class SeekableStream { +public: + virtual uint64_t tell() const = 0; + virtual uint64_t seek(const uint64_t newPos) = 0; +}; + +class SeekableInputStream + : public InputStream + , public SeekableStream {}; +class SeekableInputOutputStream + : public SeekableInputStream + , public OutputStream {}; + + +#endif /* STREAM_H */ diff --git a/contrib/preflate/support/support_tests.cpp b/contrib/preflate/support/support_tests.cpp new file mode 100644 index 0000000..b633bae --- /dev/null +++ b/contrib/preflate/support/support_tests.cpp @@ -0,0 +1,180 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include +#include "array_helper.h" +#include "bit_helper.h" +#include "bitstream.h" +#include "const_division.h" +#include "huffman_decoder.h" +#include "huffman_encoder.h" +#include "huffman_helper.h" +#include "memstream.h" +#include "outputcachestream.h" +#include "stream.h" + +bool support_self_tests() { + unsigned arr[] = {1,2,3,4,5}; + if (sumArray(arr) != 15 + || sumArray(arr, sizeof(arr) / sizeof(arr[0])) != 15) { + printf("sumArray failed\n"); + return false; + } + if (bitLength(0) != 0 + || bitLength(15) != 4 + || bitLength(0xffffffff) != 32) { + printf("bitLength failed\n"); + return false; + } + if (bitReverse(1, 3) != 4 + || bitReverse(0x12345678, 32) != 0x1e6a2c48 + || bitReverse(0xfedcba90, 32) != 0x095d3b7f) { + printf("bitReverse failed\n"); + return false; + } + + MemStream mem; + mem.write((const uint8_t*)"Hello", 5); + if (mem.tell() != 5 || !mem.eof()) { + printf("MemStream/1 failed\n"); + return false; + } + mem.write((const uint8_t*)"!", 1); + uint8_t tmp[5], tmp2[2]; + if (mem.read(tmp, 5) != 0) { + printf("MemStream/2 failed\n"); + return false; + } + if (mem.seek(0) != 6) { + printf("MemStream/3 failed\n"); + return false; + } + if (mem.tell() != 0) { + printf("MemStream/4 failed\n"); + return false; + } + if (mem.read(tmp, 5) != 5 || tmp[0] != 'H' || tmp[4] != 'o') { + printf("MemStream/5 failed\n"); + return false; + } + if (mem.read(tmp2, 2) != 1 || tmp2[0] != '!') { + printf("MemStream/6 failed\n"); + return false; + } + if (!mem.eof()) { + printf("MemStream/7 failed\n"); + return false; + } + + mem.seek(0); + { + BitOutputStream bos(mem); + for (unsigned i = 0; i <= HuffmanHelper::MAX_BL; ++i) { + bos.put(i, i); + } + bos.flush(); + } + mem.seek(0); + { + BitInputStream bis(mem); + for (unsigned i = 0; i <= HuffmanHelper::MAX_BL; ++i) { + if (bis.get(i) != i) { + printf("BitStreams failed\n"); + return false; + } + } + } + + unsigned char lengths[] = { + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, + 17,18,19,20,21,22,23,24,25,25 + }; + unsigned count = sizeof(lengths) / sizeof(lengths[0]); + HuffmanEncoder henc(lengths, count, false); + HuffmanDecoder hdec(lengths, count, false, 7); + if (henc.error() || hdec.error()) { + printf("HuffmanEncoder failed\n"); + return false; + } + mem.seek(0); + { + BitOutputStream bos(mem); + for (unsigned i = 0; i < count; ++i) { + henc.encode(bos, i); + } + bos.flush(); + } + mem.seek(0); + { + BitInputStream bis(mem); + for (unsigned i = 0; i < count; ++i) { + if (hdec.decode(bis) != i) { + printf("HuffmanDecoder failed\n"); + return false; + } + } + } + + uint16_t divtest16[] = {1, 3, 5, 7, 9, 11, 13, 17, 32767}; + for (int i = 0, n = sizeof(divtest16) / sizeof(divtest16[0]); i < n; ++i) { + udivider_t<16> du = build_udivider_16(divtest16[i]); + ucdivider_t<16> duc = build_ucdivider_16(divtest16[i]); + sdivider_t<16> ds = build_sdivider_16(divtest16[i]); + scdivider_t<16> dsc = build_scdivider_16(divtest16[i]); + + for (int k = 0; k < 65536; ++k) { + uint16_t c1 = divide((uint16_t)k, du); + uint16_t c2 = divide((uint16_t)k, duc); + uint16_t r = k / divtest16[i]; + if (c1 != r || c2 != r) { + printf("16bit divider/1 failed\n"); + return false; + } + + int16_t d1 = divide((int16_t)(k - 32768), ds); + int16_t d2 = divide((int16_t)(k - 32768), dsc); + int16_t s = ((int16_t)(k - 32768)) / (int16_t)divtest16[i]; + if (d1 != s || d2 != s) { + printf("16bit divider/2 failed\n"); + return false; + } + } + } + uint32_t divtest32[] = {1, 3, 5, 7, 9, 11, 13, 17, 0x7fff, 0x7fffffff}; + for (int i = 0, n = sizeof(divtest32) / sizeof(divtest32[0]); i < n; ++i) { + udivider_t<32> du = build_udivider_32(divtest32[i]); + ucdivider_t<32> duc = build_ucdivider_32(divtest32[i]); + sdivider_t<32> ds = build_sdivider_32(divtest32[i]); + scdivider_t<32> dsc = build_scdivider_32(divtest32[i]); + + for (int k = 0; k < 65536; ++k) { + uint32_t c1 = divide(((uint32_t)k)* 65536, du); + uint32_t c2 = divide(((uint32_t)k) * 65536, duc); + uint32_t r = (((uint32_t)k) * 65536) / divtest32[i]; + if (c1 != r || c2 != r) { + printf("32bit divider/1 failed\n"); + return false; + } + + int32_t d1 = divide((int32_t)(k - 32768) * 65536, ds); + int32_t d2 = divide((int32_t)(k - 32768) * 65536, dsc); + int32_t s = ((int32_t)(k - 32768)) * 65536 / (int32_t)divtest32[i]; + if (d1 != s || d2 != s) { + printf("32bit divider/2 failed\n"); + return false; + } + } + } + return true; +} diff --git a/contrib/preflate/support/support_tests.h b/contrib/preflate/support/support_tests.h new file mode 100644 index 0000000..5ce4efd --- /dev/null +++ b/contrib/preflate/support/support_tests.h @@ -0,0 +1,20 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef SUPPORT_TESTS_H +#define SUPPORT_TESTS_H + +bool support_self_tests(); + +#endif /* SUPPORT_TESTS_H */ diff --git a/contrib/preflate/support/task_pool.cpp b/contrib/preflate/support/task_pool.cpp new file mode 100644 index 0000000..cc56aea --- /dev/null +++ b/contrib/preflate/support/task_pool.cpp @@ -0,0 +1,15 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#include "task_pool.h" diff --git a/contrib/preflate/support/task_pool.h b/contrib/preflate/support/task_pool.h new file mode 100644 index 0000000..4265552 --- /dev/null +++ b/contrib/preflate/support/task_pool.h @@ -0,0 +1,48 @@ +/* Copyright 2018 Dirk Steinke + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ + +#ifndef TASK_POOL_H +#define TASK_POOL_H + +#include +#include + +class Task { +public: + virtual bool execute() = 0; +}; +class FunctionTask : public Task { +public: + FunctionTask(std::function && fun) + : _fun(fun) { + } + + bool execute() { + return _fun(); + } + +private: + std::function _fun; +}; + +class TaskPool { +public: + TaskPool(); + ~TaskPool(); + + void addTask(std::unique_ptr&& task); + void addTask(std::function && fun); +}; + +#endif /* TASK_POOL_H */ diff --git a/precomp.cpp b/precomp.cpp index 58c77ba..991e978 100644 --- a/precomp.cpp +++ b/precomp.cpp @@ -19,9 +19,9 @@ // version information #define V_MAJOR 0 #define V_MINOR 4 -#define V_MINOR2 7 +#define V_MINOR2 128 //#define V_STATE "ALPHA" -#define V_STATE "DEVELOPMENT" +#define V_STATE "EXPERIMENTAL (w/ preflate support)" #define V_MSG "USE FOR TESTING ONLY" //#define V_MSG "USE AT YOUR OWN RISK!" #ifdef UNIX @@ -95,6 +95,7 @@ using namespace std; #include "contrib/packjpg/precomp_jpg.h" #include "contrib/packmp3/precomp_mp3.h" #include "contrib/zlib/zlib.h" +#include "contrib/preflate/preflate.h" #define CHUNK 262144 // 256 KB buffersize #define DIV3CHUNK 262143 // DIV3CHUNK is a bit smaller/larger than CHUNK, so that DIV3CHUNK mod 3 = 0 @@ -306,6 +307,22 @@ bool use_swf = true; bool use_base64 = true; bool use_bzip2 = true; +enum { + D_PDF = 0, + D_ZIP = 1, + D_GZIP = 2, + D_PNG = 3, + D_MULTIPNG = 4, + D_GIF = 5, + D_JPG = 6, + D_SWF = 7, + D_BASE64 = 8, + D_BZIP2 = 9, + D_MP3 = 10, + D_RAW = 255, + D_BRUTE = 254, +}; + // Precomp DLL things #ifdef PRECOMPDLL @@ -519,7 +536,8 @@ int init(int argc, char* argv[]) { printf("Precomp v%i.%i.%i %s %s - %s version",V_MAJOR,V_MINOR,V_MINOR2,V_OS,V_BIT,V_STATE); } printf(" - %s\n",V_MSG); - printf("Free for non-commercial use - Copyright 2006-2018 by Christian Schneider\n\n"); + printf("Free for non-commercial use - Copyright 2006-2018 by Christian Schneider\n"); + printf("- experimental preflate support - Copyright 2018 by Dirk Steinke\n\n"); // init compression and memory level count bool use_zlib_level[81]; @@ -2418,51 +2436,6 @@ void denit() { delete[] best_penalty_bytes; } -int def(FILE *source, FILE *dest, int level, int windowbits, int memlevel) { - int ret, flush; - unsigned have; - z_stream strm; - - /* allocate deflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - ret = deflateInit2(&strm, level, Z_DEFLATED, windowbits, memlevel, Z_DEFAULT_STRATEGY); - if (ret != Z_OK) - return ret; - - /* compress until end of file */ - do { - print_work_sign(true); - - strm.avail_in = own_fread(in, 1, CHUNK, source); - if (ferror(source)) { - (void)deflateEnd(&strm); - return Z_ERRNO; - } - flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; - strm.next_in = in; - - do { - strm.avail_out = CHUNK; - strm.next_out = out; - - ret = deflate(&strm, flush); - - have = CHUNK - strm.avail_out; - - if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) { - (void)deflateEnd(&strm); - return Z_ERRNO; - } - } while (strm.avail_out == 0); - - } while (flush != Z_FINISH); - - (void)deflateEnd(&strm); - return Z_OK; -} - // Brute mode detects a bit less than intense mode to avoid false positives // and slowdowns, so both can be active. Also, both of them can have a level // limit, so two helper functions make things easier to handle. @@ -2491,88 +2464,6 @@ void copy_penalty_bytes(long long& rek_penalty_bytes_len, bool& use_penalty_byte } #define DEF_COMPARE_CHUNK 512 -long long def_compare(FILE *compfile, int level, int windowbits, int memlevel, long long& decompressed_bytes_used, long long decompressed_bytes_total, bool in_memory) { - int ret, flush; - unsigned have; - z_stream strm; - long long identical_bytes_compare = 0; - - long long comp_pos = 0; - decompressed_bytes_used = 0; - - /* allocate deflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - ret = deflateInit2(&strm, level, Z_DEFLATED, windowbits, memlevel, Z_DEFAULT_STRATEGY); - if (ret != Z_OK) - return -1; - - long long total_same_byte_count = 0; - long long total_same_byte_count_penalty = 0; - long long rek_same_byte_count = 0; - long long rek_same_byte_count_penalty = -1; - long long rek_penalty_bytes_len = 0; - long long local_penalty_bytes_len = 0; - bool use_penalty_bytes = false; - - unsigned char* buf_ptr = decomp_io_buf; - long long buf_pos = 0; - /* compress until end of file */ - do { - print_work_sign(true); - - if (in_memory) { - strm.avail_in = min((int)(decompressed_bytes_total - buf_pos), DEF_COMPARE_CHUNK); - strm.next_in = buf_ptr + buf_pos; - buf_pos += strm.avail_in; - flush = (buf_pos >= decompressed_bytes_total) ? Z_FINISH : Z_NO_FLUSH; - } else { - strm.avail_in = own_fread(in, 1, DEF_COMPARE_CHUNK, ftempout); - if (ferror(ftempout)) { - (void)deflateEnd(&strm); - return -1; - } - flush = feof(ftempout) ? Z_FINISH : Z_NO_FLUSH; - strm.next_in = in; - } - decompressed_bytes_used += strm.avail_in; - - do { - strm.avail_out = DEF_COMPARE_CHUNK; - strm.next_out = out; - - ret = deflate(&strm, flush); - - have = DEF_COMPARE_CHUNK - strm.avail_out; - - if (have > 0) { - if (compfile == fin) { - identical_bytes_compare = compare_file_mem_penalty(compfile, out, input_file_pos + comp_pos, have, total_same_byte_count, total_same_byte_count_penalty, rek_same_byte_count, rek_same_byte_count_penalty, rek_penalty_bytes_len, local_penalty_bytes_len, use_penalty_bytes); - } else { - identical_bytes_compare = compare_file_mem_penalty(compfile, out, comp_pos, have, total_same_byte_count, total_same_byte_count_penalty, rek_same_byte_count, rek_same_byte_count_penalty, rek_penalty_bytes_len, local_penalty_bytes_len, use_penalty_bytes); - } - } - - if (have > 0) { - if ((unsigned int)identical_bytes_compare < (have >> 1)) { - (void)deflateEnd(&strm); - copy_penalty_bytes(rek_penalty_bytes_len, use_penalty_bytes); - return rek_same_byte_count; - } - } - - comp_pos += have; - - } while (strm.avail_out == 0); - - } while (flush != Z_FINISH); - - (void)deflateEnd(&strm); - copy_penalty_bytes(rek_penalty_bytes_len, use_penalty_bytes); - return rek_same_byte_count; -} - long long def_compare_bzip2(FILE *source, FILE *compfile, int level, long long& decompressed_bytes_used) { int ret, flush; unsigned have; @@ -2646,65 +2537,6 @@ long long def_compare_bzip2(FILE *source, FILE *compfile, int level, long long& return rek_same_byte_count; } -int def_part(FILE *source, FILE *dest, int level, int windowbits, int memlevel, long long stream_size_in, long long stream_size_out) { - int ret, flush; - unsigned have; - z_stream strm; - - /* allocate deflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - ret = deflateInit2(&strm, level, Z_DEFLATED, windowbits, memlevel, Z_DEFAULT_STRATEGY); - if (ret != Z_OK) - return ret; - - long long pos_in = 0; - long long pos_out = 0; - - /* compress until end of file */ - do { - if ((stream_size_in - pos_in) > CHUNK) { - print_work_sign(true); - - strm.avail_in = own_fread(in, 1, CHUNK, source); - pos_in += CHUNK; - flush = Z_NO_FLUSH; - } else { - strm.avail_in = own_fread(in, 1, stream_size_in - pos_in, source); - flush = Z_FINISH; - } - if (ferror(source)) { - (void)deflateEnd(&strm); - return Z_ERRNO; - } - strm.next_in = in; - - do { - strm.avail_out = CHUNK; - strm.next_out = out; - - ret = deflate(&strm, flush); - - have = CHUNK - strm.avail_out; - - if ((pos_out + (signed)have) > stream_size_out) { - have = stream_size_out - pos_out; - } - pos_out += have; - - if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) { - (void)deflateEnd(&strm); - return Z_ERRNO; - } - } while (strm.avail_out == 0); - - } while (flush != Z_FINISH); - - (void)deflateEnd(&strm); - return Z_OK; -} - int def_part_bzip2(FILE *source, FILE *dest, int level, long long stream_size_in, long long stream_size_out) { int ret, flush; unsigned have; @@ -2796,162 +2628,6 @@ size_t fread_skip(unsigned char *ptr, size_t size, size_t count, FILE* stream) { return bytes_read; } -int def_part_skip(FILE *source, FILE *dest, int level, int windowbits, int memlevel, long long stream_size_in, long long stream_size_out, int bmp_width) { - - int ret, flush; - unsigned have; - z_stream strm; - - /* allocate deflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - ret = deflateInit2(&strm, level, Z_DEFLATED, windowbits, memlevel, Z_DEFAULT_STRATEGY); - if (ret != Z_OK) - return ret; - - long long pos_in = 0; - long long pos_out = 0; - frs_offset = 0; - frs_skip_len = (4 - (bmp_width % 4)); - frs_line_len = bmp_width; - - /* compress until end of file */ - do { - if ((stream_size_in - pos_in) >= CHUNK) { - strm.avail_in = fread_skip(in, 1, CHUNK, source); - pos_in += strm.avail_in; - flush = Z_NO_FLUSH; - } else { - strm.avail_in = fread_skip(in, 1, stream_size_in - pos_in, source); - pos_in += strm.avail_in; - if (pos_in >= stream_size_in) { - flush = Z_FINISH; - } else { - flush = Z_NO_FLUSH; - } - } - if (ferror(source)) { - (void)deflateEnd(&strm); - return Z_ERRNO; - } - strm.next_in = in; - - do { - strm.avail_out = CHUNK; - strm.next_out = out; - - ret = deflate(&strm, flush); - - have = CHUNK - strm.avail_out; - - if ((pos_out + (signed)have) > stream_size_out) { - have = stream_size_out - pos_out; - } - pos_out += have; - - if (own_fwrite(out, 1, have, dest) != have || ferror(dest)) { - (void)deflateEnd(&strm); - return Z_ERRNO; - } - } while (strm.avail_out == 0); - - } while (flush != Z_FINISH); - - (void)deflateEnd(&strm); - return Z_OK; -} - -int inf(FILE *source, int windowbits, long long& compressed_stream_size, long long& decompressed_stream_size, bool& in_memory) { - int ret; - unsigned have; - z_stream strm; - - /* allocate inflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = 0; - strm.next_in = Z_NULL; - ret = inflateInit2(&strm, windowbits); - if (ret != Z_OK) - return ret; - - compressed_stream_size = 0; - decompressed_stream_size = 0; - int avail_in_before; - - /* decompress until deflate stream ends or end of file */ - do { - print_work_sign(true); - - strm.avail_in = own_fread(in, 1, CHUNK, source); - avail_in_before = strm.avail_in; - - if (ferror(source)) { - (void)inflateEnd(&strm); - if (!in_memory) safe_fclose(&ftempout); - return Z_ERRNO; - } - if (strm.avail_in == 0) - break; - strm.next_in = in; - - /* run inflate() on input until output buffer not full */ - unsigned char* buf_ptr; - do { - strm.avail_out = CHUNK; - if (in_memory) { - buf_ptr = decomp_io_buf + decompressed_stream_size; - strm.next_out = buf_ptr; - } - else { - strm.next_out = out; - } - - ret = inflate(&strm, Z_NO_FLUSH); - switch (ret) { - case Z_NEED_DICT: - ret = Z_DATA_ERROR; - case Z_DATA_ERROR: - case Z_MEM_ERROR: - (void)inflateEnd(&strm); - if (!in_memory) safe_fclose(&ftempout); - return ret; - } - - compressed_stream_size += (avail_in_before - strm.avail_in); - avail_in_before = strm.avail_in; - - have = CHUNK - strm.avail_out; - - if (!in_memory) { - if (own_fwrite(out, 1, have, ftempout) != have || ferror(ftempout)) { - (void)inflateEnd(&strm); - safe_fclose(&ftempout); - return Z_ERRNO; - } - } - else { - if ((decompressed_stream_size + have + CHUNK) >= MAX_IO_BUFFER_SIZE) { - in_memory = false; - write_ftempout_if_not_present(decompressed_stream_size + have, true, true); - } - } - decompressed_stream_size += have; - - } while (strm.avail_out == 0); - - /* done when inflate() says it's done */ - } while (ret != Z_STREAM_END); - - /* clean up and return */ - (void)inflateEnd(&strm); - if (!in_memory) safe_fclose(&ftempout); - return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; - -} - int histogram[256]; bool check_inf_result(int cb_pos, int windowbits, bool use_brute_parameters = false) { @@ -3169,28 +2845,6 @@ int def_bzip2(FILE *source, FILE *dest, int level) { return BZ_OK; } -long long file_recompress(FILE* origfile, int compression_level, int windowbits, int memlevel, long long& decompressed_bytes_used, long long decompressed_bytes_total, bool in_memory) { - long long retval; - - if (!in_memory) { - ftempout = fopen(tempfile1,"rb"); - if (ftempout == NULL) { - error(ERR_TEMP_FILE_DISAPPEARED); - } - fseek(ftempout, 0, SEEK_SET); - } - - retval = def_compare(origfile, compression_level, windowbits, memlevel, decompressed_bytes_used, decompressed_bytes_total, in_memory); - - if (!in_memory) { - safe_fclose(&ftempout); - } - - if (retval < 0) return -1; - - return retval; -} - long long file_recompress_bzip2(FILE* origfile, int level, long long& decompressed_bytes_used, long long& decompressed_bytes_total) { long long retval; @@ -3324,7 +2978,7 @@ void end_uncompressed_data() { if (!uncompressed_data_in_work) return; - fout_fput64(uncompressed_length); + fout_fput_vlint(uncompressed_length); // fast copy of uncompressed data seek_64(fin, uncompressed_pos); @@ -3356,386 +3010,479 @@ void init_decompression_variables() { final_compression_found = false; } +struct recompress_deflate_result { + long long compressed_stream_size; + long long uncompressed_stream_size; + std::vector recon_data; + bool accepted; + bool uncompressed_in_memory; + bool zlib_perfect; + char zlib_comp_level; + char zlib_mem_level; + char zlib_window_bits; +}; + +void debug_deflate_detected(const recompress_deflate_result& rdres, const char* type) { + if (DEBUG_MODE) { + print_debug_percent(); + cout << "Possible zLib-Stream " << type << " found at position " << saved_input_file_pos << endl; + cout << "Compressed size: " << rdres.compressed_stream_size << endl; + cout << "Can be decompressed to " << rdres.uncompressed_stream_size << " bytes" << endl; + + if (rdres.accepted) { + if (rdres.zlib_perfect) { + cout << "Detect ZLIB parameters: comp level " << rdres.zlib_comp_level << ", mem level " << rdres.zlib_mem_level << ", " << rdres.zlib_window_bits << "window bits" << endl; + } else { + cout << "Non-ZLIB reconstruction data size: " << rdres.recon_data.size() << " bytes" << endl; + } + } + } +} +void debug_deflate_reconstruct(const recompress_deflate_result& rdres, const char* type, + const unsigned hdr_length, const uint64_t rec_length) { + if (DEBUG_MODE) { + cout << "Decompressed data - " << type << endl; + cout << "Header length: " << hdr_length << endl; + if (rdres.zlib_perfect) { + cout << "ZLIB Parameters: compression level " << rdres.zlib_comp_level + << " memory level " << rdres.zlib_mem_level + << " window bits " << rdres.zlib_window_bits << endl; + } else { + cout << "Reconstruction data size: " << rdres.recon_data.size() << endl; + } + if (rec_length > 0) { + cout << "Recursion data length: " << rec_length << endl; + } else { + cout << "Recompressed length: " << rdres.compressed_stream_size << " - decompressed length: " << rdres.uncompressed_stream_size << endl; + } + } +} + +class OwnFileInputStream : public InputStream { +public: + OwnFileInputStream(FILE* f) : _f(f), _eof(false) {} + + virtual bool eof() const { + return _eof; + } + virtual size_t read(unsigned char* buffer, const size_t size) { + size_t res = own_fread(buffer, 1, size, _f); + _eof |= res < size; + return res; + } +private: + FILE* _f; + bool _eof; +}; +class UncompressedOutStream : public OutputStream { +public: + UncompressedOutStream(bool& in_memory) : _written(0), _in_memory(in_memory) {} + ~UncompressedOutStream() { + if (!_in_memory) { + safe_fclose(&ftempout); + } + } + + virtual size_t write(const unsigned char* buffer, const size_t size) { + print_work_sign(true); + if (_in_memory) { + if (_written + size >= MAX_IO_BUFFER_SIZE) { + _in_memory = false; + write_ftempout_if_not_present(_written, true, true); + } else { + memcpy(decomp_io_buf + _written, buffer, size); + _written += size; + return size; + } + } + return own_fwrite(buffer, 1, size, ftempout); + } +private: + size_t _written; + bool& _in_memory; +}; + +recompress_deflate_result try_recompression_deflate(FILE* file) { + if (file == fin) { + seek_64(file, input_file_pos); + } else { + seek_64(file, 0); + } + + recompress_deflate_result result; + memset(&result, 0, sizeof(result)); + + OwnFileInputStream is(file); + + std::vector unpacked_output; + uint64_t compressed_stream_size = 0; + result.accepted = preflate_decode(unpacked_output, result.recon_data, + compressed_stream_size, is, []() { print_work_sign(true); }); + result.compressed_stream_size = compressed_stream_size; + result.uncompressed_stream_size = unpacked_output.size(); + { + result.uncompressed_in_memory = true; + UncompressedOutStream uos(result.uncompressed_in_memory); + uos.write(unpacked_output.data(), unpacked_output.size()); + } + return std::move(result); +} + +class OwnFileOutputStream : public OutputStream { +public: + OwnFileOutputStream(FILE* f) : _f(f) {} + + virtual size_t write(const unsigned char* buffer, const size_t size) { + return own_fwrite(buffer, 1, size, _f); + } +private: + FILE* _f; +}; + +bool try_reconstructing_deflate(FILE* fin, FILE* fout, const recompress_deflate_result& rdres) { + std::vector unpacked_output; + unpacked_output.resize(rdres.uncompressed_stream_size); + if ((int64_t)own_fread(unpacked_output.data(), 1, rdres.uncompressed_stream_size, fin) != rdres.uncompressed_stream_size) { + return false; + } + OwnFileOutputStream os(fout); + bool result = preflate_reencode(os, rdres.recon_data, unpacked_output, []() { print_work_sign(true); }); + return result; +} +bool try_reconstructing_deflate_skip(FILE* fin, FILE* fout, const recompress_deflate_result& rdres, const size_t read_part, const size_t skip_part) { + std::vector unpacked_output; + unpacked_output.resize(rdres.uncompressed_stream_size); + frs_offset = 0; + frs_skip_len = skip_part; + frs_line_len = read_part; + if ((int64_t)fread_skip(unpacked_output.data(), 1, rdres.uncompressed_stream_size, fin) != rdres.uncompressed_stream_size) { + return false; + } + OwnFileOutputStream os(fout); + return preflate_reencode(os, rdres.recon_data, unpacked_output, []() { print_work_sign(true); }); +} +class OwnFileOutputStreamMultiPNG : public OutputStream { +public: + OwnFileOutputStreamMultiPNG(FILE* f, + const size_t idat_count, + const uint32_t* idat_crcs, + const uint32_t* idat_lengths) + : _f(f), _idat_count(idat_count), _idat_crcs(idat_crcs), _idat_lengths(idat_lengths) + , _idat_idx(0), _to_read(_idat_lengths[0]) + {} + + virtual size_t write(const unsigned char* buffer_, const size_t size_) { + if (_idat_idx >= _idat_count) { + return 0; + } + size_t written = 0; + size_t size = size_; + const unsigned char* buffer = buffer_; + while (size > _to_read) { + own_fwrite(buffer, 1, _to_read, _f); + written += _to_read; + size -= _to_read; + buffer += _to_read; + ++_idat_idx; + if (_idat_idx >= _idat_count) { + return written; + } + unsigned char crc_out[4] = {_idat_crcs[_idat_idx] >> 24, _idat_crcs[_idat_idx] >> 16, _idat_crcs[_idat_idx] >> 8, _idat_crcs[_idat_idx] >> 0}; + own_fwrite(crc_out, 1, 4, _f); + _to_read = _idat_lengths[_idat_idx]; + unsigned char len_out[4] = {_to_read >> 24, _to_read >> 16, _to_read >> 8, _to_read >> 0}; + own_fwrite(len_out, 1, 4, _f); + own_fwrite("IDAT", 1, 4, _f); + } + own_fwrite(buffer, 1, size, _f); + written += size; + _to_read -= size; + return written; + } +private: + FILE* _f; + const size_t _idat_count; + const uint32_t* _idat_crcs; + const uint32_t* _idat_lengths; + size_t _idat_idx, _to_read; +}; +bool try_reconstructing_deflate_multipng(FILE* fin, FILE* fout, const recompress_deflate_result& rdres, + const size_t idat_count, const uint32_t* idat_crcs, const uint32_t* idat_lengths) { + std::vector unpacked_output; + unpacked_output.resize(rdres.uncompressed_stream_size); + if ((int64_t)own_fread(unpacked_output.data(), 1, rdres.uncompressed_stream_size, fin) != rdres.uncompressed_stream_size) { + return false; + } + OwnFileOutputStreamMultiPNG os(fout, idat_count, idat_crcs, idat_lengths); + return preflate_reencode(os, rdres.recon_data, unpacked_output, []() { print_work_sign(true); }); +} + +static uint64_t sum_compressed = 0, sum_uncompressed = 0, sum_recon = 0, sum_expansion = 0; +void debug_sums(const recompress_deflate_result& rdres) { + if (DEBUG_MODE) { + sum_compressed += rdres.compressed_stream_size; + sum_uncompressed += rdres.uncompressed_stream_size; + sum_expansion += rdres.uncompressed_stream_size - rdres.compressed_stream_size; + sum_recon += rdres.recon_data.size(); + printf("deflate sums: c %I64d, u %I64d, x %I64d, r %I64d, i %I64d, o %I64d\n", + sum_compressed, sum_uncompressed, sum_expansion, sum_recon, _ftelli64(fin), _ftelli64(fout)); + } +} +void debug_pos() { + if (DEBUG_MODE) { + printf("deflate pos: i %I64d, o %I64d\n", _ftelli64(fin), _ftelli64(fout)); + } +} void try_decompression_pdf(int windowbits, int pdf_header_length, int img_width, int img_height, int img_bpc) { init_decompression_variables(); int bmp_header_type = 0; // 0 = none, 1 = 8-bit, 2 = 24-bit - // try to decompress at current position - long long compressed_stream_size = -1; - bool in_memory; - retval = try_to_decompress(fin, windowbits, compressed_stream_size, in_memory); + // try to decompress at current position + recompress_deflate_result rdres = try_recompression_deflate(fin); - if (retval > 0) { // seems to be a zLib-Stream + if (rdres.uncompressed_stream_size > 0) { // seems to be a zLib-Stream - decompressed_streams_count++; - if (img_bpc == 8) { - decompressed_pdf_count_8_bit++; - } else { - decompressed_pdf_count++; - } + decompressed_streams_count++; + if (img_bpc == 8) { + decompressed_pdf_count_8_bit++; + } else { + decompressed_pdf_count++; + } + + debug_deflate_detected(rdres, "in PDF"); + if (rdres.accepted) { + recompressed_streams_count++; + recompressed_pdf_count++; + + non_zlib_was_used = true; + debug_sums(rdres); + + if (img_bpc == 8) { + if (best_identical_bytes_decomp == (img_width * img_height)) { + bmp_header_type = 1; if (DEBUG_MODE) { - print_debug_percent(); - cout << "Possible zLib-Stream in PDF found at position " << saved_input_file_pos << ", windowbits = " << -windowbits << endl; - cout << "Compressed size: " << compressed_stream_size << endl; - cout << "Can be decompressed to " << retval << " bytes" << endl; + printf("Image size did match (8 bit)\n"); } - for (int index = MTF.First(); index>=0; index=MTF.Next()){ - if (comp_mem_level_count[index] == -1) continue; - int comp_level = (index % 9) + 1; - int mem_level = (index / 9) + 1; + recompressed_pdf_count_8_bit++; + recompressed_pdf_count--; + } else if (best_identical_bytes_decomp == (img_width * img_height * 3)) { + bmp_header_type = 2; + if (DEBUG_MODE) { + printf("Image size did match (24 bit)\n"); + } + decompressed_pdf_count_8_bit--; + decompressed_pdf_count_24_bit++; + recompressed_pdf_count_24_bit++; + recompressed_pdf_count--; + } else { + if (DEBUG_MODE) { + printf("Image size didn't match with stream size\n"); + } + recompressed_pdf_count--; + } + } - try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size, retval, in_memory); + // end uncompressed data - if (final_compression_found){ MTF.Update(); break; } + compressed_data_found = true; + end_uncompressed_data(); + + debug_pos(); + + // write compressed data header (PDF) without 12 first bytes + // (/FlateDecode) + + unsigned char bmp_c = 0; + + if (bmp_header_type == 1) { + // 8 Bit, Bit 7,6 = 01 + bmp_c = 64; + } else if (bmp_header_type == 2) { + // 24 Bit, Bit 7,6 = 10 + bmp_c = 128; + } + + fout_fput_deflate_hdr(D_PDF, bmp_c, rdres, in_buf + cb + 12, pdf_header_length - 12, false); + fout_fput_recon_data(rdres); + + // eventually write BMP header + + if (bmp_header_type > 0) { + + int i; + + fout_fputc('B'); + fout_fputc('M'); + // BMP size in bytes + int bmp_size = ((img_width+3) & -4) * img_height; + if (bmp_header_type == 2) bmp_size *= 3; + if (bmp_header_type == 1) { + bmp_size += 54 + 1024; + } else { + bmp_size += 54; + } + fout_fput32_little_endian(bmp_size); + + for (i = 0; i < 4; i++) { + fout_fputc(0); + } + fout_fputc(54); + if (bmp_header_type == 1) { + fout_fputc(4); + } else { + fout_fputc(0); + } + fout_fputc(0); + fout_fputc(0); + fout_fputc(40); + fout_fputc(0); + fout_fputc(0); + fout_fputc(0); + + fout_fput32_little_endian(img_width); + fout_fput32_little_endian(img_height); + + fout_fputc(1); + fout_fputc(0); + + if (bmp_header_type == 1) { + fout_fputc(8); + } else { + fout_fputc(24); + } + fout_fputc(0); + + for (i = 0; i < 4; i++) { + fout_fputc(0); + } + + if (bmp_header_type == 2) img_width *= 3; + + int datasize = ((img_width+3) & -4) * img_height; + if (bmp_header_type == 2) datasize *= 3; + fout_fput32_little_endian(datasize); + + for (i = 0; i < 16; i++) { + fout_fputc(0); + } + + if (bmp_header_type == 1) { + // write BMP palette + for (i = 0; i < 1024; i++) { + fout_fputc(0); + } + } + } + + // write decompressed data + + if ((bmp_header_type == 0) || ((img_width % 4) == 0)) { + fout_fput_uncompressed(rdres); + } else { + if (!rdres.uncompressed_in_memory) { + ftempout = fopen(tempfile1,"rb"); + if (ftempout == NULL) { + error(ERR_TEMP_FILE_DISAPPEARED); } - if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) { - recompressed_streams_count++; - recompressed_pdf_count++; + fseek(ftempout, 0, SEEK_SET); + } - if (DEBUG_MODE) { - cout << "Best match with level combination " << best_compression << best_mem_level << ": " << best_identical_bytes << " bytes, decompressed to " << best_identical_bytes_decomp << " bytes" << endl; - } - - if (img_bpc == 8) { - if (best_identical_bytes_decomp == (img_width * img_height)) { - bmp_header_type = 1; - if (DEBUG_MODE) { - printf("Image size did match (8 bit)\n"); - } - recompressed_pdf_count_8_bit++; - recompressed_pdf_count--; - } else if (best_identical_bytes_decomp == (img_width * img_height * 3)) { - bmp_header_type = 2; - if (DEBUG_MODE) { - printf("Image size did match (24 bit)\n"); - } - decompressed_pdf_count_8_bit--; - decompressed_pdf_count_24_bit++; - recompressed_pdf_count_24_bit++; - recompressed_pdf_count--; - } else { - if (DEBUG_MODE) { - printf("Image size didn't match with stream size\n"); - } - recompressed_pdf_count--; - } - } - - if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) { - if (fast_mode) { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - for (int i = 0; i < 81; i++) { - if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) { - comp_mem_level_count[i] = -1; - } - } - anything_was_used = true; - } else { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - anything_was_used = true; - } - } - - // end uncompressed data - - compressed_data_found = true; - end_uncompressed_data(); - - // write compressed data header (PDF) without 12 first bytes - // (/FlateDecode) - - unsigned char bmp_c = 0; - - if (bmp_header_type == 1) { - // 8 Bit, Bit 7,6 = 01 - bmp_c = 64; - } else if (bmp_header_type == 2) { - // 24 Bit, Bit 7,6 = 10 - bmp_c = 128; - } - - if (best_penalty_bytes_len == 0) { - fout_fputc(1 + (best_compression << 2) + bmp_c); - } else { - fout_fputc(1 + 2 + (best_compression << 2) + bmp_c); - } - fout_fputc(0); // PDF - fout_fputc((((-windowbits) - 8) << 4) + best_mem_level); - - pdf_header_length -= 12; - - fout_fput24(pdf_header_length); - - own_fwrite(in_buf + cb + 12, 1, pdf_header_length, fout); - - // store penalty bytes, if any - if (best_penalty_bytes_len != 0) { - if (DEBUG_MODE) { - printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); - } - fout_fput32(best_penalty_bytes_len); - for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { - fout_fputc(best_penalty_bytes[pbc]); - } - } - - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); - - // eventually write BMP header - - if (bmp_header_type > 0) { - - int i; - - fout_fputc('B'); - fout_fputc('M'); - // BMP size in bytes - int bmp_size = ((img_width+3) & -4) * img_height; - if (bmp_header_type == 2) bmp_size *= 3; - if (bmp_header_type == 1) { - bmp_size += 54 + 1024; - } else { - bmp_size += 54; - } - fout_fput32_little_endian(bmp_size); - - for (i = 0; i < 4; i++) { - fout_fputc(0); - } - fout_fputc(54); - if (bmp_header_type == 1) { - fout_fputc(4); - } else { - fout_fputc(0); - } - fout_fputc(0); - fout_fputc(0); - fout_fputc(40); - fout_fputc(0); - fout_fputc(0); - fout_fputc(0); - - fout_fput32_little_endian(img_width); - fout_fput32_little_endian(img_height); - - fout_fputc(1); - fout_fputc(0); - - if (bmp_header_type == 1) { - fout_fputc(8); - } else { - fout_fputc(24); - } - fout_fputc(0); - - for (i = 0; i < 4; i++) { - fout_fputc(0); - } - - if (bmp_header_type == 2) img_width *= 3; - - int datasize = ((img_width+3) & -4) * img_height; - if (bmp_header_type == 2) datasize *= 3; - fout_fput32_little_endian(datasize); - - for (i = 0; i < 16; i++) { - fout_fputc(0); - } - - if (bmp_header_type == 1) { - // write BMP palette - for (i = 0; i < 1024; i++) { - fout_fputc(0); - } - } - } - - // write decompressed data - - if ((bmp_header_type == 0) || ((img_width % 4) == 0)) { - write_decompressed_data_io_buf(best_identical_bytes_decomp, in_memory); - } else { - if (!in_memory) { - ftempout = fopen(tempfile1,"rb"); - if (ftempout == NULL) { - error(ERR_TEMP_FILE_DISAPPEARED); - } - - fseek(ftempout, 0, SEEK_SET); - } - - unsigned char* buf_ptr = decomp_io_buf; - for (int y = 0; y < img_height; y++) { - - if (in_memory) { - fast_copy(buf_ptr, fout, img_width); - buf_ptr += img_width; - } else { - fast_copy(ftempout, fout, img_width); - } - - for (int i = 0; i < (4 - (img_width % 4)); i++) { - fout_fputc(0); - } - - } - - safe_fclose(&ftempout); - } - - // start new uncompressed data - - // set input file pointer after recompressed data - input_file_pos += best_identical_bytes - 1; - cb += best_identical_bytes - 1; + unsigned char* buf_ptr = decomp_io_buf; + for (int y = 0; y < img_height; y++) { + if (rdres.uncompressed_in_memory) { + fast_copy(buf_ptr, fout, img_width); + buf_ptr += img_width; } else { - if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2); - if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); - if (DEBUG_MODE) { - printf("No matches\n"); - } + fast_copy(ftempout, fout, img_width); + } + + for (int i = 0; i < (4 - (img_width % 4)); i++) { + fout_fputc(0); } } + safe_fclose(&ftempout); + } + // start new uncompressed data + debug_pos(); + + // set input file pointer after recompressed data + input_file_pos += rdres.compressed_stream_size - 1; + cb += rdres.compressed_stream_size - 1; + + } else { + if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2); + if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); + if (DEBUG_MODE) { + printf("No matches\n"); + } + } + } +} + +void try_decompression_deflate_type(unsigned& dcounter, unsigned& rcounter, + const unsigned char type, + const unsigned char* hdr, const int hdr_length, const bool inc_last, + const char* debugname) { + init_decompression_variables(); + + // try to decompress at current position + recompress_deflate_result rdres = try_recompression_deflate(fin); + + if (rdres.uncompressed_stream_size > 0) { // seems to be a zLib-Stream + decompressed_streams_count++; + dcounter++; + + debug_deflate_detected(rdres, debugname); + + if (rdres.accepted) { + recompressed_streams_count++; + rcounter++; + + non_zlib_was_used = true; + + debug_sums(rdres); + + // end uncompressed data + + compressed_data_found = true; + end_uncompressed_data(); + + debug_pos(); + + // check recursion + recursion_result r = recursion_write_file_and_compress(rdres); + + // write compressed data header without first bytes + fout_fput_deflate_rec(type, rdres, hdr, hdr_length, inc_last, r); + + debug_pos(); + + // set input file pointer after recompressed data + input_file_pos += rdres.compressed_stream_size - 1; + cb += rdres.compressed_stream_size - 1; + + } else { + if (type == D_SWF && intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2); + if (type != D_BRUTE && brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); + if (DEBUG_MODE) { + printf("No matches\n"); + } + } + + } } void try_decompression_zip(int zip_header_length) { - init_decompression_variables(); - - int windowbits; - - // try to decompress at current position - long long compressed_stream_size = -1; - bool in_memory; - retval = try_to_decompress(fin, -15, compressed_stream_size, in_memory); - - if (retval > 0) { // seems to be a zLib-Stream - - decompressed_streams_count++; - decompressed_zip_count++; - - if (DEBUG_MODE) { - print_debug_percent(); - cout << "Possible zLib-Stream in ZIP found at position " << saved_input_file_pos << endl; - cout << "Compressed size: " << compressed_stream_size << endl; - cout << "Can be decompressed to " << retval << " bytes" << endl; - } - - for (windowbits = -15; windowbits < -7; windowbits++) { - for (int index = MTF.First(); index>=0; index=MTF.Next()){ - if (comp_mem_level_count[index] == -1) continue; - int comp_level = (index % 9) + 1; - int mem_level = (index / 9) + 1; - - try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size, retval, in_memory); - - if (final_compression_found){ MTF.Update(); break; } - } - if (final_compression_found) break; - } - - if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) { - recompressed_streams_count++; - recompressed_zip_count++; - - windowbits = best_windowbits; - if (DEBUG_MODE) { - cout << "Best match with level combination " << best_compression << best_mem_level << ", windowbits = " << -windowbits << ": " << best_identical_bytes << " bytes, decompressed to " << best_identical_bytes_decomp << " bytes" << endl; - } - - if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) { - if (fast_mode) { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - for (int i = 0; i < 81; i++) { - if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) { - comp_mem_level_count[i] = -1; - } - } - anything_was_used = true; - } else { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - anything_was_used = true; - } - } - - // end uncompressed data - - compressed_data_found = true; - end_uncompressed_data(); - - // check recursion - write_ftempout_if_not_present(best_identical_bytes_decomp, in_memory); - recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp); - - // write compressed data header (ZIP) without 4 first bytes (PK..) - - int header_byte = 1 + (best_compression << 2); - if (best_penalty_bytes_len != 0) { - header_byte += 2; - } - if (r.success) { - header_byte += 128; - } - fout_fputc(header_byte); - fout_fputc(1); // ZIP - fout_fputc((((-windowbits) - 8) << 4) + best_mem_level); - - zip_header_length -= 4; - - fout_fput24(zip_header_length); - - own_fwrite(in_buf + cb + 4, 1, zip_header_length, fout); - - // store penalty bytes, if any - if (best_penalty_bytes_len != 0) { - if (DEBUG_MODE) { - printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); - } - fout_fput32(best_penalty_bytes_len); - for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { - fout_fputc(best_penalty_bytes[pbc]); - } - } - - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); - - if (r.success) { - fout_fput64(r.file_length); - } - - // write decompressed data - if (r.success) { - write_decompressed_data(r.file_length, r.file_name); - remove(r.file_name); - delete[] r.file_name; - } else { - write_decompressed_data_io_buf(best_identical_bytes_decomp, in_memory); - } - - // set input file pointer after recompressed data - input_file_pos += best_identical_bytes - 1; - cb += best_identical_bytes - 1; - - } else { - if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); - if (DEBUG_MODE) { - printf("No matches\n"); - } - } - - } + try_decompression_deflate_type(decompressed_zip_count, recompressed_zip_count, + D_ZIP, in_buf + cb + 4, zip_header_length - 4, false, + "in ZIP"); } void show_used_levels() { @@ -3900,7 +3647,9 @@ bool compress_file(float min_percent, float max_percent) { printf("extra field length: %i\n", extra_field_length); } - if ((filename_length + extra_field_length) <= CHECKBUF_SIZE) { + if ((filename_length + extra_field_length) <= CHECKBUF_SIZE + && compressed_size > 0 && compressed_size != uncompressed_size + && in_buf[cb + 8] == 8 && in_buf[cb + 9] == 0) { int header_length = 30 + filename_length + extra_field_length; @@ -4240,7 +3989,7 @@ bool compress_file(float min_percent, float max_percent) { idat_lengths[0] += 2; input_file_pos += 6; - try_decompression_png_multi(-windowbits); + try_decompression_png_multi(fpng, -windowbits); cb += 6; safe_fclose(&fpng); @@ -4724,7 +4473,7 @@ while (fin_pos < fin_length) { unsigned char header1 = fin_fgetc(); if (header1 == 0) { // uncompressed data long long uncompressed_data_length; - uncompressed_data_length = fin_fget64(); + uncompressed_data_length = fin_fget_vlint(); if (uncompressed_data_length == 0) break; // end of PCF file, used by bZip2 compress-on-the-fly @@ -4738,59 +4487,23 @@ while (fin_pos < fin_length) { unsigned char headertype = fin_fgetc(); - if (headertype == 0) { // PDF recompression - if (DEBUG_MODE) { - printf("Decompressed data - PDF\n"); - } - - unsigned char header2 = fin_fgetc(); - - bool penalty_bytes_stored = ((header1 & 2) == 2); - int compression_level = (header1 >> 2) & 15; - int bmp_c = (header1 >> 6); - int windowbits = -(((header2 >> 4) & 15) + 8); - int memlevel = header2 & 15; - - if (DEBUG_MODE) { - printf("Compression level: %i\n", compression_level); - printf("Window size: %i\n", -windowbits); - printf("Memory level: %i\n", memlevel); - if (bmp_c == 1) printf("Skipping BMP header (8-Bit)\n"); - if (bmp_c == 2) printf("Skipping BMP header (24-Bit)\n"); - } - - int pdf_header_length; - pdf_header_length = (fin_fgetc() << 16); - pdf_header_length += (fin_fgetc() << 8); - pdf_header_length += fin_fgetc(); - + switch (headertype) { + case D_PDF: { // PDF recompression + recompress_deflate_result rdres; + unsigned hdr_length; // restore PDF header fprintf(fout, "/FlateDecode"); + fin_fget_deflate_hdr(rdres, header1, in, hdr_length, false); + fin_fget_recon_data(rdres); + int bmp_c = (header1 >> 6); - own_fread(in, 1, pdf_header_length, fin); - own_fwrite(in, 1, pdf_header_length, fout); - - // read penalty bytes - if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); - own_fread(penalty_bytes, 1, penalty_bytes_len, fin); - } - - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); - + debug_deflate_reconstruct(rdres, "PDF", hdr_length, 0); if (DEBUG_MODE) { - cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; + if (bmp_c == 1) printf("Skipping BMP header (8-Bit)\n"); + if (bmp_c == 2) printf("Skipping BMP header (24-Bit)\n"); } - // keep file position for penalty bytes - long long old_fout_pos = tell_64(fout); - // read BMP header - int bmp_width = 0; switch (bmp_c) { @@ -4806,457 +4519,117 @@ while (fin_pos < fin_length) { if (bmp_c == 2) bmp_width *= 3; } + uint64_t read_part, skip_part; if ((bmp_c == 0) || ((bmp_width % 4) == 0)) { // recompress directly to fout - retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - if (retval != Z_OK) { - printf("Error recompressing data!"); - cout << "retval = " << retval << endl; - exit(0); - } + read_part = rdres.uncompressed_stream_size; + skip_part = 0; } else { // lines aligned to 4 byte, skip those bytes // recompress directly to fout, but skipping bytes - - retval = def_part_skip(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length, bmp_width); - - if (retval != Z_OK) { - printf("Error recompressing data!"); - cout << "retval = " << retval << endl; - exit(0); - } - + read_part = bmp_width; + skip_part = (-bmp_width) & 3; } - - if (penalty_bytes_stored) { - fflush(fout); - - long long fsave_fout_pos = tell_64(fout); - - int pb_pos = 0; - for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) { - pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24; - pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16; - pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8; - pb_pos += (unsigned char)penalty_bytes[pbc + 3]; - - seek_64(fout, old_fout_pos + pb_pos); - own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout); - } - - seek_64(fout, fsave_fout_pos); + if (!try_reconstructing_deflate_skip(fin, fout, rdres, read_part, skip_part)) { + printf("Error recompressing data!"); + exit(0); } - - } else if (headertype == 1) { // ZIP recompression - - if (DEBUG_MODE) { - printf("Decompressed data - ZIP\n"); - } - - unsigned char header2 = fin_fgetc(); - - bool penalty_bytes_stored = ((header1 & 2) == 2); - bool recursion_used = ((header1 & 128) == 128); - int compression_level = (header1 >> 2) & 15; - int windowbits = -(((header2 >> 4) & 15) + 8); - int memlevel = header2 & 15; - - if (DEBUG_MODE) { - printf("Compression level: %i\n", compression_level); - printf("Window size: %i\n", -windowbits); - printf("Memory level: %i\n", memlevel); - } - - int zip_header_length; - zip_header_length = (fin_fgetc() << 16); - zip_header_length += (fin_fgetc() << 8); - zip_header_length += fin_fgetc(); - - if (DEBUG_MODE) { - printf("ZIP header length: %i\n", zip_header_length); - } - + break; + } + case D_ZIP: { // ZIP recompression + recompress_deflate_result rdres; + unsigned hdr_length; + int64_t recursion_data_length; fputc('P', fout); fputc('K', fout); fputc(3, fout); fputc(4, fout); + bool ok = fin_fget_deflate_rec(rdres, header1, in, hdr_length, false, recursion_data_length); - own_fread(in, 1, zip_header_length, fin); - own_fwrite(in, 1, zip_header_length, fout); + debug_deflate_reconstruct(rdres, "ZIP", hdr_length, recursion_data_length); - // read penalty bytes - if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); - own_fread(penalty_bytes, 1, penalty_bytes_len, fin); - } - - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); - - long long recursion_data_length = 0; - if (recursion_used) { - recursion_data_length = fin_fget64(); - } - - if (DEBUG_MODE) { - if (recursion_used) { - cout << "Recursion data length: " << recursion_data_length << endl; - } else { - cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; - } - } - - long long old_fout_pos = tell_64(fout); - - if (recursion_used) { - recursion_result r = recursion_decompress(recursion_data_length); - retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - safe_fclose(&r.frecurse); - remove(r.file_name); - delete[] r.file_name; - } else { - retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - } - - if (retval != Z_OK) { + if (!ok) { printf("Error recompressing data!"); - cout << "retval = " << retval << endl; exit(0); } - - if (penalty_bytes_stored) { - fflush(fout); - - long long fsave_fout_pos = tell_64(fout); - int pb_pos = 0; - for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) { - pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24; - pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16; - pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8; - pb_pos += (unsigned char)penalty_bytes[pbc + 3]; - - seek_64(fout, old_fout_pos + pb_pos); - own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout); - - } - - seek_64(fout, fsave_fout_pos); - } - - } else if (headertype == 2) { // GZip recompression - - if (DEBUG_MODE) { - printf("Decompressed data - GZip\n"); - } - - unsigned char header2 = fin_fgetc(); - - bool penalty_bytes_stored = ((header1 & 2) == 2); - bool recursion_used = ((header1 & 128) == 128); - int compression_level = (header1 >> 2) & 15; - int windowbits = -(((header2 >> 4) & 15) + 8); - int memlevel = header2 & 15; - - if (DEBUG_MODE) { - printf("Compression level: %i\n", compression_level); - printf("Window size: %i\n", -windowbits); - printf("Memory level: %i\n", memlevel); - } - - int gzip_header_length; - gzip_header_length = (fin_fgetc() << 16); - gzip_header_length += (fin_fgetc() << 8); - gzip_header_length += fin_fgetc(); - - if (DEBUG_MODE) { - printf("GZip header length: %i\n", gzip_header_length); - } - + break; + } + case D_GZIP: { // GZip recompression + recompress_deflate_result rdres; + unsigned hdr_length; + int64_t recursion_data_length; fputc(31, fout); fputc(139, fout); + bool ok = fin_fget_deflate_rec(rdres, header1, in, hdr_length, false, recursion_data_length); - own_fread(in, 1, gzip_header_length, fin); - own_fwrite(in, 1, gzip_header_length, fout); + debug_deflate_reconstruct(rdres, "GZIP", hdr_length, recursion_data_length); - // read penalty bytes - if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); - own_fread(penalty_bytes, 1, penalty_bytes_len, fin); - } - - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); - - long long recursion_data_length = 0; - if (recursion_used) { - recursion_data_length = fin_fget64(); - } - - if (DEBUG_MODE) { - if (recursion_used) { - cout << "Recursion data length: " << recursion_data_length << endl; - } else { - cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; - } - } - - long long old_fout_pos = tell_64(fout); - - if (recursion_used) { - recursion_result r = recursion_decompress(recursion_data_length); - retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - safe_fclose(&r.frecurse); - remove(r.file_name); - delete[] r.file_name; - } else { - retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - } - - if (retval != Z_OK) { + if (!ok) { printf("Error recompressing data!"); - cout << "retval = " << retval << endl; exit(0); } - - if (penalty_bytes_stored) { - fflush(fout); - - long long fsave_fout_pos = tell_64(fout); - int pb_pos = 0; - for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) { - pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24; - pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16; - pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8; - pb_pos += (unsigned char)penalty_bytes[pbc + 3]; - - seek_64(fout, old_fout_pos + pb_pos); - own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout); - } - - seek_64(fout, fsave_fout_pos); - } - - } else if (headertype == 3) { // PNG recompression - - if (DEBUG_MODE) { - printf("Decompressed data - PNG\n"); - } - - unsigned char header2 = fin_fgetc(); - - bool penalty_bytes_stored = ((header1 & 2) == 2); - int compression_level = (header1 >> 2) & 15; - int windowbits = -(((header2 >> 4) & 15) + 8); - int memlevel = header2 & 15; - - if (DEBUG_MODE) { - printf("Compression level: %i\n", compression_level); - printf("Window size: %i\n", -windowbits); - printf("Memory level: %i\n", memlevel); - } - + break; + } + case D_PNG: { // PNG recompression + recompress_deflate_result rdres; + unsigned hdr_length; // restore IDAT fprintf(fout, "IDAT"); - // restore zLib header (decrease by 1) - own_fread(in, 1, 2, fin); - unsigned char decchar = *(in + 1) - 1; - own_fwrite(in, 1, 1, fout); - fputc(decchar, fout); + fin_fget_deflate_hdr(rdres, header1, in, hdr_length, true); + fin_fget_recon_data(rdres); + debug_sums(rdres); + debug_pos(); - // read penalty bytes - if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); - own_fread(penalty_bytes, 1, penalty_bytes_len, fin); - } + debug_deflate_reconstruct(rdres, "PNG", hdr_length, 0); - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); - - if (DEBUG_MODE) { - cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; - } - - long long old_fout_pos = tell_64(fout); - - retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - - if (retval != Z_OK) { + if (!try_reconstructing_deflate(fin, fout, rdres)) { printf("Error recompressing data!"); - cout << "retval = " << retval << endl; exit(0); } - - if (penalty_bytes_stored) { - fflush(fout); - - long long fsave_fout_pos = tell_64(fout); - - int pb_pos = 0; - for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) { - pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24; - pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16; - pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8; - pb_pos += (unsigned char)penalty_bytes[pbc + 3]; - - seek_64(fout, old_fout_pos + pb_pos); - own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout); - } - - seek_64(fout, fsave_fout_pos); - } - - } else if (headertype == 4) { // PNG multi recompression - - if (DEBUG_MODE) { - printf("Decompressed data - PNG multi\n"); - } - - unsigned char header2 = fin_fgetc(); - - bool penalty_bytes_stored = ((header1 & 2) == 2); - int compression_level = (header1 >> 2) & 15; - int windowbits = -(((header2 >> 4) & 15) + 8); - int memlevel = header2 & 15; - - if (DEBUG_MODE) { - printf("Compression level: %i\n", compression_level); - printf("Window size: %i\n", -windowbits); - printf("Memory level: %i\n", memlevel); - } - + debug_pos(); + break; + } + case D_MULTIPNG: { // PNG multi recompression + recompress_deflate_result rdres; + unsigned hdr_length; // restore first IDAT fprintf(fout, "IDAT"); - - // restore zLib header (decrease by 1) - own_fread(in, 1, 2, fin); - unsigned char decchar = *(in + 1) - 1; - own_fwrite(in, 1, 1, fout); - fputc(decchar, fout); + + fin_fget_deflate_hdr(rdres, header1, in, hdr_length, true); // get IDAT count - own_fread(in, 1, 2, fin); - idat_count = (in[0] << 8) + in[1]; - idat_count++; + idat_count = fin_fget_vlint() + 1; idat_crcs = (unsigned int*)(realloc(idat_crcs, idat_count * sizeof(unsigned int))); idat_lengths = (unsigned int*)(realloc(idat_lengths, idat_count * sizeof(unsigned int))); // get first IDAT length - own_fread(in, 1, 4, fin); - idat_lengths[0] = (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3]; - idat_lengths[0] -= 2; // zLib header length + idat_lengths[0] = fin_fget_vlint() - 2; // zLib header length // get IDAT chunk lengths and CRCs for (int i = 1; i < idat_count; i++) { - own_fread(in, 1, 4, fin); - idat_crcs[i] = (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3]; - own_fread(in, 1, 4, fin); - idat_lengths[i] = (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3]; + idat_crcs[i] = fin_fget32(); + idat_lengths[i] = fin_fget_vlint(); } - // read penalty bytes - if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); - own_fread(penalty_bytes, 1, penalty_bytes_len, fin); - } + fin_fget_recon_data(rdres); + debug_sums(rdres); + debug_pos(); - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); + debug_deflate_reconstruct(rdres, "PNG multi", hdr_length, 0); - if (DEBUG_MODE) { - cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; - } - - remove(tempfile1); - ftempout = tryOpen(tempfile1,"wb"); - - fast_copy(fin, ftempout, decompressed_data_length); - - safe_fclose(&ftempout); - - remove(tempfile2); - - ftempout = tryOpen(tempfile1,"rb"); - frecomp = tryOpen(tempfile2,"wb"); - - long long old_frecomp_pos = tell_64(frecomp); - - // recompress data - retval = def(ftempout, frecomp, compression_level, windowbits, memlevel); - if ((!penalty_bytes_stored) || (retval != Z_OK)) safe_fclose(&frecomp); - safe_fclose(&ftempout); - - if (retval != Z_OK) { + if (!try_reconstructing_deflate_multipng(fin, fout, rdres, idat_count, idat_crcs, idat_lengths)) { printf("Error recompressing data!"); - cout << "retval = " << retval << endl; exit(0); } - - if (penalty_bytes_stored) { - fflush(frecomp); - - int pb_pos = 0; - for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) { - pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24; - pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16; - pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8; - pb_pos += (unsigned char)penalty_bytes[pbc + 3]; - - seek_64(frecomp, old_frecomp_pos + pb_pos); - own_fwrite(penalty_bytes + pbc + 4, 1, 1, frecomp); - } - - safe_fclose(&frecomp); - } - - frecomp = tryOpen(tempfile2,"rb"); - - long long remaining_bytes = recompressed_data_length; - unsigned int act_idat_chunk = 0; - for (;;) { - if ((remaining_bytes + 2) > (int)idat_lengths[act_idat_chunk]) { - fast_copy(frecomp, fout, idat_lengths[act_idat_chunk]); - remaining_bytes -= idat_lengths[act_idat_chunk]; - - fputc((idat_crcs[act_idat_chunk+1] >> 24) % 256, fout); - fputc((idat_crcs[act_idat_chunk+1] >> 16) % 256, fout); - fputc((idat_crcs[act_idat_chunk+1] >> 8) % 256, fout); - fputc(idat_crcs[act_idat_chunk+1] % 256, fout); - fputc((idat_lengths[act_idat_chunk+1] >> 24) % 256, fout); - fputc((idat_lengths[act_idat_chunk+1] >> 16) % 256, fout); - fputc((idat_lengths[act_idat_chunk+1] >> 8) % 256, fout); - fputc(idat_lengths[act_idat_chunk+1] % 256, fout); - fprintf(fout, "IDAT"); - } else { - fast_copy(frecomp, fout, remaining_bytes); - break; - } - act_idat_chunk++; - } - - safe_fclose(&frecomp); - - remove(tempfile2); - remove(tempfile1); - + debug_pos(); free(idat_lengths); idat_lengths = NULL; free(idat_crcs); idat_crcs = NULL; - - } else if (headertype == 5) { // GIF recompression + break; + } + case D_GIF: { // GIF recompression if (DEBUG_MODE) { printf("Decompressed data - GIF\n"); @@ -5271,10 +4644,7 @@ while (fin_pos < fin_length) { GifDiffStruct gDiff; // read diff bytes - gDiff.GIFDiffIndex = (fin_fgetc() << 24); - gDiff.GIFDiffIndex += (fin_fgetc() << 16); - gDiff.GIFDiffIndex += (fin_fgetc() << 8); - gDiff.GIFDiffIndex += fin_fgetc(); + gDiff.GIFDiffIndex = fin_fget_vlint(); gDiff.GIFDiff = (unsigned char*)malloc(gDiff.GIFDiffIndex * sizeof(unsigned char)); own_fread(gDiff.GIFDiff, 1, gDiff.GIFDiffIndex, fin); if (DEBUG_MODE) { @@ -5286,15 +4656,12 @@ while (fin_pos < fin_length) { // read penalty bytes if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); + penalty_bytes_len = fin_fget_vlint(); own_fread(penalty_bytes, 1, penalty_bytes_len, fin); } - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); + long long recompressed_data_length = fin_fget_vlint(); + long long decompressed_data_length = fin_fget_vlint(); if (DEBUG_MODE) { cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; @@ -5359,8 +4726,9 @@ while (fin_pos < fin_length) { } GifDiffFree(&gDiff); - - } else if (headertype == 6) { // JPG recompression + break; + } + case D_JPG: { // JPG recompression if (DEBUG_MODE) { printf("Decompressed data - JPG\n"); @@ -5368,8 +4736,8 @@ while (fin_pos < fin_length) { bool mjpg_dht_used = ((header1 & 4) == 4); - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); + long long recompressed_data_length = fin_fget_vlint(); + long long decompressed_data_length = fin_fget_vlint(); if (DEBUG_MODE) { cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; @@ -5478,107 +4846,26 @@ while (fin_pos < fin_length) { remove(tempfile2); remove(tempfile1); } - - } else if (headertype == 7) { // SWF recompression - - if (DEBUG_MODE) { - printf("Decompressed data - SWF\n"); - } - - unsigned char header2 = fin_fgetc(); - - bool penalty_bytes_stored = ((header1 & 2) == 2); - bool recursion_used = ((header1 & 128) == 128); - int compression_level = (header1 >> 2) & 15; - int windowbits = -(((header2 >> 4) & 15) + 8); - int memlevel = header2 & 15; - - if (DEBUG_MODE) { - printf("Compression level: %i\n", compression_level); - printf("Window size: %i\n", -windowbits); - printf("Memory level: %i\n", memlevel); - } - + break; + } + case D_SWF: { // SWF recompression + recompress_deflate_result rdres; + unsigned hdr_length; + int64_t recursion_data_length; fputc('C', fout); fputc('W', fout); fputc('S', fout); - // get Flash version - char c = fin_fgetc(); - fputc(c, fout); - // get length from SWF header - for (int i = 0; i < 4; i++) { - c = fin_fgetc(); - fputc(c, fout); - } + bool ok = fin_fget_deflate_rec(rdres, header1, in, hdr_length, true, recursion_data_length); - // restore zLib header (decrease by 1) - own_fread(in, 1, 2, fin); - unsigned char decchar = *(in + 1) - 1; - own_fwrite(in, 1, 1, fout); - fputc(decchar, fout); + debug_deflate_reconstruct(rdres, "SWF", hdr_length, recursion_data_length); - // read penalty bytes - if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); - own_fread(penalty_bytes, 1, penalty_bytes_len, fin); - } - - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); - - long long recursion_data_length = 0; - if (recursion_used) { - recursion_data_length = fin_fget64(); - } - - if (DEBUG_MODE) { - if (recursion_used) { - cout << "Recursion data length: " << recursion_data_length << endl; - } else { - cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; - } - } - - long long old_fout_pos = tell_64(fout); - - if (recursion_used) { - recursion_result r = recursion_decompress(recursion_data_length); - retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - safe_fclose(&r.frecurse); - remove(r.file_name); - delete[] r.file_name; - } else { - retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - } - - if (retval != Z_OK) { + if (!ok) { printf("Error recompressing data!"); - cout << "retval = " << retval << endl; exit(0); } - - if (penalty_bytes_stored) { - fflush(fout); - - long long fsave_fout_pos = tell_64(fout); - int pb_pos = 0; - for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) { - pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24; - pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16; - pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8; - pb_pos += (unsigned char)penalty_bytes[pbc + 3]; - - seek_64(fout, old_fout_pos + pb_pos); - own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout); - } - - seek_64(fout, fsave_fout_pos); - } - - } else if (headertype == 8) { // Base64 recompression + break; + } + case D_BASE64: { // Base64 recompression if (DEBUG_MODE) { printf("Decompressed data - Base64\n"); @@ -5588,20 +4875,17 @@ while (fin_pos < fin_length) { bool recursion_used = ((header1 & 128) == 128); // restore Base64 "header" - int base64_header_length; - base64_header_length = (fin_fgetc() << 8); - base64_header_length += fin_fgetc(); + int base64_header_length = fin_fget_vlint(); if (DEBUG_MODE) { - printf("Base64 header length: %i\n", base64_header_length); + printf("Base64 header length: %i\n", base64_header_length); } own_fread(in, 1, base64_header_length, fin); fputc(*(in) + 1, fout); // first char was decreased own_fwrite(in + 1, 1, base64_header_length - 1, fout); // read line length list - int line_count = fin_fgetc() << 8; - line_count += fin_fgetc(); + int line_count = fin_fget_vlint(); unsigned int* base64_line_len = new unsigned int[line_count]; @@ -5617,12 +4901,12 @@ while (fin_pos < fin_length) { if (line_case == 1) base64_line_len[line_count - 1] = fin_fgetc(); } - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); + long long recompressed_data_length = fin_fget_vlint(); + long long decompressed_data_length = fin_fget_vlint(); long long recursion_data_length = 0; if (recursion_used) { - recursion_data_length = fin_fget64(); + recursion_data_length = fin_fget_vlint(); } if (DEBUG_MODE) { @@ -5646,7 +4930,9 @@ while (fin_pos < fin_length) { } delete[] base64_line_len; - } else if (headertype == 9) { // bZip2 recompression + break; + } + case D_BZIP2: { // bZip2 recompression if (DEBUG_MODE) { printf("Decompressed data - bZip2\n"); @@ -5664,19 +4950,16 @@ while (fin_pos < fin_length) { // read penalty bytes if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); + penalty_bytes_len = fin_fget_vlint(); own_fread(penalty_bytes, 1, penalty_bytes_len, fin); } - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); + long long recompressed_data_length = fin_fget_vlint(); + long long decompressed_data_length = fin_fget_vlint(); long long recursion_data_length = 0; if (recursion_used) { - recursion_data_length = fin_fget64(); + recursion_data_length = fin_fget_vlint(); } if (DEBUG_MODE) { @@ -5722,14 +5005,16 @@ while (fin_pos < fin_length) { seek_64(fout, fsave_fout_pos); } - } else if (headertype == 10) { // MP3 recompression + break; + } + case D_MP3: { // MP3 recompression if (DEBUG_MODE) { printf("Decompressed data - MP3\n"); } - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); + long long recompressed_data_length = fin_fget_vlint(); + long long decompressed_data_length = fin_fget_vlint(); if (DEBUG_MODE) { cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; @@ -5784,175 +5069,37 @@ while (fin_pos < fin_length) { remove(tempfile2); remove(tempfile1); } - } else if (headertype == 254) { // brute mode recompression + break; + } + case D_BRUTE: { // brute mode recompression + recompress_deflate_result rdres; + unsigned hdr_length; + int64_t recursion_data_length; + bool ok = fin_fget_deflate_rec(rdres, header1, in, hdr_length, false, recursion_data_length); - if (DEBUG_MODE) { - printf("Decompressed data - brute mode\n"); - } + debug_deflate_reconstruct(rdres, "brute mode", hdr_length, recursion_data_length); - unsigned char header2 = fin_fgetc(); - - bool penalty_bytes_stored = ((header1 & 2) == 2); - bool recursion_used = ((header1 & 128) == 128); - int compression_level = (header1 >> 2) & 15; - int windowbits = -(((header2 >> 4) & 15) + 8); - int memlevel = header2 & 15; - - if (DEBUG_MODE) { - printf("Compression level: %i\n", compression_level); - printf("Window size: %i\n", -windowbits); - printf("Memory level: %i\n", memlevel); - } - - // read penalty bytes - if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); - own_fread(penalty_bytes, 1, penalty_bytes_len, fin); - } - - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); - - long long recursion_data_length = 0; - if (recursion_used) { - recursion_data_length = fin_fget64(); - } - - if (DEBUG_MODE) { - if (recursion_used) { - cout << "Recursion data length: " << recursion_data_length << endl; - } else { - cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; - } - } - - long long old_fout_pos = tell_64(fout); - - if (recursion_used) { - recursion_result r = recursion_decompress(recursion_data_length); - retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - safe_fclose(&r.frecurse); - remove(r.file_name); - delete[] r.file_name; - } else { - retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - } - - if (retval != Z_OK) { + if (!ok) { printf("Error recompressing data!"); - cout << "retval = " << retval << endl; exit(0); } + break; + } + case D_RAW: { // raw zLib recompression + recompress_deflate_result rdres; + unsigned hdr_length; + int64_t recursion_data_length; + bool ok = fin_fget_deflate_rec(rdres, header1, in, hdr_length, true, recursion_data_length); - if (penalty_bytes_stored) { - fflush(fout); + debug_deflate_reconstruct(rdres, "raw zLib", hdr_length, recursion_data_length); - long long fsave_fout_pos = tell_64(fout); - int pb_pos = 0; - for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) { - pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24; - pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16; - pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8; - pb_pos += (unsigned char)penalty_bytes[pbc + 3]; - - seek_64(fout, old_fout_pos + pb_pos); - own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout); - } - - seek_64(fout, fsave_fout_pos); - } - - } else if (headertype == 255) { // raw zLib recompression - - if (DEBUG_MODE) { - printf("Decompressed data - raw zLib\n"); - } - - unsigned char header2 = fin_fgetc(); - - bool penalty_bytes_stored = ((header1 & 2) == 2); - bool recursion_used = ((header1 & 128) == 128); - int compression_level = (header1 >> 2) & 15; - int windowbits = -(((header2 >> 4) & 15) + 8); - int memlevel = header2 & 15; - - if (DEBUG_MODE) { - printf("Compression level: %i\n", compression_level); - printf("Window size: %i\n", -windowbits); - printf("Memory level: %i\n", memlevel); - } - - // restore zLib header (decrease by 1) - own_fread(in, 1, 2, fin); - unsigned char decchar = *(in + 1) - 1; - own_fwrite(in, 1, 1, fout); - fputc(decchar, fout); - - // read penalty bytes - if (penalty_bytes_stored) { - penalty_bytes_len = (fin_fgetc() << 24); - penalty_bytes_len += (fin_fgetc() << 16); - penalty_bytes_len += (fin_fgetc() << 8); - penalty_bytes_len += fin_fgetc(); - own_fread(penalty_bytes, 1, penalty_bytes_len, fin); - } - - long long recompressed_data_length = fin_fget64(); - long long decompressed_data_length = fin_fget64(); - - long long recursion_data_length = 0; - if (recursion_used) { - recursion_data_length = fin_fget64(); - } - - if (DEBUG_MODE) { - if (recursion_used) { - cout << "Recursion data length: " << recursion_data_length << endl; - } else { - cout << "Recompressed length: " << recompressed_data_length << " - decompressed length: " << decompressed_data_length << endl; - } - } - - long long old_fout_pos = tell_64(fout); - - if (recursion_used) { - recursion_result r = recursion_decompress(recursion_data_length); - retval = def_part(r.frecurse, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - safe_fclose(&r.frecurse); - remove(r.file_name); - delete[] r.file_name; - } else { - retval = def_part(fin, fout, compression_level, windowbits, memlevel, decompressed_data_length, recompressed_data_length); - } - - if (retval != Z_OK) { + if (!ok) { printf("Error recompressing data!"); - cout << "retval = " << retval << endl; exit(0); } - - if (penalty_bytes_stored) { - fflush(fout); - - long long fsave_fout_pos = tell_64(fout); - - int pb_pos = 0; - for (int pbc = 0; pbc < penalty_bytes_len; pbc += 5) { - pb_pos = ((unsigned char)penalty_bytes[pbc]) << 24; - pb_pos += ((unsigned char)penalty_bytes[pbc + 1]) << 16; - pb_pos += ((unsigned char)penalty_bytes[pbc + 2]) << 8; - pb_pos += (unsigned char)penalty_bytes[pbc + 3]; - - seek_64(fout, old_fout_pos + pb_pos); - own_fwrite(penalty_bytes + pbc + 4, 1, 1, fout); - } - - seek_64(fout, fsave_fout_pos); - } - } else { + break; + } + default: printf("ERROR: Unsupported stream type %i\n", headertype); exit(0); } @@ -6015,24 +5162,6 @@ void convert_file() { denit_convert(); } -long long try_to_decompress(FILE* file, int windowbits, long long& compressed_stream_size, bool& in_memory) { - long long r, decompressed_stream_size; - - print_work_sign(true); - - if (file == fin) { - seek_64(file, input_file_pos); - } else { - seek_64(file, 0); - } - - in_memory = true; - r = inf(file, windowbits, compressed_stream_size, decompressed_stream_size, in_memory); - if (r == Z_OK) return decompressed_stream_size; - - return r; -} - long long try_to_decompress_bzip2(FILE* file, int compression_level, long long& compressed_stream_size) { long long r, decompressed_stream_size; @@ -6053,58 +5182,6 @@ long long try_to_decompress_bzip2(FILE* file, int compression_level, long long& return r; } -void try_recompress(FILE* origfile, int comp_level, int mem_level, int windowbits, long long& compressed_stream_size, long long decomp_bytes_total, bool in_memory) { - print_work_sign(true); - - identical_bytes = file_recompress(origfile, comp_level, windowbits, mem_level, identical_bytes_decomp, decomp_bytes_total, in_memory); - if (identical_bytes > -1) { // successfully recompressed? - if ((identical_bytes > best_identical_bytes) || ((identical_bytes == best_identical_bytes) && (penalty_bytes_len < best_penalty_bytes_len))) { - if (identical_bytes > min_ident_size) { - if (DEBUG_MODE) { - cout << "Identical recompressed bytes: " << identical_bytes << " of " << compressed_stream_size << endl; - cout << "Identical decompressed bytes: " << identical_bytes_decomp << " of " << decomp_bytes_total << endl; - } - - bool enough_identical_compressed_bytes = (identical_bytes == compressed_stream_size); - if (!enough_identical_compressed_bytes) { - if ((identical_bytes > DEF_COMPARE_CHUNK) && (identical_bytes + IDENTICAL_COMPRESSED_BYTES_TOLERANCE >= compressed_stream_size)) { - enough_identical_compressed_bytes = true; - } - } - - final_compression_found = (identical_bytes_decomp == decomp_bytes_total) && (enough_identical_compressed_bytes) && (penalty_bytes_len < PENALTY_BYTES_TOLERANCE); - - // Partial matches sometimes need all the decompressed bytes, but there are much less - // identical recompressed bytes - in these cases, all the decompressed bytes have to - // be stored together with the remaining recompressed bytes, so the result won't compress - // better than the original stream. What's important here is the ratio between recompressed ratio - // and decompressed ratio that shouldn't get too high. - // Example: A stream has 5 of 1000 identical recompressed bytes, but needs 1000 of 1000 decompressed bytes, - // so the ratio is (1000/1000)/(5/1000) = 200 which is too high. With 5 of 1000 decompressed bytes or - // 1000 of 1000 identical recompressed bytes, ratio would've been 1 and we'd accept it. - float partial_ratio = ((float)identical_bytes_decomp / decomp_bytes_total) / ((float)identical_bytes / compressed_stream_size); - if (partial_ratio < 3.0f) { - best_identical_bytes_decomp = identical_bytes_decomp; - best_identical_bytes = identical_bytes; - best_compression = comp_level; - best_mem_level = mem_level; - best_windowbits = windowbits; - if (penalty_bytes_len > 0) { - memcpy(best_penalty_bytes, penalty_bytes, penalty_bytes_len); - best_penalty_bytes_len = penalty_bytes_len; - } else { - best_penalty_bytes_len = 0; - } - } else { - if (DEBUG_MODE) { - printf("Not enough identical recompressed bytes\n"); - } - } - } - } - } -} - void try_recompress_bzip2(FILE* origfile, int level, long long& compressed_stream_size) { print_work_sign(true); @@ -6697,404 +5774,149 @@ long long compare_files_penalty(FILE* file1, FILE* file2, long long pos1, long l } void try_decompression_gzip(int gzip_header_length) { - init_decompression_variables(); - - int windowbits; - - // try to decompress at current position - long long compressed_stream_size = -1; - bool in_memory; - retval = try_to_decompress(fin, -15, compressed_stream_size, in_memory); - - if (retval > 0) { // seems to be a zLib-Stream - - decompressed_streams_count++; - decompressed_gzip_count++; - - if (DEBUG_MODE) { - print_debug_percent(); - cout << "Possible zLib-Stream in GZip found at position " << saved_input_file_pos << endl; - cout << "Compressed size: " << compressed_stream_size << endl; - cout << "Can be decompressed to " << retval << " bytes" << endl; - } - - for (windowbits = -15; windowbits < -7; windowbits++) { - for (int index = MTF.First(); index>=0; index=MTF.Next()){ - if (comp_mem_level_count[index] == -1) continue; - int comp_level = (index % 9) + 1; - int mem_level = (index / 9) + 1; - - try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size, retval, in_memory); - - if (final_compression_found){ MTF.Update(); break; } - } - if (final_compression_found) break; - } - - if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) { - recompressed_streams_count++; - recompressed_gzip_count++; - - windowbits = best_windowbits; - if (DEBUG_MODE) { - cout << "Best match with level combination " << best_compression << best_mem_level << ", windowbits = " << -windowbits << ": " << best_identical_bytes << " bytes, decompressed to " << best_identical_bytes_decomp << " bytes" << endl; - } - - if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) { - if (fast_mode) { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - for (int i = 0; i < 81; i++) { - if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) { - comp_mem_level_count[i] = -1; - } - } - anything_was_used = true; - } else { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - anything_was_used = true; - } - } - - // end uncompressed data - - compressed_data_found = true; - end_uncompressed_data(); - - // check recursion - write_ftempout_if_not_present(best_identical_bytes_decomp, in_memory); - recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp); - - // write compressed data header (GZip) without 2 first bytes - - int header_byte = 1 + (best_compression << 2); - if (best_penalty_bytes_len != 0) { - header_byte += 2; - } - if (r.success) { - header_byte += 128; - } - fout_fputc(header_byte); - fout_fputc(2); // GZip - fout_fputc((((-windowbits) - 8) << 4) + best_mem_level); - - gzip_header_length -= 2; - - fout_fput24(gzip_header_length); - - own_fwrite(in_buf + cb + 2, 1, gzip_header_length, fout); - - // store penalty bytes, if any - if (best_penalty_bytes_len != 0) { - if (DEBUG_MODE) { - printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); - } - fout_fput32(best_penalty_bytes_len); - for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { - fout_fputc(best_penalty_bytes[pbc]); - } - } - - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); - - if (r.success) { - fout_fput64(r.file_length); - } - - // write decompressed data - if (r.success) { - write_decompressed_data(r.file_length, r.file_name); - remove(r.file_name); - delete[] r.file_name; - } else { - write_decompressed_data_io_buf(best_identical_bytes_decomp, in_memory); - } - - // start new uncompressed data - - // set input file pointer after recompressed data - input_file_pos += best_identical_bytes - 1; - cb += best_identical_bytes - 1; - - } else { - if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); - if (DEBUG_MODE) { - printf("No matches\n"); - } - } - - } - - + try_decompression_deflate_type(decompressed_gzip_count, recompressed_gzip_count, + D_GZIP, in_buf + cb + 2, gzip_header_length - 2, false, + "in GZIP"); } void try_decompression_png (int windowbits) { init_decompression_variables(); - // try to decompress at current position - long long compressed_stream_size = -1; - bool in_memory; - retval = try_to_decompress(fin, windowbits, compressed_stream_size, in_memory); + // try to decompress at current position + recompress_deflate_result rdres = try_recompression_deflate(fin); - if (retval > 0) { // seems to be a zLib-Stream + if (rdres.uncompressed_stream_size > 0) { // seems to be a zLib-Stream - decompressed_streams_count++; - decompressed_png_count++; + decompressed_streams_count++; + decompressed_png_count++; - if (DEBUG_MODE) { - print_debug_percent(); - cout << "Possible zLib-Stream in PNG found at position " << saved_input_file_pos << ", windowbits = " << -windowbits << endl; - cout << "Compressed size: " << compressed_stream_size << endl; - cout << "Can be decompressed to " << retval << " bytes" << endl; - } + debug_deflate_detected(rdres, "in PNG"); - for (int index = MTF.First(); index>=0; index=MTF.Next()){ - if (comp_mem_level_count[index] == -1) continue; - int comp_level = (index % 9) + 1; - int mem_level = (index / 9) + 1; + if (rdres.accepted) { + recompressed_streams_count++; + recompressed_png_count++; - try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size, retval, in_memory); + non_zlib_was_used = true; - if (final_compression_found){ MTF.Update(); break; } - } + debug_sums(rdres); - if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) { - recompressed_streams_count++; - recompressed_png_count++; + // end uncompressed data + compressed_data_found = true; + end_uncompressed_data(); - if (DEBUG_MODE) { - cout << "Best match with level combination " << best_compression << best_mem_level << ": " << best_identical_bytes << " bytes, decompressed to " << best_identical_bytes_decomp << " bytes" << endl; - } + debug_pos(); - if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) { - if (fast_mode) { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - for (int i = 0; i < 81; i++) { - if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) { - comp_mem_level_count[i] = -1; - } - } - anything_was_used = true; - } else { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - anything_was_used = true; - } - } + // write compressed data header (PNG) + fout_fput_deflate_hdr(D_PNG, 0, rdres, zlib_header, 2, true); - // end uncompressed data - - compressed_data_found = true; - end_uncompressed_data(); - - // write compressed data header (PNG) - - if (best_penalty_bytes_len == 0) { - fout_fputc(1 + (best_compression << 2)); - } else { - fout_fputc(1 + 2 + (best_compression << 2)); - } - fout_fputc(3); // PNG - fout_fputc((((-windowbits) - 8) << 4) + best_mem_level); - - // store zLib header, but increased by 1 to prevent finding it - // again in the next pass - own_fwrite(zlib_header, 1, 1, fout); - unsigned char incchar = *(zlib_header + 1) + 1; - fout_fputc(incchar); - - // store penalty bytes, if any - if (best_penalty_bytes_len != 0) { - if (DEBUG_MODE) { - printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); - } - fout_fput32(best_penalty_bytes_len); - for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { - fout_fputc(best_penalty_bytes[pbc]); - } - } - - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); - - // write decompressed data - - write_decompressed_data_io_buf(best_identical_bytes_decomp, in_memory); - - // start new uncompressed data - - // set input file pointer after recompressed data - input_file_pos += best_identical_bytes - 1; - cb += best_identical_bytes - 1; - - } else { - if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2); - if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); - if (DEBUG_MODE) { - printf("No matches\n"); - } - } - - } + // write reconstruction and decompressed data + fout_fput_recon_data(rdres); + fout_fput_uncompressed(rdres); + debug_pos(); + // set input file pointer after recompressed data + input_file_pos += rdres.compressed_stream_size - 1; + cb += rdres.compressed_stream_size - 1; + } else { + if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2); + if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); + if (DEBUG_MODE) { + printf("No matches\n"); + } + } + } } -void try_decompression_png_multi(int windowbits) { +void try_decompression_png_multi(FILE* fpng, int windowbits) { init_decompression_variables(); - // try to decompress at current position - long long compressed_stream_size = -1; - bool in_memory; - retval = try_to_decompress(fpng, windowbits, compressed_stream_size, in_memory); + // try to decompress at current position + recompress_deflate_result rdres = try_recompression_deflate(fpng); - if (retval > 0) { // seems to be a zLib-Stream + if (rdres.uncompressed_stream_size > 0) { // seems to be a zLib-Stream - decompressed_streams_count++; - decompressed_png_multi_count++; + decompressed_streams_count++; + decompressed_png_multi_count++; - if (DEBUG_MODE) { - print_debug_percent(); - cout << "Possible zLib-Stream in multiPNG found at position " << saved_input_file_pos << ", windowbits = " << -windowbits << endl; - cout << "Compressed size: " << compressed_stream_size << endl; - cout << "Can be decompressed to " << retval << " bytes" << endl; - } + debug_deflate_detected(rdres, "in multiPNG"); - for (int index = MTF.First(); index>=0; index=MTF.Next()){ - if (comp_mem_level_count[index] == -1) continue; - int comp_level = (index % 9) + 1; - int mem_level = (index / 9) + 1; + if (rdres.accepted) { + recompressed_streams_count++; + recompressed_png_multi_count++; - try_recompress(fpng, comp_level, mem_level, windowbits, compressed_stream_size, retval, in_memory); + non_zlib_was_used = true; - if (final_compression_found){ MTF.Update(); break; } - } + debug_sums(rdres); - if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) { - recompressed_streams_count++; - recompressed_png_multi_count++; + // end uncompressed data + compressed_data_found = true; + end_uncompressed_data(); - if (DEBUG_MODE) { - cout << "Best match with level combination " << best_compression << best_mem_level << ": " << best_identical_bytes << " bytes, decompressed to " << best_identical_bytes_decomp << " bytes" << endl; - } + debug_pos(); - if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) { - if (fast_mode) { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - for (int i = 0; i < 81; i++) { - if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) { - comp_mem_level_count[i] = -1; - } - } - anything_was_used = true; - } else { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - anything_was_used = true; - } - } + // write compressed data header (PNG) + fout_fput_deflate_hdr(D_MULTIPNG, 0, rdres, zlib_header, 2, true); - // end uncompressed data + // simulate IDAT write to get IDAT pairs count + int i = 1; + int idat_pos = idat_lengths[0] - 2; + unsigned int idat_pairs_written_count = 0; + if (idat_pos <= rdres.compressed_stream_size) { + do { + idat_pairs_written_count++; - compressed_data_found = true; - end_uncompressed_data(); + idat_pos += idat_lengths[i]; + if (idat_pos > rdres.compressed_stream_size) break; - // write compressed data header (PNG) + i++; + } while (i < idat_count); + } + // store IDAT pairs count + fout_fput_vlint(idat_pairs_written_count); - if (best_penalty_bytes_len == 0) { - fout_fputc(1 + (best_compression << 2)); - } else { - fout_fputc(1 + 2 + (best_compression << 2)); - } - fout_fputc(4); // PNG multi - fout_fputc((((-windowbits) - 8) << 4) + best_mem_level); + // store IDAT CRCs and lengths + fout_fput_vlint(idat_lengths[0]); - // store zLib header, but increased by 1 to prevent finding it - // again in the next pass - own_fwrite(zlib_header, 1, 1, fout); - unsigned char incchar = *(zlib_header + 1) + 1; - fout_fputc(incchar); + // store IDAT CRCs and lengths + i = 1; + idat_pos = idat_lengths[0] - 2; + idat_pairs_written_count = 0; + if (idat_pos <= rdres.compressed_stream_size) { + do { + fout_fput32(idat_crcs[i]); + fout_fput_vlint(idat_lengths[i]); - // simulate IDAT write to get IDAT pairs count - int i = 1; - int idat_pos = idat_lengths[0] - 2; - unsigned int idat_pairs_written_count = 0; - if (idat_pos <= best_identical_bytes) { - do { - idat_pairs_written_count++; + idat_pairs_written_count++; - idat_pos += idat_lengths[i]; - if (idat_pos > best_identical_bytes) break; + idat_pos += idat_lengths[i]; + if (idat_pos > rdres.compressed_stream_size) break; - i++; - } while (i < idat_count); - } - // store IDAT pairs count - fout_fput16(idat_pairs_written_count); + i++; + } while (i < idat_count); + } - // store IDAT CRCs and lengths - fout_fput32(idat_lengths[0]); + // write reconstruction and decompressed data + fout_fput_recon_data(rdres); + fout_fput_uncompressed(rdres); - // store IDAT CRCs and lengths - i = 1; - idat_pos = idat_lengths[0] - 2; - idat_pairs_written_count = 0; - if (idat_pos <= best_identical_bytes) { - do { - fout_fput32(idat_crcs[i]); - fout_fput32(idat_lengths[i]); - - idat_pairs_written_count++; - - idat_pos += idat_lengths[i]; - if (idat_pos > best_identical_bytes) break; - - i++; - } while (i < idat_count); - } - - // store penalty bytes, if any - if (best_penalty_bytes_len != 0) { - if (DEBUG_MODE) { - printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); - } - fout_fput32(best_penalty_bytes_len); - for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { - fout_fputc(best_penalty_bytes[pbc]); - } - } - - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); - - // write decompressed data - - write_decompressed_data_io_buf(best_identical_bytes_decomp, in_memory); - - // start new uncompressed data - - // set input file pointer after recompressed data - input_file_pos += best_identical_bytes - 1; - cb += best_identical_bytes - 1; - // now add IDAT chunk overhead - input_file_pos += (idat_pairs_written_count * 12); - cb += (idat_pairs_written_count * 12); - - } else { - if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2); - if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); - if (DEBUG_MODE) { - printf("No matches\n"); - } - } - - } + debug_pos(); + // set input file pointer after recompressed data + input_file_pos += rdres.compressed_stream_size - 1; + cb += rdres.compressed_stream_size - 1; + // now add IDAT chunk overhead + input_file_pos += (idat_pairs_written_count * 12); + cb += (idat_pairs_written_count * 12); + } else { + if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2); + if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); + if (DEBUG_MODE) { + printf("No matches\n"); + } + } + } } // GIF functions @@ -7593,10 +6415,10 @@ void try_decompression_gif(unsigned char version[5]) { if (recompress_success_needed) add_bits += 128; fout_fputc(1 + add_bits); - fout_fputc(5); // GIF + fout_fputc(D_GIF); // GIF // store diff bytes - fout_fput32(gDiff.GIFDiffIndex); + fout_fput_vlint(gDiff.GIFDiffIndex); if(DEBUG_MODE) { if (gDiff.GIFDiffIndex > 0) printf("Diff bytes were used: %i bytes\n", gDiff.GIFDiffIndex); @@ -7611,15 +6433,15 @@ void try_decompression_gif(unsigned char version[5]) { printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); } - fout_fput32(best_penalty_bytes_len); + fout_fput_vlint(best_penalty_bytes_len); for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { fout_fputc(best_penalty_bytes[pbc]); } } - fout_fput64(best_identical_bytes); - fout_fput64(decomp_length); + fout_fput_vlint(best_identical_bytes); + fout_fput_vlint(decomp_length); // write decompressed data write_decompressed_data(decomp_length); @@ -7831,10 +6653,10 @@ void try_decompression_jpg (long long jpg_length, bool progressive_jpg) { } else { fout_fputc(1); // no penalty bytes } - fout_fputc(6); // JPG + fout_fputc(D_JPG); // JPG - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); + fout_fput_vlint(best_identical_bytes); + fout_fput_vlint(best_identical_bytes_decomp); // write compressed JPG if (in_memory) { @@ -7977,10 +6799,10 @@ void try_decompression_mp3 (long long mp3_length) { // write compressed data header (MP3) fout_fputc(1); // no penalty bytes - fout_fputc(10); // MP3 + fout_fputc(D_MP3); // MP3 - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); + fout_fput_vlint(best_identical_bytes); + fout_fput_vlint(best_identical_bytes_decomp); // write compressed MP3 if (in_memory) { @@ -8075,387 +6897,21 @@ inline unsigned short mp3_calc_layer3_crc(unsigned char header2, unsigned char h } void try_decompression_zlib(int windowbits) { - init_decompression_variables(); - - // try to decompress at current position - long long compressed_stream_size = -1; - bool in_memory; - retval = try_to_decompress(fin, windowbits, compressed_stream_size, in_memory); - - if (retval > 0) { // seems to be a zLib-Stream - - decompressed_streams_count++; - decompressed_zlib_count++; - - if (DEBUG_MODE) { - print_debug_percent(); - cout << "Possible zLib-Stream (intense mode) found at position " << saved_input_file_pos << ", windowbits = " << -windowbits << endl; - cout << "Compressed size: " << compressed_stream_size << endl; - cout << "Can be decompressed to " << retval << " bytes" << endl; - } - - for (int index = MTF.First(); index>=0; index=MTF.Next()){ - if (comp_mem_level_count[index] == -1) continue; - int comp_level = (index % 9) + 1; - int mem_level = (index / 9) + 1; - - try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size, retval, in_memory); - - if (final_compression_found){ MTF.Update(); break; } - } - - if ((best_identical_bytes > min_ident_size_intense_brute_mode) && (best_identical_bytes < best_identical_bytes_decomp)) { - recompressed_streams_count++; - recompressed_zlib_count++; - - if (DEBUG_MODE) { - cout << "Best match with level combination " << best_compression << best_mem_level << ": " << best_identical_bytes << " bytes, decompressed to " << best_identical_bytes_decomp << " bytes" << endl; - } - - if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) { - if (fast_mode) { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - for (int i = 0; i < 81; i++) { - if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) { - comp_mem_level_count[i] = -1; - } - } - anything_was_used = true; - } else { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - anything_was_used = true; - } - } - - // end uncompressed data - - compressed_data_found = true; - end_uncompressed_data(); - - // check recursion - write_ftempout_if_not_present(best_identical_bytes_decomp, in_memory); - recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp); - - // write compressed data header (zLib) - - int header_byte = 1 + (best_compression << 2); - if (best_penalty_bytes_len != 0) { - header_byte += 2; - } - if (r.success) { - header_byte += 128; - } - fout_fputc(header_byte); - fout_fputc(255); // raw zLib - fout_fputc((((-windowbits) - 8) << 4) + best_mem_level); - - // store zLib header, but increased by 1 to prevent finding it - // again in the next pass - own_fwrite(in_buf + cb, 1, 1, fout); - unsigned char incchar = *(in_buf + cb + 1) + 1; - fout_fputc(incchar); - - // store penalty bytes, if any - if (best_penalty_bytes_len != 0) { - if (DEBUG_MODE) { - printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); - } - fout_fput32(best_penalty_bytes_len); - for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { - fout_fputc(best_penalty_bytes[pbc]); - } - } - - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); - - if (r.success) { - fout_fput64(r.file_length); - } - - // write decompressed data - if (r.success) { - write_decompressed_data(r.file_length, r.file_name); - remove(r.file_name); - delete[] r.file_name; - } else { - write_decompressed_data_io_buf(best_identical_bytes_decomp, in_memory); - } - - // start new uncompressed data - - // set input file pointer after recompressed data - input_file_pos += best_identical_bytes - 1; - cb += best_identical_bytes - 1; - - } else { - if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); - if (DEBUG_MODE) { - printf("No matches\n"); - } - } - - } - - + try_decompression_deflate_type(decompressed_zlib_count, recompressed_zlib_count, + D_RAW, in_buf + cb, 2, true, + "(intense mode)"); } void try_decompression_brute() { - init_decompression_variables(); - - int windowbits; - - // try to decompress at current position - long long compressed_stream_size = -1; - bool in_memory; - retval = try_to_decompress(fin, -15, compressed_stream_size, in_memory); - - if (retval > 0) { // seems to be a zLib-Stream - - decompressed_streams_count++; - decompressed_brute_count++; - - if (DEBUG_MODE) { - print_debug_percent(); - cout << "Possible zLib-Stream (brute mode) found at position " << saved_input_file_pos << endl; - cout << "Compressed size: " << compressed_stream_size << endl; - cout << "Can be decompressed to " << retval << " bytes" << endl; - } - - for (windowbits = -15; windowbits < -7; windowbits++) { - for (int index = MTF.First(); index>=0; index=MTF.Next()){ - if (comp_mem_level_count[index] == -1) continue; - int comp_level = (index % 9) + 1; - int mem_level = (index / 9) + 1; - - try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size, retval, in_memory); - - if (final_compression_found){ MTF.Update(); break; } - } - if (final_compression_found) break; - } - - if ((best_identical_bytes > min_ident_size_intense_brute_mode) && (best_identical_bytes < best_identical_bytes_decomp)) { - recompressed_streams_count++; - recompressed_brute_count++; - - windowbits = best_windowbits; - if (DEBUG_MODE) { - cout << "Best match with level combination " << best_compression << best_mem_level << ", windowbits = " << -windowbits << ": " << best_identical_bytes << " bytes, decompressed to " << best_identical_bytes_decomp << " bytes" << endl; - } - - if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) { - if (fast_mode) { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - for (int i = 0; i < 81; i++) { - if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) { - comp_mem_level_count[i] = -1; - } - } - anything_was_used = true; - } else { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - anything_was_used = true; - } - } - - // end uncompressed data - - compressed_data_found = true; - end_uncompressed_data(); - - // check recursion - write_ftempout_if_not_present(best_identical_bytes_decomp, in_memory); - recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp); - - // write compressed data header (brute) - - int header_byte = 1 + (best_compression << 2); - if (best_penalty_bytes_len != 0) { - header_byte += 2; - } - if (r.success) { - header_byte += 128; - } - fout_fputc(header_byte); - fout_fputc(254); // brute - fout_fputc((((-windowbits) - 8) << 4) + best_mem_level); - - // store penalty bytes, if any - if (best_penalty_bytes_len != 0) { - if (DEBUG_MODE) { - printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); - } - fout_fput32(best_penalty_bytes_len); - for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { - fout_fputc(best_penalty_bytes[pbc]); - } - } - - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); - - if (r.success) { - fout_fput64(r.file_length); - } - - // write decompressed data - if (r.success) { - write_decompressed_data(r.file_length, r.file_name); - remove(r.file_name); - delete[] r.file_name; - } else { - write_decompressed_data_io_buf(best_identical_bytes_decomp, in_memory); - } - - // set input file pointer after recompressed data - input_file_pos += best_identical_bytes - 1; - cb += best_identical_bytes - 1; - - } else { - if (DEBUG_MODE) { - printf("No matches\n"); - } - } - - } - - + try_decompression_deflate_type(decompressed_brute_count, recompressed_brute_count, + D_BRUTE, in_buf + cb, 0, false, + "(brute mode)"); } void try_decompression_swf(int windowbits) { - init_decompression_variables(); - - // try to decompress at current position - long long compressed_stream_size = -1; - bool in_memory; - retval = try_to_decompress(fin, windowbits, compressed_stream_size, in_memory); - - if (retval > 0) { // seems to be a zLib-Stream - - decompressed_streams_count++; - decompressed_swf_count++; - - if (DEBUG_MODE) { - print_debug_percent(); - cout << "Possible zLib-Stream in SWF found at position " << saved_input_file_pos << ", windowbits = " << -windowbits << endl; - cout << "Compressed size: " << compressed_stream_size << endl; - cout << "Can be decompressed to " << retval << " bytes" << endl; - } - - for (int index = MTF.First(); index>=0; index=MTF.Next()){ - if (comp_mem_level_count[index] == -1) continue; - int comp_level = (index % 9) + 1; - int mem_level = (index / 9) + 1; - - try_recompress(fin, comp_level, mem_level, windowbits, compressed_stream_size, retval, in_memory); - - if (final_compression_found){ MTF.Update(); break; } - } - - if ((best_identical_bytes > min_ident_size) && (best_identical_bytes < best_identical_bytes_decomp)) { - recompressed_streams_count++; - recompressed_swf_count++; - - if (DEBUG_MODE) { - cout << "Best match with level combination " << best_compression << best_mem_level << ": " << best_identical_bytes << " bytes, decompressed to " << best_identical_bytes_decomp << " bytes" << endl; - } - - if (!(comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9] == -1)) { - if (fast_mode) { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - for (int i = 0; i < 81; i++) { - if (i != ((best_compression - 1) + (best_mem_level - 1) * 9)) { - comp_mem_level_count[i] = -1; - } - } - anything_was_used = true; - } else { - comp_mem_level_count[(best_compression - 1) + (best_mem_level - 1) * 9]++; - zlib_level_was_used[(best_compression - 1) + (best_mem_level - 1) * 9] = true; - anything_was_used = true; - } - } - - // end uncompressed data - - compressed_data_found = true; - end_uncompressed_data(); - - // check recursion - write_ftempout_if_not_present(best_identical_bytes_decomp, in_memory); - recursion_result r = recursion_compress(best_identical_bytes, best_identical_bytes_decomp); - - // write compressed data header (SWF) - - int header_byte = 1 + (best_compression << 2); - if (best_penalty_bytes_len != 0) { - header_byte += 2; - } - if (r.success) { - header_byte += 128; - } - fout_fputc(header_byte); - fout_fputc(7); // SWF - fout_fputc((((-windowbits) - 8) << 4) + best_mem_level); - - // store version and length from SWF header - own_fwrite(in_buf + cb + 3, 1, 5, fout); - - // store zLib header, but increased by 1 to prevent finding it - // again in the next pass - own_fwrite(in_buf + cb + 8, 1, 1, fout); - unsigned char incchar = *(in_buf + cb + 9) + 1; - fout_fputc(incchar); - - // store penalty bytes, if any - if (best_penalty_bytes_len != 0) { - if (DEBUG_MODE) { - printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); - } - fout_fput32(best_penalty_bytes_len); - for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { - fout_fputc(best_penalty_bytes[pbc]); - } - } - - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); - - if (r.success) { - fout_fput64(r.file_length); - } - - // write decompressed data - if (r.success) { - write_decompressed_data(r.file_length, r.file_name); - remove(r.file_name); - delete[] r.file_name; - } else { - write_decompressed_data_io_buf(best_identical_bytes_decomp, in_memory); - } - - // start new uncompressed data - - // set input file pointer after recompressed data - input_file_pos += best_identical_bytes - 1; - cb += best_identical_bytes - 1; - - } else { - if (intense_mode_is_active()) intense_ignore_offsets->insert(input_file_pos - 2); - if (brute_mode_is_active()) brute_ignore_offsets->insert(input_file_pos); - if (DEBUG_MODE) { - printf("No matches\n"); - } - } - - } - + try_decompression_deflate_type(decompressed_swf_count, recompressed_swf_count, + D_SWF, in_buf + cb + 3, 7, true, + "in SWF"); } void try_decompression_bzip2(int compression_level) { @@ -8511,7 +6967,7 @@ void try_decompression_bzip2(int compression_level) { header_byte += 128; } fout_fputc(header_byte); - fout_fputc(9); // Base64 + fout_fputc(D_BZIP2); // Base64 fout_fputc(compression_level); // store penalty bytes, if any @@ -8519,17 +6975,17 @@ void try_decompression_bzip2(int compression_level) { if (DEBUG_MODE) { printf("Penalty bytes were used: %i bytes\n", best_penalty_bytes_len); } - fout_fput32(best_penalty_bytes_len); + fout_fput_vlint(best_penalty_bytes_len); for (int pbc = 0; pbc < best_penalty_bytes_len; pbc++) { fout_fputc(best_penalty_bytes[pbc]); } } - fout_fput64(best_identical_bytes); - fout_fput64(best_identical_bytes_decomp); + fout_fput_vlint(best_identical_bytes); + fout_fput_vlint(best_identical_bytes_decomp); if (r.success) { - fout_fput64(r.file_length); + fout_fput_vlint(r.file_length); } // write decompressed data @@ -8835,15 +7291,15 @@ void try_decompression_base64(int base64_header_length) { header_byte += 128; } fout_fputc(header_byte); - fout_fputc(8); // Base64 + fout_fputc(D_BASE64); // Base64 - fout_fput16(base64_header_length); + fout_fput_vlint(base64_header_length); // write "header", but change first char to prevent re-detection fout_fputc(in_buf[cb] - 1); own_fwrite(in_buf + cb + 1, 1, base64_header_length - 1, fout); - fout_fput16(line_count); + fout_fput_vlint(line_count); if (line_case == 2) { for (i = 0; i < line_count; i++) { fout_fputc(base64_line_len[i]); @@ -8855,11 +7311,11 @@ void try_decompression_base64(int base64_header_length) { delete[] base64_line_len; - fout_fput64(identical_bytes); - fout_fput64(identical_bytes_decomp); + fout_fput_vlint(identical_bytes); + fout_fput_vlint(identical_bytes_decomp); if (r.success) { - fout_fput64(r.file_length); + fout_fput_vlint(r.file_length); } // write decompressed data @@ -9316,6 +7772,11 @@ recursion_result recursion_compress(long long compressed_bytes, long long decomp return tmp_r; } +recursion_result recursion_write_file_and_compress(const recompress_deflate_result& rdres) { + write_ftempout_if_not_present(rdres.uncompressed_stream_size, rdres.uncompressed_in_memory); + recursion_result r = recursion_compress(rdres.compressed_stream_size, rdres.uncompressed_stream_size); + return r; +} recursion_result recursion_decompress(long long recursion_data_length) { FILE* recursion_fin; @@ -9408,17 +7869,6 @@ void fout_fputc(char c) { } } -void fout_fput16(int v) { - fout_fputc((v >> 8) % 256); - fout_fputc(v % 256); -} - -void fout_fput24(int v) { - fout_fputc((v >> 16) % 256); - fout_fputc((v >> 8) % 256); - fout_fputc(v % 256); -} - void fout_fput32_little_endian(int v) { fout_fputc(v % 256); fout_fputc((v >> 8) % 256); @@ -9440,26 +7890,116 @@ void fout_fput32(unsigned int v) { fout_fputc(v % 256); } -void fout_fput64(long long v) { - fout_fputc((v >> 56) % 256); - fout_fputc((v >> 48) % 256); - fout_fputc((v >> 40) % 256); - fout_fputc((v >> 32) % 256); - fout_fputc((v >> 24) % 256); - fout_fputc((v >> 16) % 256); - fout_fputc((v >> 8) % 256); - fout_fputc(v % 256); +void fout_fput_vlint(unsigned long long v) { + while (v >= 128) { + fout_fputc((v & 127) + 128); + v = (v >> 7) - 1; + } + fout_fputc(v); } +void fout_fput_deflate_hdr(const unsigned char type, const unsigned char flags, + const recompress_deflate_result& rdres, + const unsigned char* hdr, const unsigned hdr_length, + const bool inc_last_hdr_byte) { + fout_fputc(1 + (rdres.zlib_perfect ? rdres.zlib_comp_level << 2 : 2) + flags); + fout_fputc(type); // PDF/PNG/... + if (rdres.zlib_perfect) { + fout_fputc(((rdres.zlib_window_bits - 8) << 4) + rdres.zlib_mem_level); + } + fout_fput_vlint(hdr_length); + if (!inc_last_hdr_byte) { + own_fwrite(hdr, 1, hdr_length, fout); + } else { + own_fwrite(hdr, 1, hdr_length - 1, fout); + fout_fputc(hdr[hdr_length - 1] + 1); + } +} +void fin_fget_deflate_hdr(recompress_deflate_result& rdres, const unsigned char flags, + unsigned char* hdr_data, unsigned& hdr_length, + const bool inc_last_hdr_byte) { + rdres.zlib_perfect = (flags & 2) == 0; + if (rdres.zlib_perfect) { + unsigned char zlib_params = fin_fgetc(); + rdres.zlib_comp_level = (flags & 0x3c) >> 2; + rdres.zlib_mem_level = zlib_params & 0x0f; + rdres.zlib_window_bits = ((zlib_params >> 4) & 0x7) + 8; + } + hdr_length = fin_fget_vlint(); + if (!inc_last_hdr_byte) { + own_fread(hdr_data, 1, hdr_length, fin); + } else { + own_fread(hdr_data, 1, hdr_length - 1, fin); + hdr_data[hdr_length - 1] = fin_fgetc() - 1; + } + own_fwrite(hdr_data, 1, hdr_length, fout); +} +void fout_fput_recon_data(const recompress_deflate_result& rdres) { + if (!rdres.zlib_perfect) { + fout_fput_vlint(rdres.recon_data.size()); + own_fwrite(rdres.recon_data.data(), 1, rdres.recon_data.size(), fout); + } -void fout_fput64(unsigned long long v) { - fout_fputc((v >> 56) % 256); - fout_fputc((v >> 48) % 256); - fout_fputc((v >> 40) % 256); - fout_fputc((v >> 32) % 256); - fout_fputc((v >> 24) % 256); - fout_fputc((v >> 16) % 256); - fout_fputc((v >> 8) % 256); - fout_fputc(v % 256); + fout_fput_vlint(rdres.compressed_stream_size); + fout_fput_vlint(rdres.uncompressed_stream_size); +} +void fin_fget_recon_data(recompress_deflate_result& rdres) { + if (!rdres.zlib_perfect) { + size_t sz = fin_fget_vlint(); + rdres.recon_data.resize(sz); + own_fread(rdres.recon_data.data(), 1, rdres.recon_data.size(), fin); + } + + rdres.compressed_stream_size = fin_fget_vlint(); + rdres.uncompressed_stream_size = fin_fget_vlint(); +} +void fout_fput_uncompressed(const recompress_deflate_result& rdres) { + write_decompressed_data_io_buf(rdres.uncompressed_stream_size, rdres.uncompressed_in_memory); +} +void fin_fget_uncompressed(const recompress_deflate_result&) { +} +void fout_fput_deflate_rec(const unsigned char type, + const recompress_deflate_result& rdres, + const unsigned char* hdr, const unsigned hdr_length, const bool inc_last, + const recursion_result& recres) { + fout_fput_deflate_hdr(type, recres.success ? 128 : 0, rdres, hdr, hdr_length, inc_last); + fout_fput_recon_data(rdres); + + // write decompressed data + if (recres.success) { + fout_fput_vlint(recres.file_length); + write_decompressed_data(recres.file_length, recres.file_name); + remove(recres.file_name); + delete[] recres.file_name; + } else { + fout_fput_uncompressed(rdres); + } +} +bool fin_fget_deflate_rec(recompress_deflate_result& rdres, const unsigned char flags, + unsigned char* hdr, unsigned& hdr_length, const bool inc_last, + int64_t& recursion_length) { + fin_fget_deflate_hdr(rdres, flags, hdr, hdr_length, inc_last); + fin_fget_recon_data(rdres); + + debug_sums(rdres); + + // write decompressed data + if (flags & 128) { + recursion_length = fin_fget_vlint(); + recursion_result r = recursion_decompress(recursion_length); + debug_pos(); + bool result = try_reconstructing_deflate(r.frecurse, fout, rdres); + debug_pos(); + safe_fclose(&r.frecurse); + remove(r.file_name); + delete[] r.file_name; + return result; + } else { + recursion_length = 0; + debug_pos(); + bool result = try_reconstructing_deflate(fin, fout, rdres); + debug_pos(); + return result; + } } unsigned char fin_fgetc() { @@ -9473,19 +8013,33 @@ unsigned char fin_fgetc() { return temp_buf[0]; } } - -long long fin_fget64() { - long long result = ((long long)fin_fgetc() << 56); - result += ((long long)fin_fgetc() << 48); - result += ((long long)fin_fgetc() << 40); - result += ((long long)fin_fgetc() << 32); - result += ((long long)fin_fgetc() << 24); - result += ((long long)fin_fgetc() << 16); - result += ((long long)fin_fgetc() << 8); - result += (long long)fin_fgetc(); - +int32_t fin_fget32_little_endian() { + int32_t result = 0; + result += ((long)fin_fgetc() << 0); + result += ((long)fin_fgetc() << 8); + result += ((long)fin_fgetc() << 16); + result += ((long)fin_fgetc() << 24); return result; } +int32_t fin_fget32() { + int32_t result = 0; + result += ((long)fin_fgetc() << 24); + result += ((long)fin_fgetc() << 16); + result += ((long)fin_fgetc() << 8); + result += (long)fin_fgetc(); + return result; +} +long long fin_fget_vlint() { + unsigned char c; + long long v = 0, o = 0, s = 0; + while ((c = fin_fgetc()) >= 128) { + v += (((long long)(c & 127)) << s); + s += 7; + o = (o + 1) << 7; + } + return v + o + (((long long)c) << s); +} + void init_compress_otf() { if (comp_decomp_state == P_CONVERT) compression_otf_method = conversion_to_method; diff --git a/precomp.h b/precomp.h index 5062fdd..e52626b 100644 --- a/precomp.h +++ b/precomp.h @@ -3,7 +3,6 @@ long long def_compare(FILE *compfile, int level, int windowbits, int memlevel, l long long def_compare_bzip2(FILE *source, FILE *compfile, int level, long long& decompressed_bytes_used); int def_part(FILE *source, FILE *dest, int level, int windowbits, int memlevel, long long stream_size_in, long long stream_size_out); int def_part_skip(FILE *source, FILE *dest, int level, int windowbits, int memlevel, long long stream_size_in, long long stream_size_out, int bmp_width); -int inf(FILE *source, int windowbits, long long& compressed_stream_size, long long& decompressed_stream_size, bool& in_memory); void zerr(int ret); #ifndef PRECOMPDLL #ifndef COMFORT @@ -32,7 +31,7 @@ void try_decompression_pdf(int windowbits, int pdf_header_length, int img_width, void try_decompression_zip(int zip_header_length); void try_decompression_gzip(int gzip_header_length); void try_decompression_png(int windowbits); -void try_decompression_png_multi(int windowbits); +void try_decompression_png_multi(FILE* fpng, int windowbits); void try_decompression_gif(unsigned char version[5]); void try_decompression_jpg(long long jpg_length, bool progressive_jpg); void try_decompression_mp3(long long mp3_length); @@ -129,24 +128,33 @@ public: List[Root=Index].Previous = -1; } }; +struct recompress_deflate_result; void write_ftempout_if_not_present(long long byte_count, bool in_memory, bool leave_open = false); recursion_result recursion_compress(long long compressed_bytes, long long decompressed_bytes); recursion_result recursion_decompress(long long recursion_data_length); +recursion_result recursion_write_file_and_compress(const recompress_deflate_result&); // compression-on-the-fly enum {OTF_NONE = 0, OTF_BZIP2 = 1, OTF_XZ_MT = 2}; // uncompressed, bzip2, lzma2 multithreaded void own_fputc(char c, FILE* f); unsigned char fin_fgetc(); -long long fin_fget64(); +int32_t fin_fget32_little_endian(); +int32_t fin_fget32(); +long long fin_fget_vlint(); +void fin_fget_deflate_hdr(recompress_deflate_result&, const unsigned char flags, unsigned char* hdr_data, unsigned& hdr_length, const bool inc_last); +void fin_fget_recon_data(recompress_deflate_result&); +bool fin_fget_deflate_rec(recompress_deflate_result&, const unsigned char flags, unsigned char* hdr, unsigned& hdr_length, const bool inc_last, int64_t& rec_length); +void fin_fget_uncompressed(const recompress_deflate_result&); void fout_fputc(char c); -void fout_fput16(int v); -void fout_fput24(int v); void fout_fput32_little_endian(int v); void fout_fput32(int v); void fout_fput32(unsigned int v); -void fout_fput64(long long v); -void fout_fput64(unsigned long long v); +void fout_fput_vlint(unsigned long long v); +void fout_fput_deflate_hdr(const unsigned char type, const unsigned char flags, const recompress_deflate_result&, const unsigned char* hdr_data, const unsigned hdr_length, const bool inc_last); +void fout_fput_recon_data(const recompress_deflate_result&); +void fout_fput_deflate_rec(const unsigned char type, const recompress_deflate_result&, const unsigned char* hdr, const unsigned hdr_length, const bool inc_last, const recursion_result& recres); +void fout_fput_uncompressed(const recompress_deflate_result&); void init_compress_otf(); void denit_compress_otf(); void init_decompress_otf();