123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874moduleBigarray=Bigarray_compat(* XXX(dinosaure): MirageOS compatibility. *)typebigstring=(char,Bigarray.int8_unsigned_elt,Bigarray.c_layout)Bigarray.Array1.t(* XXX(dinosaure): prelude. *)letinvalid_argfmt=Format.kasprintfinvalid_argfmtletkstrfkfmt=Format.kasprintfkfmtletbigstring_empty=Bigarray.Array1.createBigarray.charBigarray.c_layout0letbigstring_createl=Bigarray.Array1.createBigarray.charBigarray.c_layoutlletbigstring_lengthx=Bigarray.Array1.dimx[@@inline]externalswap:int->int="%bswap16"externalunsafe_get_uint8:bigstring->int->int="%caml_ba_ref_1"externalunsafe_get_char:bigstring->int->char="%caml_ba_ref_1"externalunsafe_get_uint16:bigstring->int->int="%caml_bigstring_get16"externalunsafe_get_uint32:bigstring->int->int32="%caml_bigstring_get32"externalstring_unsafe_get_uint32:string->int->int32="%caml_string_get32"letstring_unsafe_get_uint8:string->int->int=funbufoff->Char.code(String.getbufoff)externalbytes_unsafe_get_uint32:bytes->int->int32="%caml_bytes_get32"letbytes_unsafe_get_uint8:bytes->int->int=funbufoff->Char.code(Bytes.getbufoff)externalunsafe_set_uint8:bigstring->int->int->unit="%caml_ba_set_1"externalunsafe_set_uint16:bigstring->int->int->unit="%caml_bigstring_set16"externalunsafe_set_uint32:bigstring->int->int32->unit="%caml_bigstring_set32"letbytes_unsafe_set_uint8:bytes->int->int->unit=funbufoffv->Bytes.setbufoff(Char.unsafe_chr(vland0xff))externalbytes_unsafe_set_uint32:bytes->int->int32->unit="%caml_bytes_set32"(* XXX(dinosaure): little-endian only *)letunsafe_set_uint16_le=ifnotSys.big_endianthenfunbufoffv->unsafe_set_uint16bufoffvelsefunbufoffv->unsafe_set_uint16bufoff(swapv)letbigstring_to_stringv=letlen=bigstring_lengthvinletres=Bytes.createleninletlen0=lenland3inletlen1=lenasr2infori=0tolen1-1doleti=i*4inletv=unsafe_get_uint32viinbytes_unsafe_set_uint32resivdone;fori=0tolen0-1doleti=len1*4+iinletv=unsafe_get_uint8viinbytes_unsafe_set_uint8resivdone;Bytes.unsafe_to_stringresletbigstring_of_stringv=letlen=String.lengthvinletres=bigstring_createleninletlen0=lenland3inletlen1=lenasr2infori=0tolen1-1doleti=i*4inletv=string_unsafe_get_uint32viinunsafe_set_uint32resivdone;fori=0tolen0-1doleti=len1*4+iinletv=string_unsafe_get_uint8viinunsafe_set_uint8resivdone;reslet[@inlinealways]is_power_of_twov=v<>0&&vland(lnotv+1)=vlet[@inlinealways]to_power_of_twov=letres=ref(predv)inres:=!reslor(!reslsr1);res:=!reslor(!reslsr2);res:=!reslor(!reslsr4);res:=!reslor(!reslsr8);res:=!reslor(!reslsr16);succ!resletoutput_bigstringocbufofflen=(* XXX(dinosaure): stupidly slow! *)letv=Bigarray.Array1.subbufoffleninletv=bigstring_to_stringvinoutput_stringocvletinput_bigstringicbufofflen=lettmp=Bytes.createleninletres=inputictmp0leninletlen0=resland3inletlen1=resasr2infori=0tolen1-1doleti=i*4inletv=bytes_unsafe_get_uint32tmpiinunsafe_set_uint32buf(off+i)vdone;fori=0tolen0-1doleti=len1*4+iinletv=bytes_unsafe_get_uint8tmpiinunsafe_set_uint8buf(off+i)vdone;resletinvalid_boundsofflen=invalid_arg"Out of bounds (off: %d, len: %d)"offlenletunsafe_blitsrcsrc_offdstdst_offlen=fori=0tolen-1dounsafe_set_uint8dst(dst_off+i)(unsafe_get_uint8src(src_off+i))doneletslow_blit2srcsrc_offdst0dst0_offdst1dst1_offlen=fori=0tolen-1doletv=unsafe_get_uint8src(src_off+i)inunsafe_set_uint8dst0(dst0_off+i)v;unsafe_set_uint8dst1(dst1_off+i)v;done(* XXX(dinosaure): fast blit when it's possible. *)letblit2srcsrc_offdst0dst0_offdst1dst1_offlen=ifdst0_off-src_off<4thenslow_blit2srcsrc_offdst0dst0_offdst1dst1_offlenelseletlen0=lenland3inletlen1=lenasr2infori=0tolen1-1doleti=i*4inletv=unsafe_get_uint32src(src_off+i)inunsafe_set_uint32dst0(dst0_off+i)v;unsafe_set_uint32dst1(dst1_off+i)v;done;fori=0tolen0-1doleti=len1*4+iinletv=unsafe_get_uint8src(src_off+i)inunsafe_set_uint8dst0(dst0_off+i)v;unsafe_set_uint8dst1(dst1_off+i)v;done(* XXX(dinosaure): fast fill operation. (usually when [Match (len:?, dist:1)]) *)letfill2vdst0dst0_offdst1dst1_offlen=letlen0=lenland3inletlen1=lenasr2inletnv=Nativeint.of_intvinletvv=Nativeint.(logor(shift_leftnv8)nv)inletvvvv=Nativeint.(logor(shift_leftvv16)vv)inletvvvv=Nativeint.to_int32vvvvinfori=0tolen1-1doleti=i*4inunsafe_set_uint32dst0(dst0_off+i)vvvv;unsafe_set_uint32dst1(dst1_off+i)vvvvdone;fori=0tolen0-1doleti=len1*4+iinunsafe_set_uint8dst0(dst0_off+i)v;unsafe_set_uint8dst1(dst1_off+i)vdoneletio_buffer_size=65536(* XXX(dinosaure): Specialization. *)external(<):'a->'a->bool="%lessthan"external(<=):'a->'a->bool="%lessequal"external(>=):'a->'a->bool="%greaterequal"external(>):'a->'a->bool="%greaterthan"let(>)(x:int)y=x>y[@@inline]let(<)(x:int)y=x<y[@@inline]let(<=)(x:int)y=x<=y[@@inline]let(>=)(x:int)y=x>=y[@@inline]letmin(a:int)b=ifa<=bthenaelseb[@@inline](* XXX(dinosaure): Constants. *)let_max_bits=15let_smallest=1let_rep_3_6=16let_repz_3_10=17let_repz_11_138=18let_literals=256let_length_codes=29let_l_codes=_literals+1+_length_codeslet_d_codes=30let_heap_size=2*_l_codes+1let_bl_codes=19letzigzag=[|16;17;18;0;8;7;9;6;10;5;11;4;12;3;13;2;14;1;15|]let_length=[|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|]let_distancecode=lett=[|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|]inifcode<256thent.(code)elset.(256+(codelsr7))[@@inline]let_base_length=[|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;0;0|](* assert (Array.length _base_length = 32) ;
XXX(dinosaure): in [zlib], [base_length] has 29 elements - however, it uses
the array only when it deflates something - it uses something else about
the inflation. We added two last [0] to avoid an [index out of bounds] where,
in some context, [_base_length] is used with input bits - finally, we can
mask input bits with [0x1f]. *)let_extra_lbits=[|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;0;0;0|]let_extra_dbits=[|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;0;0|](* assert (Array.length _extra_dbits = 32) ; *)let_base_dist=[|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;(-1);(-1)|](* Window for end-user. *)typewindow=bigstringletmake_window~bits=ifbits>=8&&bits<=15thenbigstring_create(1lsl15)elseinvalid_arg"bits MUST be between 8 and 15 (%d)"bitsletffsn=ifn=0theninvalid_arg"ffs on 0"else(lett=ref1inletr=ref0inwhilenland!t=0dot:=!tlsl1;incrrdone;!r)letwindow_bitsw=ffs(bigstring_lengthw)moduleLookup=struct(* Used as inflate to store lookup.[bit-sequence] = [len << 15 | byte].
Used as deflate to store lookup.[byte] = [len << 15 | bit-sequence]. *)typet={t:intarray;m:int;l:int}letmask=(1lsl_max_bits)-1letmaketm={t;m=(1lslm)-1;l=m}letgetti=letv=t.t.(i)invlsr_max_bits,vlandmask(* allocation *)[@@inline]endlet_static_ltree=[|(12,8);(140,8);(76,8);(204,8);(44,8);(172,8);(108,8);(236,8);(28,8);(156,8);(92,8);(220,8);(60,8);(188,8);(124,8);(252,8);(2,8);(130,8);(66,8);(194,8);(34,8);(162,8);(98,8);(226,8);(18,8);(146,8);(82,8);(210,8);(50,8);(178,8);(114,8);(242,8);(10,8);(138,8);(74,8);(202,8);(42,8);(170,8);(106,8);(234,8);(26,8);(154,8);(90,8);(218,8);(58,8);(186,8);(122,8);(250,8);(6,8);(134,8);(70,8);(198,8);(38,8);(166,8);(102,8);(230,8);(22,8);(150,8);(86,8);(214,8);(54,8);(182,8);(118,8);(246,8);(14,8);(142,8);(78,8);(206,8);(46,8);(174,8);(110,8);(238,8);(30,8);(158,8);(94,8);(222,8);(62,8);(190,8);(126,8);(254,8);(1,8);(129,8);(65,8);(193,8);(33,8);(161,8);(97,8);(225,8);(17,8);(145,8);(81,8);(209,8);(49,8);(177,8);(113,8);(241,8);(9,8);(137,8);(73,8);(201,8);(41,8);(169,8);(105,8);(233,8);(25,8);(153,8);(89,8);(217,8);(57,8);(185,8);(121,8);(249,8);(5,8);(133,8);(69,8);(197,8);(37,8);(165,8);(101,8);(229,8);(21,8);(149,8);(85,8);(213,8);(53,8);(181,8);(117,8);(245,8);(13,8);(141,8);(77,8);(205,8);(45,8);(173,8);(109,8);(237,8);(29,8);(157,8);(93,8);(221,8);(61,8);(189,8);(125,8);(253,8);(19,9);(275,9);(147,9);(403,9);(83,9);(339,9);(211,9);(467,9);(51,9);(307,9);(179,9);(435,9);(115,9);(371,9);(243,9);(499,9);(11,9);(267,9);(139,9);(395,9);(75,9);(331,9);(203,9);(459,9);(43,9);(299,9);(171,9);(427,9);(107,9);(363,9);(235,9);(491,9);(27,9);(283,9);(155,9);(411,9);(91,9);(347,9);(219,9);(475,9);(59,9);(315,9);(187,9);(443,9);(123,9);(379,9);(251,9);(507,9);(7,9);(263,9);(135,9);(391,9);(71,9);(327,9);(199,9);(455,9);(39,9);(295,9);(167,9);(423,9);(103,9);(359,9);(231,9);(487,9);(23,9);(279,9);(151,9);(407,9);(87,9);(343,9);(215,9);(471,9);(55,9);(311,9);(183,9);(439,9);(119,9);(375,9);(247,9);(503,9);(15,9);(271,9);(143,9);(399,9);(79,9);(335,9);(207,9);(463,9);(47,9);(303,9);(175,9);(431,9);(111,9);(367,9);(239,9);(495,9);(31,9);(287,9);(159,9);(415,9);(95,9);(351,9);(223,9);(479,9);(63,9);(319,9);(191,9);(447,9);(127,9);(383,9);(255,9);(511,9);(0,7);(64,7);(32,7);(96,7);(16,7);(80,7);(48,7);(112,7);(8,7);(72,7);(40,7);(104,7);(24,7);(88,7);(56,7);(120,7);(4,7);(68,7);(36,7);(100,7);(20,7);(84,7);(52,7);(116,7);(3,8);(131,8);(67,8);(195,8);(35,8);(163,8);(99,8);(227,8)|]let_static_ltree=lett=Array.map(fun(v,l)->(llsl_max_bits)lorv)_static_ltreeinLookup.maket9let_static_dtree=[|(0,5);(16,5);(8,5);(24,5);(4,5);(20,5);(12,5);(28,5);(2,5);(18,5);(10,5);(26,5);(6,5);(22,5);(14,5);(30,5);(1,5);(17,5);(9,5);(25,5);(5,5);(21,5);(13,5);(29,5);(3,5);(19,5);(11,5);(27,5);(7,5);(23,5)|]let_static_dtree=lett=Array.map(fun(v,l)->(llsl_max_bits)lorv)_static_dtreeinLookup.maket5(* XXX(dinosaure): [zlib] raises "Invalid distance code" where it wants to
access to [base_dist.(30|31)]. It uses a smart mask to catch this behavior.
In this code, we did not raise an error nor /compromise/ output when we fall
to [Match (len:?, dist:0)] (so, nothing to do).
Case can be retrieved with "\x02\x7e\xff\xff". NOTE: [miniz] has this silent
behavior.
XXX(dinosaure): It's not true anymore where we decide to raise an error to
avoid an other error about access on window. It's explained below when we
have a [Write] operation. *)typeoptint=Optint.t(* XXX(dinosaure): optimize [Heap]. TODO! *)moduleHeap=structtypepriority=inttype'aqueue=None|Nodeofpriority*'a*'aqueue*'aqueueletrecpushqueuepriorityelt=matchqueuewith|None->Node(priority,elt,None,None)|Node(p,e,left,right)->ifpriority<=pthenNode(priority,elt,pushrightpe,left)elseNode(p,e,pushrightpriorityelt,left)exceptionEmptyletrecremove=function|None->raise_notraceEmpty|Node(_,_,left,None)->left|Node(_,_,None,right)->right|Node(_,_,(Node(lp,le,_,_)asleft),(Node(rp,re,_,_)asright))->iflp<=rpthenNode(lp,le,removeleft,right)elseNode(rp,re,left,removeright)lettake=function|None->raise_notraceEmpty|Node(p,e,_,_)asqueue->(p,e,removequeue)endmoduleWInf=structtypet={raw:bigstring;mutablew:int;mutablec:optint}letmax=1lsl15letmask=(1lsl15)-1let[@warning"-32"]make()={raw=bigstring_createmax;w=0;c=Checkseum.Adler32.default}letfromraw={raw;w=0;c=Checkseum.Adler32.default}letresett=t.w<-0;t.c<-Checkseum.Adler32.defaultletmaskv=vlandmask[@@inline]letupdatew=letc=Checkseum.Adler32.unsafe_digest_bigstringw.raw0maxw.cinw.c<-cletaddtv=unsafe_set_uint8t.raw(maskt.w)v;ifmask(t.w+1)==0thenupdatet;t.w<-t.w+1letsubab=(-)abletcompareab=(compare:int->int->int)(subamin_int)(subbmin_int)lethavet=ifcomparet.wmax<0thent.welsemax(* XXX(dinosaure): a dragoon here. overflow can appear on [t.w] which only
increases. [compare] gives us a new chance to compare correctly [t.w] if it
overflows __one-time__. Then, for the second time, this code is broken. *)letblittww_offoo_offlen=letmsk=maskt.winletpre=max-mskinletrst=len-preinifrst>=0then(blit2ww_offt.rawmskoo_offpre;updatet;blit2w(w_off+pre)t.raw0o(o_off+pre)rst)else(blit2ww_offt.rawmskoo_offlen;ifmask(t.w+len)==0&&len>0thenupdatet);t.w<-t.w+lenletfilltvoo_offlen=letmsk=maskt.winletpre=max-mskinletrst=len-preinifrst>=0then(fill2vt.rawmskoo_offpre;updatet;fill2vt.raw0o(o_off+pre)rst)else(fill2vt.rawmskoo_offlen;ifmask(t.w+len)==0&&len>0thenupdatet);t.w<-t.w+lenlettailw=letmsk=maskw.winifmsk>0then(letc=Checkseum.Adler32.unsafe_digest_bigstringw.raw0mskw.cinw.w<-0;(* XXX(dinosaure): reset! *)w.c<-c)letchecksumw=w.cendmoduleInf=struct(* à la dbuenzli *)typesrc=[`Channelofin_channel|`Stringofstring|`Manual]typedecode=[`Await|`Flush|`End|`Malformedofstring]exceptionInvalid_huffmanletprefixheapmax=assert(max<16);(* allocation *)lettbl=Array.make(1lslmax)0inletrecbackwardhuffincr=ifhufflandincr<>0thenbackwardhuff(incrlsr1)elseincrinletrecauxhuffheap=matchHeap.takeheapwith|_,(len,value),heap->letrecloopdecrfill=tbl.(huff+fill)<-(lenlsl15)lorvalue;iffill<>0thenloopdecr(fill-decr)inletdecr=1lslleninloopdecr((1lslmax)-decr);letincr=backwardhuff(1lsl(len-1))inaux(ifincr!=0then(huffland(incr-1))+increlse0)heap|exceptionHeap.Empty->()inaux0heap;tbltypekind=CODES|LENS|DISTSletempty_table=[|1lsl_max_bits(* len: 1, val: 0 *)|],1lethuffmankindtableoffcodes=letbl_count=Array.make160inletmax=ref15inforsym=0tocodes-1doletp=table.(off+sym)inbl_count.(p)<-bl_count.(p)+1done;(* XXX(dinosaure): check if we have an incomplete set for [LENS] and [DIST].
This code is ugly, TODO! *)letexceptionBreakin(trywhile!max>=1doifbl_count.(!max)!=0thenraise_notraceBreak;decrmaxdonewithBreak->());if!max==0thenempty_tableelse(letcode=ref0inletleft=ref1inletnext_code=Array.make160infori=1to15doleft:=!leftlsl1;left:=!left-bl_count.(i);if!left<0thenraiseInvalid_huffman;code:=(!code+bl_count.(i))lsl1;next_code.(i)<-!codedone;if!left>0&&(kind=CODES||!max!=1)thenraiseInvalid_huffman;letordered=refHeap.Noneinletmax=ref0infori=0tocodes-1doletl=table.(off+i)inifl<>0then(letn=next_code.(l-1)innext_code.(l-1)<-n+1;ordered:=Heap.push!orderedn(l,i);(* allocation *)max:=ifl>!maxthenlelse!max)done;(prefix!ordered!max,!max)(* allocation *))typedecoder={src:src;mutablei:bigstring;mutablei_pos:int;mutablei_len:int;mutablehold:int;mutablebits:int;mutablelast:bool;o:bigstring;t:bigstring;mutablet_need:int;mutablet_len:int;mutableo_pos:int;mutablel:int(* literal / length *);mutabled:int(* distance *);mutableliteral:Lookup.t;mutabledistance:Lookup.t;mutablejump:jump;w:WInf.t;mutables:state;mutablek:decoder->ret}andstate=|Header|Tableof{hlit:int;hdist:int;hclen:int}|Inflate_tableof{t:intarray;l:int;r:intarray;h:int*int*int}|Inflate|Slow|Flat_header|Dynamic_header|Flat|End_of_inflateandjump=Length|Extra_length|Distance|Extra_distance|Writeandret=Await|Flush|End|K|Malformedofstringletmalformedffmt=kstrf(funs->Malformeds)fmt(* End of input [eoi] is signalled by [d.i_pos = 0] and [d.i_len = min_int]
which implies [i_rem d < 0] is [true]. *)leteoid=d.i<-bigstring_empty;d.i_pos<-0;d.i_len<-min_intletfinal_=End(* errors. *)leterr_unexpected_end_of_inputd=eoid;d.k<-final;malformedf"Unexpected end of input"leterr_invalid_kind_of_blockd=eoid;d.k<-final;malformedf"Invalid kind of block"leterr_invalid_dictionaryd=eoid;d.k<-final;malformedf"Invalid dictionary"leterr_invalid_complement_of_lengthd=eoid;d.k<-final;malformedf"Invalid complement of length"leterr_invalid_distanced=eoid;d.k<-final;malformedf"Invalid distance"leterr_invalid_distance_coded=eoid;d.k<-final;malformedf"Invalid distance code"(* remaining bytes to read [d.i]. *)leti_remd=d.i_len-d.i_pos+1[@@inline](* set [d.i] with [s]. *)letsrcdsjl=if(j<0||l<0||j+l>bigstring_lengths)theninvalid_boundsjl;if(l==0)theneoidelse(d.i<-s;d.i_pos<-j;d.i_len<-j+l-1)(* get new input in [d.i] and [k]ontinue. *)letrefillkd=matchd.srcwith|`String_->eoid;kd|`Channelic->letres=input_bigstringicd.i0(bigstring_lengthd.i)insrcdd.i0res;kd|`Manual->d.k<-k;Await(* ensure to call [k] with, at least, [n] bits available. *)letrecc_peek_bitsnkd=ifd.bits>=nthenkdelseletrem=i_remdinifrem<=0thenifrem<0(* end of input *)thenerr_unexpected_end_of_inputdelserefill(c_peek_bitsnk)d(* allocation *)else(letbyte=unsafe_get_uint8d.id.i_posind.i_pos<-d.i_pos+1;d.hold<-d.holdlor(bytelsld.bits);d.bits<-d.bits+8;ifd.bits>=nthenkdelsec_peek_bitsnkd)lett_needdn=d.t_len<-0;d.t_need<-nletrect_fillkd=letblitdlen=unsafe_blitd.id.i_posd.td.t_lenlen;d.i_pos<-d.i_pos+len;d.t_len<-d.t_len+leninletrem=i_remdinifrem<0thenkd(* TODO *)elseletneed=d.t_need-d.t_leninifrem<needthen(blitdrem;refill(t_fillk)d)else(blitdneed;d.t_need<-0;kd)letreverse_bitsbits=lett=[|0x00;0x80;0x40;0xC0;0x20;0xA0;0x60;0xE0;0x10;0x90;0x50;0xD0;0x30;0xB0;0x70;0xF0;0x08;0x88;0x48;0xC8;0x28;0xA8;0x68;0xE8;0x18;0x98;0x58;0xD8;0x38;0xB8;0x78;0xF8;0x04;0x84;0x44;0xC4;0x24;0xA4;0x64;0xE4;0x14;0x94;0x54;0xD4;0x34;0xB4;0x74;0xF4;0x0C;0x8C;0x4C;0xCC;0x2C;0xAC;0x6C;0xEC;0x1C;0x9C;0x5C;0xDC;0x3C;0xBC;0x7C;0xFC;0x02;0x82;0x42;0xC2;0x22;0xA2;0x62;0xE2;0x12;0x92;0x52;0xD2;0x32;0xB2;0x72;0xF2;0x0A;0x8A;0x4A;0xCA;0x2A;0xAA;0x6A;0xEA;0x1A;0x9A;0x5A;0xDA;0x3A;0xBA;0x7A;0xFA;0x06;0x86;0x46;0xC6;0x26;0xA6;0x66;0xE6;0x16;0x96;0x56;0xD6;0x36;0xB6;0x76;0xF6;0x0E;0x8E;0x4E;0xCE;0x2E;0xAE;0x6E;0xEE;0x1E;0x9E;0x5E;0xDE;0x3E;0xBE;0x7E;0xFE;0x01;0x81;0x41;0xC1;0x21;0xA1;0x61;0xE1;0x11;0x91;0x51;0xD1;0x31;0xB1;0x71;0xF1;0x09;0x89;0x49;0xC9;0x29;0xA9;0x69;0xE9;0x19;0x99;0x59;0xD9;0x39;0xB9;0x79;0xF9;0x05;0x85;0x45;0xC5;0x25;0xA5;0x65;0xE5;0x15;0x95;0x55;0xD5;0x35;0xB5;0x75;0xF5;0x0D;0x8D;0x4D;0xCD;0x2D;0xAD;0x6D;0xED;0x1D;0x9D;0x5D;0xDD;0x3D;0xBD;0x7D;0xFD;0x03;0x83;0x43;0xC3;0x23;0xA3;0x63;0xE3;0x13;0x93;0x53;0xD3;0x33;0xB3;0x73;0xF3;0x0B;0x8B;0x4B;0xCB;0x2B;0xAB;0x6B;0xEB;0x1B;0x9B;0x5B;0xDB;0x3B;0xBB;0x7B;0xFB;0x07;0x87;0x47;0xC7;0x27;0xA7;0x67;0xE7;0x17;0x97;0x57;0xD7;0x37;0xB7;0x77;0xF7;0x0F;0x8F;0x4F;0xCF;0x2F;0xAF;0x6F;0xEF;0x1F;0x9F;0x5F;0xDF;0x3F;0xBF;0x7F;0xFF|]int.(bits)[@@inline]letfixed_lit,fixed_dist=lettbl_lit=Array.init288@@funn->ifn<144then8elseifn<256then9elseifn<280then7else8inlettbl_dist=letres=Array.make(1lsl5)0inArray.iteri(funi_->res.(i)<-(5lsl15)lorreverse_bits(ilsl3))res;resinlettbl_lit,max_lit=huffmanLENStbl_lit0288inLookup.maketbl_litmax_lit,Lookup.maketbl_dist5letchecksumd=WInf.checksumd.wletrecflatd=letlen=min(min(i_remd)d.l)(bigstring_lengthd.o-d.o_pos)inWInf.blitd.wd.id.i_posd.od.o_poslen;d.o_pos<-d.o_pos+len;d.i_pos<-d.i_pos+len;d.l<-d.l-len;ifd.l==0then(ifd.lastthen(d.s<-End_of_inflate;K)else(d.s<-Header;K))elsematchi_remd,bigstring_lengthd.o-d.o_poswith|0,_->(matchd.srcwith|`String_->eoid;err_unexpected_end_of_inputd|`Channelic->letlen=input_bigstringicd.i0(bigstring_lengthd.i)insrcdd.i0len;flatd(* XXX(dinosaure): check this branch. TODO! *)|`Manual->Await)|_,0->Flush|_,_->assertfalseletflat_headerd=letkd=lett_pos=ref0inlethold=refd.holdinletbits=refd.bitsinletlen=ref0andnlen=ref0xffffinletconsume()=if!bits<8then(hold:=((unsafe_get_uint8d.t!t_pos)lsl!bits)lor!hold;bits:=!bits+8;incrt_pos)inconsume();len:=!holdland0xff;hold:=!holdasr8;bits:=!bits-8;consume();len:=((!holdland0xff)lsl8)lor!len;hold:=!holdasr8;bits:=!bits-8;consume();nlen:=!holdland0xff;hold:=!holdasr8;bits:=!bits-8;consume();nlen:=((!holdland0xff)lsl8)lor!nlen;hold:=!holdasr8;bits:=!bits-8;if!nlen!=0xffff-!lenthenerr_invalid_complement_of_lengthdelse(d.hold<-0;d.bits<-0;d.l<-!len;d.s<-Flat;flatd)ind.hold<-d.holdasr(d.bitsland7);(* XXX(cfcs): diff between [d.bits] and [d.bits round down to nearest multiple of 8]. *)lettruncated_bits=d.bitsland(lnot7)in(* XXX(cfcs): round down to nearest multiple of 8, logical equivalents:
d.bits land (lnot (8 - 1))
d.bits land (lnot 7)
For some reason saving this variable locally instead of accessing [d.bits] twice
shaves off one instruction when compiling with [flambda]. *)d.bits<-truncated_bits;letrequired=4-(truncated_bitsasr3)ind.s<-Flat_header;t_needdrequired;t_fillkdletrecc_put_bytebytekd=ifd.o_pos<bigstring_lengthd.othen(unsafe_set_uint8d.od.o_posbyte;WInf.addd.wbyte;d.o_pos<-d.o_pos+1;kd)else(d.k<-c_put_bytebytek(* allocation *);Flush)let[@inlinealways]is_end_of_blocklitd=letrem=i_remdinlit.Lookup.t.(d.holdlandlit.Lookup.m)landLookup.mask==256&&lit.Lookup.t.(d.holdlandlit.Lookup.m)lsr15<=d.bits&&rem<1letslow_inflatelitdistjumpd=letrecc_peek_bitsnkd=ifd.bits>=nthenkdelseletrem=i_remdinifrem<=0thenifrem<0(* end of input *)thenerr_unexpected_end_of_inputdelserefill(c_peek_bitsnk)d(* allocation *)else(letbyte=unsafe_get_uint8d.id.i_posind.i_pos<-d.i_pos+1;d.hold<-d.holdlor(bytelsld.bits);d.bits<-d.bits+8;ifd.bits>=n||is_end_of_blocklitdthenkdelsec_peek_bitsnkd)inmatchjumpwith|Length->letkd=letvalue=lit.Lookup.t.(d.holdlandlit.Lookup.m)landLookup.maskinletlen=lit.Lookup.t.(d.holdlandlit.Lookup.m)lsr15ind.hold<-d.holdlsrlen;d.bits<-d.bits-len;ifvalue<256thenletkd=d.s<-Inflate;(* allocation *)Kinc_put_bytevaluekdelseifvalue==256then(ifd.lastthen(d.s<-End_of_inflate;K)(* XXX(dinosaure): [K] is needed here to save remaining byte(s) correctly
in [End_of_inflate] state. *)else(d.s<-Header;K))else(d.l<-value-257;d.jump<-Extra_length;d.s<-Inflate(* allocation *);K)in(* XXX(dinosaure): this is necessary where [EOB] is not necessary the
longest code. So we can occur the case where we are at the end of the
input and have the [EOB] code, but not enough to have [lit.Lookup.l]
bits:
- previously, we just ask more input
- now, we check if [d.hold] is [EOB]: assumption, codes are prefix free
AND we reach end of input.
TODO: optimize this branch! *)ifis_end_of_blocklitdthenkdelsec_peek_bitslit.Lookup.lkd|Extra_length->letlen=_extra_lbits.(d.l)inletkd=letextra=d.holdland((1lsllen)-1)ind.hold<-d.holdlsrlen;d.bits<-d.bits-len;d.l<-_base_length.(d.lland0x1f)+3+extra;d.jump<-Distance;d.s<-Inflate;(* allocation *)Kinc_peek_bitslenkd|Distance->letkd=letvalue=dist.Lookup.t.(d.holdlanddist.Lookup.m)landLookup.maskinletlen=dist.Lookup.t.(d.holdlanddist.Lookup.m)lsr15ind.hold<-d.holdlsrlen;d.bits<-d.bits-len;d.d<-value;d.jump<-Extra_distance;d.s<-Inflate;(* allocation *)Kinc_peek_bitsdist.Lookup.lkd|Extra_distance->letlen=_extra_dbits.(d.dland0x1f)inletkd=letextra=d.holdland((1lsllen)-1)ind.hold<-d.holdlsrlen;d.bits<-d.bits-len;d.d<-_base_dist.(d.d)+1+extra;d.jump<-Write;d.s<-Inflate;(* allocation *)Kinc_peek_bitslenkd|Write->ifd.d==0thenerr_invalid_distance_codedelseifd.d>WInf.haved.wthenerr_invalid_distancedelseletlen=mind.l(bigstring_lengthd.o-d.o_pos)inletoff=WInf.mask(d.w.WInf.w-d.d)inletpre=WInf.max-offinletrst=len-preinifrst>0then(WInf.blitd.wd.w.WInf.rawoffd.od.o_pospre;WInf.blitd.wd.w.WInf.raw0d.o(d.o_pos+pre)rst)elseWInf.blitd.wd.w.WInf.rawoffd.od.o_poslen;d.o_pos<-d.o_pos+len;ifd.l-len==0then(d.jump<-Length;d.s<-Inflate(* allocation *);K)else(d.l<-d.l-len;d.s<-Inflate(* allocation *);Flush)letinflatelitdistjumpd=letexceptionEndinletexceptionInvalid_distanceinletexceptionInvalid_distance_codeinlethold=ref(Nativeint.of_intd.hold)inletbits=refd.bitsinletjump=refjumpinleti_pos=refd.i_posinleto_pos=refd.o_posinletlit_mask=Nativeint.of_intlit.Lookup.minletdist_mask=Nativeint.of_intdist.Lookup.min(* XXX(dinosaure): 2 jumps were done in this hot-loop:
1- [while],
2- [match .. with]).
A [let rec length = .. and extra_length = ..] can be optimized by
[flambda]. We should replace [match .. with] by this design. TODO. *)trywhiled.i_len-!i_pos+1>1&&!o_pos<bigstring_lengthd.odomatch!jumpwith|Length->if!bits<lit.Lookup.lthen(hold:=Nativeint.logor!holdNativeint.(shift_left(of_int(unsafe_get_uint8d.i!i_pos))!bits);bits:=!bits+8;incri_pos;hold:=Nativeint.logor!holdNativeint.(shift_left(of_int(unsafe_get_uint8d.i!i_pos))!bits);bits:=!bits+8;incri_pos);letvalue=lit.Lookup.t.(Nativeint.(to_int(logand!holdlit_mask)))landLookup.maskinletlen=lit.Lookup.t.(Nativeint.(to_int(logand!holdlit_mask)))lsr15inhold:=Nativeint.shift_right_logical!holdlen;bits:=!bits-len;ifvalue<256then(unsafe_set_uint8d.o!o_posvalue;WInf.addd.wvalue;incro_pos(* ; jump := Length *))elseifvalue==256thenraise_notraceEndelse(jump:=Extra_length;d.l<-value-257)|Extra_length->letlen=_extra_lbits.(d.l)inif!bits<lenthen(hold:=Nativeint.logor!holdNativeint.(shift_left(of_int(unsafe_get_uint8d.i!i_pos))!bits);bits:=!bits+8;incri_pos);letextra=Nativeint.(to_int(logand!hold(sub(shift_left1nlen)1n)))inhold:=Nativeint.shift_right_logical!holdlen;bits:=!bits-len;d.l<-_base_length.(d.lland0x1f)+3+extra;jump:=Distance|Distance->if!bits<dist.Lookup.lthen(hold:=Nativeint.logor!holdNativeint.(shift_left(of_int(unsafe_get_uint8d.i!i_pos))!bits);bits:=!bits+8;incri_pos;hold:=Nativeint.logor!holdNativeint.(shift_left(of_int(unsafe_get_uint8d.i!i_pos))!bits);bits:=!bits+8;incri_pos);letvalue=dist.Lookup.t.(Nativeint.(to_int(logand!holddist_mask)))landLookup.maskinletlen=dist.Lookup.t.(Nativeint.(to_int(logand!holddist_mask)))lsr15inhold:=Nativeint.shift_right_logical!holdlen;bits:=!bits-len;d.d<-value;jump:=Extra_distance|Extra_distance->letlen=_extra_dbits.(d.dland0x1f)inif!bits<lenthen(hold:=Nativeint.logor!holdNativeint.(shift_left(of_int(unsafe_get_uint8d.i!i_pos))!bits);bits:=!bits+8;incri_pos;hold:=Nativeint.logor!holdNativeint.(shift_left(of_int(unsafe_get_uint8d.i!i_pos))!bits);bits:=!bits+8;incri_pos);letextra=Nativeint.(to_int(logand!hold(sub(shift_left1nlen)1n)))inhold:=Nativeint.shift_right_logical!holdlen;bits:=!bits-len;d.d<-_base_dist.(d.d)+1+extra;jump:=Write|Write->ifd.d==0thenraise_notraceInvalid_distance_code;ifd.d>WInf.haved.wthenraise_notraceInvalid_distance;(* if d.d > WInf.have d.w then raise Invalid_distance ;
XXX(dinosaure): [WInf.have] does not tell me the truth where
we need a read cursor in [WInf.t] for that. *)letlen=mind.l(bigstring_lengthd.o-!o_pos)inletoff=WInf.mask(d.w.WInf.w-d.d)inifd.d==1then(letv=unsafe_get_uint8d.w.WInf.rawoffinWInf.filld.wvd.o!o_poslen)else(letoff=WInf.mask(d.w.WInf.w-d.d)inletpre=WInf.max-offinletrst=len-preinifrst>0then(WInf.blitd.wd.w.WInf.rawoffd.o!o_pospre;WInf.blitd.wd.w.WInf.raw0d.o(!o_pos+pre)rst)elseWInf.blitd.wd.w.WInf.rawoffd.o!o_poslen);o_pos:=!o_pos+len;ifd.l-len==0thenjump:=Lengthelsed.l<-d.l-lendone;d.hold<-Nativeint.to_int!hold;d.bits<-!bits;d.i_pos<-!i_pos;d.o_pos<-!o_pos;d.jump<-!jump;d.k<-slow_inflatelitdist!jump;(* allocation *)d.s<-Slow;ifi_remd>0then(ifd.o_pos==bigstring_lengthd.othenFlushelseK)else(matchd.srcwith|`String_->eoid;K(* XXX(dinosaure): [K] is required here mostly because the semantic
of the hot-loop. If we reach end of input, we may have some
trailing bits in [d.hold] and we need to process them.
[slow_inflate] is more precise (but... slow) and will consume
them to reach [End_of_inflate] then correctly. *)|`Channelic->letlen=input_bigstringicd.i0(bigstring_lengthd.i)insrcdd.i0len;K(* XXX(dinosaure): should work fine! But it
needs check. *)|`Manual->K)withEnd->d.hold<-Nativeint.to_int!hold;d.bits<-!bits;d.i_pos<-!i_pos;d.o_pos<-!o_pos;ifd.lastthen(d.s<-End_of_inflate;K)(* XXX(dinosaure): [K] is needed here to save remaining byte(s) correctly
in [End_of_inflate] state. *)else(d.s<-Header;K)|Invalid_distance->err_invalid_distanced|Invalid_distance_code->err_invalid_distance_codedletfixedd=letlit,dist=fixed_lit,fixed_distind.literal<-lit;d.distance<-dist;d.jump<-Length;d.s<-Inflate;(* allocation *)inflatelitdistLengthd(* XXX(dinosaure): [huffman] can raise an exception. *)letmake_tablethlithdistd=tryift.(256)==0then(raise_notraceInvalid_huffman);(* XXX(dinosaure): an huffman tree MUST have at least an End-Of-Block
symbol. *)lett_lit,l_lit=huffmanLENSt0hlitinlett_dist,l_dist=huffmanDISTSthlithdistinletlit=Lookup.maket_litl_litinletdist=Lookup.maket_distl_distind.literal<-lit;d.distance<-dist;d.jump<-Length;d.s<-Inflate;(* allocation *)inflatelitdistLengthdwithInvalid_huffman->err_invalid_dictionarydletinflate_tabled=let[@warning"-8"]Inflate_table{t;l=max_bits;r=res;h=(hlit,hdist,_)}=d.sinletmax_res=hlit+hdistinletmask=(1lslmax_bits)-1inletgetkd=letlen,v=t.(d.holdlandmask)lsr15,t.(d.holdlandmask)land((1lsl15)-1)ind.hold<-d.holdlsrlen;d.bits<-d.bits-len;kvdinletgetkd=c_peek_bitsmax_bits(getk)dinletget_bitsnkd=letkd=letv=d.holdland((1lsln)-1)ind.hold<-d.holdlsrn;d.bits<-d.bits-n;kvdinc_peek_bitsnkdinletretrd=make_tablerhlithdistdin(* XXX(dinosaure): [prv] and [i] are stored as associated env of [go]. We
can not retake them from [d.s]. *)letrecrecordicopylend=ifi+copy>max_resthen(err_invalid_dictionaryd)else(forx=0tocopy-1dores.(i+x)<-lendone;ifi+copy<max_resthenget(fund->go(i+copy)d)delseretresd)andgoivd=ifv<16then(res.(i)<-v;ifsucci<max_resthenget(fund->go(succi)d)delseretresd)elseifv==16then(letkvd=recordi(v+3)res.(i-1)dinifi==0then(err_invalid_dictionaryd)elseget_bits2kd)elseifv==17then(letkvd=recordi(v+3)0dinget_bits3kd)elseifv==18then(letkvd=recordi(v+11)0dinget_bits7kd)elseassertfalse(* TODO: really never occur? *)inletkvd=go0vdingetkd(* XXX(dinosaure): previous design asks to load [hclen * 3] bits, however, in
a specific context, it can oveflow [hold]. So new design is to ensure to
have enough bytes to inflate huffman tree. *)lettabled=let[@warning"-8"]Table{hlit;hdist;hclen;}=d.sinlethold=refd.holdinletbits=refd.bitsinlett_pos=ref0inleti=ref0inletres=Array.make190inwhile!i<hclendoif!bits<3then(hold:=!holdlor(unsafe_get_uint8d.t!t_poslsl!bits);bits:=!bits+8;incrt_pos);letcode=!holdland0x7inres.(zigzag.(!i))<-code;hold:=!holdlsr3;bits:=!bits-3;incri;done;trylett,l=huffmanCODESres019ind.hold<-!hold;d.bits<-!bits;(* assert (!t_pos == d.t_len) ; *)d.t_len<-0;d.t_need<-0;d.s<-Inflate_table{t;l;r=Array.make(hlit+hdist)0;h=(hlit,hdist,hclen)};inflate_tabledwithInvalid_huffman->err_invalid_dictionarydlet(//)xy=ify<0thenraiseDivision_by_zeroelse(ifx>0then1+((x-1)/y)else0)[@@inline]letdynamicd=letl_headerd=lett_pos=ref0inwhiled.t_len>0dod.hold<-d.holdlor(unsafe_get_uint8d.t!t_poslsld.bits);d.bits<-d.bits+8;incrt_pos;d.t_len<-d.t_len-1;done;lethlit=(d.holdland0x1f)+257inlethdist=((d.holdland0x3e0)lsr5)+1inlethclen=((d.holdland0x3c00)lsr10)+4ind.s<-Table{hlit;hdist;hclen;};d.hold<-d.holdlsr14;d.bits<-d.bits-14;(* XXX(dinosaure): we ensure to have enough bytes to start to inflate
huffman tree. *)letkd=letrem=i_remdinifrem<0thenerr_unexpected_end_of_inputdelse(t_needd((hclen*3-d.bits)//8);t_filltabled)inkdinletrequired=(14-d.bits)//8ind.s<-Dynamic_header;t_needdrequired;t_filll_headerdletdecode_kd=matchd.swith|Header->(* XXX(dinosaure): check this code, we should need a [k]ontinuation. *)letl_headerd=assert(d.bits>=3);(* allocation *)letlast=d.holdland1==1inletk=match(d.holdland0x6)asr1with|0->flat_header|1->fixed|2->dynamic|3->err_invalid_kind_of_block|_->assertfalseind.last<-last;d.hold<-d.holdlsr3;d.bits<-d.bits-3;d.k<-k;kdinc_peek_bits3l_headerd|Table_->t_filltabled;|Inflate_table_->d.kd|Inflate->ifi_remd>1theninflated.literald.distanced.jumpdelse(d.s<-Slow;slow_inflated.literald.distanced.jumpd)|Slow->d.kd|Dynamic_header->d.kd|Flat_header->d.kd|Flat->flatd|End_of_inflate->WInf.taild.w;ifd.bits>=8then(d.i_pos<-d.i_pos-1;d.bits<-d.bits-8;d.hold<-0(* XXX(dinosaure): keep? *));Endletrecdecoded=matchdecode_kdwith|Await->`Await|Flush->`Flush|End->`End|Malformederr->`Malformederr|K->decodedletdst_remd=bigstring_lengthd.o-d.o_pos(* TODO: why [+1] disappears? *)letsrc_remd=i_remdletflushd=d.o_pos<-0letdecodersrc~o~w=leti,i_pos,i_len=matchsrcwith|`Manual->bigstring_empty,1,0|`Stringx->bigstring_of_stringx,0,String.lengthx-1|`Channel_->bigstring_createio_buffer_size,1,0in{src;i;i_pos;i_len;o;o_pos=0;t=bigstring_create10;t_need=0;t_len=0;hold=0;bits=0;last=false;l=0;d=0;literal=fixed_lit;distance=fixed_dist;jump=Length;w=WInf.fromw;s=Header;k=decode_k}letresetd=leti,i_pos,i_len=matchd.srcwith|`Manual->bigstring_empty,1,0|`Stringx->bigstring_of_stringx,0,String.lengthx-1|`Channel_->bigstring_createio_buffer_size,1,0ind.i<-i;d.i_pos<-i_pos;d.i_len<-i_len;d.hold<-0;d.bits<-0;d.last<-false;d.o_pos<-0;d.l<-0;d.d<-0;d.literal<-fixed_lit;d.distance<-fixed_dist;d.jump<-Length;d.s<-Header;d.k<-decode_k;WInf.resetd.wendletunsafe_set_cursordc=d.Inf.w.WInf.w<-cmoduleT=structmoduleHeap=structtypet={heap:intarray;mutablelen:int;mutablemax:int}letmake()={heap=Array.make_heap_size0;len=0;max=_heap_size}letpopulate~length~freqstree_lengths~depthheap=(* assert (Array.length tree_lengths = Array.length freqs) ;
assert (Array.length depth = heap.max) ;
assert (Array.length heap.heap = heap.max) ;
assert (heap.max = _heap_size) ;
*)letmax_code=ref(-1)in(* Construct the initial heap, with least frequent element in
heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
heap[0] is not used. *)forn=0tolength-1doiffreqs.(n)<>0then(heap.len<-heap.len+1;heap.heap.(heap.len)<-n;max_code:=n;depth.(n)<-0)elsetree_lengths.(n)<-0(* XXX(dinosaure): we consider that [tree_lengths] can have bad
informations, so we clean it. However, it was initialized with [0] in
[T.make] builder. *)done;!max_code(* The pkzip format requires that at least one distance code exists,
and that at least one bit should be sent even if there is only one
possible code. So to avoid special checks later on we force at least
two codes of non zero frequency. *)letpkzipmax_code~freqs~depthheap=letmax_code=refmax_codeinwhileheap.len<2doletnode=if!max_code<2then(incrmax_code;!max_code)else0infreqs.(node)<-1;heap.len<-heap.len+1;heap.heap.(heap.len)<-node;depth.(node)<-0;done;!max_codelet[@inline]smallerfreqsnmdepth=(freqs.(n)<freqs.(m)||(freqs.(n)=freqs.(m)&&depth.(n)<=depth.(m)))letpqdownheap~freqs~depthheapk=letexceptionBreakinletv=heap.heap.(k)inletj=ref(klsl1)inletk=refkin(trywhile!j<=heap.lendoif!j<heap.len&&smallerfreqsheap.heap.(!j+1)heap.heap.(!j)depththenincrj;ifsmallerfreqsvheap.heap.(!j)depththenraise_notraceBreak;heap.heap.(!k)<-heap.heap.(!j);k:=!j;j:=!jlsl1;donewithBreak->());heap.heap.(!k)<-vletpqremove~freqs~depthheap=lettop=heap.heap.(_smallest)inheap.heap.(_smallest)<-heap.heap.(heap.len);heap.len<-heap.len-1;pqdownheap~freqs~depthheap_smallest;topend(* Reverse the first len bits of a code, using a straightforward code
(a faster method would use a table). *)letreverse_codecodelen=(* assert (1 <= len && len <= 15); *)letres=ref0inletlen=refleninletcode=refcodeinwhileres:=!reslor(!codeland1);code:=!codeasr1;res:=!reslsl1;decrlen;!len>0do()done;!resasr1letgenerate_codes~tree_lengths~max_code~bl_count=lettree_codes=Array.make(Array.lengthtree_lengths)0inletnext_code=Array.make(_max_bits+1)0inletcode=ref0in(* The distribution counts are fist used to generate the code values without
bit reversal. *)forbits=1to_max_bitsdocode:=(!code+bl_count.(bits-1))lsl1;next_code.(bits)<-(!codeland0xffff);done;(* check that the bit counts in [bl_count] are consistent. The last code
must be all ones. *)assert(!code+bl_count.(_max_bits)-1=(1lsl_max_bits)-1);forn=0tomax_codedoletlen=tree_lengths.(n)iniflen>0then(* Now reverse the bits. *)(tree_codes.(n)<-reverse_codenext_code.(len)len;next_code.(len)<-next_code.(len)+1)done;tree_codesletgenerate_lengths~tree_dads~tree_lengths~max_code~max_lengthheap~bl_count=(* assert (Array.length bl_count = _max_bits + 1) ;
assert (Array.for_all ((=) 0) bl_count) ;
*)(* In a first pass, compute the optimal bit lengths (which may overflow in
the case of the bit length tree). *)tree_lengths.(heap.Heap.heap.(heap.max))<-0;(* root of the heap. *)letoverflow=ref0inArray.fillbl_count0(Array.lengthbl_count)0;forh=heap.max+1to_heap_size-1doletn=heap.heap.(h)inletbits=tree_lengths.(tree_dads.(n))+1inletbits=ifbits>max_lengththen(incroverflow;max_length)elsebitsintree_lengths.(n)<-bits;ifn<=max_code(* XXX(dinosaure): it's a leaf. *)then(bl_count.(bits)<-bl_count.(bits)+1)done;if!overflow!=0(* This happends for example on obj2 and pic of the
Calgary corpus. *)then(letrecgo()=letbits=ref(max_length-1)inwhilebl_count.(!bits)==0dodecrbitsdone;bl_count.(!bits)<-bl_count.(!bits)-1;bl_count.(!bits+1)<-bl_count.(!bits+1)+2;bl_count.(max_length)<-bl_count.(max_length)-1;overflow:=!overflow-2;if!overflow>0thengo()ingo();leth=ref_heap_sizeinforbits=max_lengthdownto1doletn=refbl_count.(bits)inwhile!n!=0dodecrh;letm=heap.heap.(!h)inifm<=max_codethen(iftree_lengths.(m)<>bitsthen(tree_lengths.(m)<-bits);decrn)donedone)typetree={lengths:intarray;max_code:int;tree:Lookup.t}letmake~length?(max_length=_max_bits)freqs~bl_count=letheap=Heap.make()inletdepth=Array.make(2*_l_codes+1)0inlettree_dads=Array.make_heap_size0inlettree_lengths=Array.make_heap_size0inletmax_code=Heap.populate~length~freqs~depthtree_lengthsheapinletmax_code=Heap.pkzipmax_code~freqs~depthheapinforn=heap.len/2downto1doHeap.pqdownheap~freqs~depthheapndone;letnode=reflengthinletrecgo()=letn=Heap.pqremove~freqs~depthheapinletm=heap.heap.(_smallest)inheap.max<-heap.max-1;heap.heap.(heap.max)<-n;heap.max<-heap.max-1;heap.heap.(heap.max)<-m;freqs.(!node)<-freqs.(n)+freqs.(m);depth.(!node)<-(ifdepth.(n)>=depth.(m)thendepth.(n)elsedepth.(m))+1;tree_dads.(n)<-!node;tree_dads.(m)<-!node;heap.heap.(_smallest)<-!node;incrnode;Heap.pqdownheap~freqs~depthheap_smallest;ifheap.len>=2thengo()else(heap.max<-heap.max-1;heap.heap.(heap.max)<-heap.heap.(_smallest))ingo();generate_lengths~tree_dads~tree_lengths~max_code~max_lengthheap~bl_count;lettree_codes=generate_codes~tree_lengths~max_code~bl_countinletlength=ref0inlettree=Array.map2(funlencode->length:=max!lengthlen;((lenlsl_max_bits)lorcode))tree_lengthstree_codesin{lengths=tree_lengths;max_code;tree={Lookup.t=tree;m=(1lsl!length)-1;l=!length}}letscantree_lengthsmax_code~bl_freqs=letprevlen=ref(-1)inletnextlen=reftree_lengths.(0)inletcurlen=ref!nextleninletcount=ref0inletmax_count=ref7inletmin_count=ref4inletexceptionContinueinif!nextlen=0then(max_count:=138;min_count:=3);tree_lengths.(max_code+1)<-0xffff;forn=0tomax_codedocurlen:=!nextlen;nextlen:=tree_lengths.(n+1);incrcount;tryif!count<!max_count&&!curlen==!nextlenthenraise_notraceContinueelseif!count<!min_countthenbl_freqs.(!curlen)<-bl_freqs.(!curlen)+!countelseif!curlen!=0then(if!curlen!=!prevlenthenbl_freqs.(!curlen)<-bl_freqs.(!curlen)+1;bl_freqs.(_rep_3_6)<-bl_freqs.(_rep_3_6)+1)elseif!count<=10thenbl_freqs.(_repz_3_10)<-bl_freqs.(_repz_3_10)+1elsebl_freqs.(_repz_11_138)<-bl_freqs.(_repz_11_138)+1;count:=0;prevlen:=!curlen;if!nextlen==0then(max_count:=138;min_count:=3)elseif!curlen=!nextlenthen(max_count:=6;min_count:=3)else(max_count:=7;min_count:=4)withContinue->()doneletcodecodelookup=lookup.Lookup.t.(code)letbitscodelen=(lenlsl_max_bits)lorcodeletsymbolsitree_lengthsmax_code~bl_symbols~bltree=leti=refiinletprevlen=ref(-1)inletnextlen=reftree_lengths.(0)inletcurlen=ref!nextleninletcount=ref0inletmax_count=ref7inletmin_count=ref4inletexceptionContinueinif!nextlen=0then(max_count:=138;min_count:=3);forn=0tomax_codedocurlen:=!nextlen;nextlen:=tree_lengths.(n+1);incrcount;tryif!count<!max_count&&!curlen==!nextlenthenraise_notraceContinueelseif!count<!min_countthenwhilebl_symbols.(!i)<-code!curlenbltree.tree;incri;decrcount;!count!=0do()doneelseif!curlen!=0then(if!curlen!=!prevlenthen(bl_symbols.(!i)<-code!curlenbltree.tree;incri;decrcount);bl_symbols.(!i)<-code_rep_3_6bltree.tree;incri;bl_symbols.(!i)<-bits(!count-3)2;incri)elseif!count<=10then(bl_symbols.(!i)<-code_repz_3_10bltree.tree;incri;bl_symbols.(!i)<-bits(!count-3)3;incri)else(bl_symbols.(!i)<-code_repz_11_138bltree.tree;incri;bl_symbols.(!i)<-bits(!count-11)7;incri);count:=0;prevlen:=!curlen;if!nextlen==0then(max_count:=138;min_count:=3)elseif!curlen==!nextlenthen(max_count:=6;min_count:=3)else(max_count:=7;min_count:=4)withContinue->()done;!iendmoduleQueue=structtypecmd=inttypebuf=(cmd,Bigarray.int_elt,Bigarray.c_layout)Bigarray.Array1.ttypet={buf:buf;mutablew:int;mutabler:int;mutablec:int}letmasktv=vland(t.c-1)letemptyt=t.r=t.wletsizet=t.w-t.rletavailablet=t.c-(t.w-t.r)letfullt=sizet=t.cletlengtht=sizetletis_emptyt=emptytletis_fullt=fulltexternalunsafe_get:buf->int->int="%caml_ba_ref_1"externalunsafe_set:buf->int->int->unit="%caml_ba_set_1"exceptionFullexceptionEmptyletpush_exntv=if(full[@inlined])tthenraiseFull;unsafe_sett.buf((mask[@inlined])tt.w)v;t.w<-t.w+1letpop_exnt=if(empty[@inlined])tthenraiseEmpty;letr=unsafe_gett.buf((mask[@inlined])tt.r)int.r<-t.r+1;rletpeek_exnt=if(empty[@inlined])tthenraiseEmpty;unsafe_gett.buf((mask[@inlined])tt.r)letunsafe_junkt=t.r<-t.r+1letjunk_exntn=if(size[@inlined])t<ntheninvalid_arg"You want to junk more than what we have";t.r<-t.r+nletcopy~off~len:cmd=assert(len>=3&&len<=255+3);assert(off>=1&&off<=32767+1);((len-3)lsl16)lor(off-1)lor0x2000000[@@inline]letliteralchr=Char.codechr[@@inline]leteob=256letcmd=function|`Literalchr->literalchr|`Copy(off,len)->copy~off~len|`End->256letcodecmd=matchcmdland0x2000000<>0with|false->ifcmd==256then`Endelse`Literal(Char.chr(cmdland0xff))|true->letoff=(cmdland0xffff)+1inletlen=((cmdlsr16)land0x1ff)+3in(* XXX(dinosaure): ((1 lsl 9) - 1) - 0xff *)`Copy(off,len)letblittbufofflen=ifavailablet<lenthenraiseFull;letmsk=masktt.winletpre=t.c-mskinletrst=len-preinifrst>0then(fori=0topre-1dounsafe_sett.buf(msk+i)(unsafe_get_uint8buf(off+i))done;fori=0torst-1dounsafe_sett.bufi(unsafe_get_uint8buf(off+pre+i))done)elsefori=0tolen-1dounsafe_sett.buf(msk+i)(unsafe_get_uint8buf(off+i))done;t.w<-t.w+lenletcreatelength=ifnot(is_power_of_twolength)theninvalid_arg"Length of queue MUST be a power of two";{buf=Bigarray.Array1.createBigarray.intBigarray.c_layoutlength;w=0;r=0;c=length}letresett=t.w<-0;t.r<-0letto_listt=letres=ref[]inletlen=sizetinletmsk=masktt.rinletpre=t.c-mskinletrst=len-preinifrst>0then(fori=0topre-1dores:=code(unsafe_gett.bufi)::!resdone;fori=0torst-1dores:=code(unsafe_gett.bufi)::!resdone)elsefori=0tolen-1dores:=code(unsafe_gett.bufi)::!resdone;List.rev!reslet(<.>)fg=funx->f(gx)letof_listlst=letq=create(to_power_of_two(List.lengthlst))inList.iter(push_exnq<.>cmd)lst;qendtypeliterals=intarraytypedistances=intarrayletmake_literals()=letres=Array.make(2*_l_codes+1)0inres.(256)<-1;resletsucc_literalliteralschr=literals.(Char.codechr)<-literals.(Char.codechr)+1letsucc_lengthliteralslength=assert(length>=3&&length<=255+3);literals.(256+1+_length.(length-3))<-literals.(256+1+_length.(length-3))+1letmake_distances()=Array.make(2*_d_codes+1)0letsucc_distancedistancesdistance=assert(distance>=1&&distance<=32767+1);distances.(_distance(preddistance))<-distances.(_distance(preddistance))+1moduleDef=structtypedst=[`Channelofout_channel|`BufferofBuffer.t|`Manual]typedynamic={ltree:T.tree;dtree:T.tree;bltree:T.tree;h_lit:int;h_dst:int;h_len:int;symbols:intarray}letbl_treeltreedtree~bl_count=letbl_freqs=Array.make(2*_bl_codes+1)0inT.scanltree.T.lengthsltree.T.max_code~bl_freqs;T.scandtree.T.lengthsdtree.T.max_code~bl_freqs;letbltree=T.make~length:_bl_codes~max_length:7bl_freqs~bl_countin(* XXX(dinosaure): [T.make] needs [max_length] to avoid generation of a bad
bltree (limited to 7 bits with extra). *)letmax_blindex=ref(_bl_codes-1)inletexceptionBreakin(trywhile!max_blindex>=3doifbltree.T.lengths.(zigzag.(!max_blindex))<>0thenraise_notraceBreak;decrmax_blindexdonewithBreak->());!max_blindex,bltreeletdynamic_of_frequencies:literals:intarray->distances:intarray->dynamic=fun~literals:lit_freqs~distances:dst_freqs->letbl_count=Array.make(_max_bits+1)0inletltree=T.make~length:_l_codeslit_freqs~bl_countinletdtree=T.make~length:_d_codesdst_freqs~bl_countinletmax_blindex,bltree=bl_treeltreedtree~bl_countinletbl_symbols=Array.make(_l_codes+_d_codes)0inleti=T.symbols0ltree.T.lengthsltree.T.max_code~bltree~bl_symbolsinleti=T.symbolsidtree.T.lengthsdtree.T.max_code~bltree~bl_symbolsinletbl_symbols=Array.subbl_symbols0iin{h_lit=ltree.T.max_code+1;h_dst=dtree.T.max_code+1;h_len=max_blindex+1;bltree;ltree;dtree;symbols=bl_symbols}letinvalid_encode()=invalid_arg"expected `Await encode"typekind=Flatofint|Fixed|Dynamicofdynamictypeblock={kind:kind;last:bool;}typeencode=[`Await|`Flush|`Blockofblock]letexistsvblock=matchv,block.kindwith|(`Copy_|`End),Flat_->invalid_arg"copy code in flat block can not exist"|`Literalchr,Dynamicdynamic->dynamic.ltree.T.tree.Lookup.t.(Char.codechr)lsr_max_bits>0|`Copy(off,len),Dynamicdynamic->(* assert (len >= 3 && len <= 255 + 3) ; *)(* assert (off >= 1 && off <= 32767 + 1) ; *)dynamic.ltree.T.tree.Lookup.t.(256+1+_length.(len-3))lsr_max_bits>0&&dynamic.dtree.T.tree.Lookup.t.(_distance(predoff))lsr_max_bits>0|`End,(Fixed|Dynamic_)|`Literal_,(Flat_|Fixed)|`Copy_,Fixed->truetypeencoder={dst:dst;mutableblk:block;mutablehold:int;mutablebits:int;mutablebits_rem:[`Remofint|`Pending];mutableflat:int;mutableo:bigstring;mutableo_pos:int;mutableo_max:int;b:Queue.t;mutablek:encoder->encode->[`Ok|`Partial|`Block]}(* remaining bytes to write in [e.o]. *)leto_reme=e.o_max-e.o_pos+1[@@inline](* set [e.o] with [s]. *)letdstesjl=if(j<0||l<0||j+l>bigstring_lengths)theninvalid_boundsjl;e.o<-s;e.o_pos<-j;e.o_max<-j+l-1letpartialke=function|`Await->ke(* if [encode] returns [`Partial], end-user must call [encode] with
[`Await] value. Otherwise, it's a bad logic. *)|`Literal_|`Copy_|`Block_|`Flush|`End->invalid_encode()letflushke=matche.dstwith|`Manual->e.k<-partialk;`Partial|`Channeloc->output_bigstringoce.o0e.o_pos;e.o_pos<-0;ke|`Bufferb->fori=0toe.o_pos-1doBuffer.add_charb(Char.unsafe_chr(unsafe_get_uint8e.oi))done;(* TODO: check why we need [unsafe_chr]. *)e.o_pos<-0;keletrecc_bytebyteke=letrem=o_remeinifrem<1thenflush(fune->c_bytebyteke)eelse(unsafe_set_uint8e.oe.o_posbyte;e.o_pos<-e.o_pos+1;ke)letrecc_shortshortke=letrem=o_remeinifrem<2thenflush(fune->c_shortshortke)eelse(unsafe_set_uint16_lee.oe.o_posshort;e.o_pos<-e.o_pos+2;ke)letc_bitsbitslongke=ife.bits+long<16then(e.hold<-(bitslsle.bits)lore.hold;e.bits<-e.bits+long;ke)else(letke=e.hold<-e.holdlsr16;e.bits<-e.bits-16;keine.hold<-(bitslsle.bits)lore.hold;e.bits<-e.bits+long;c_short(e.holdland0xffff)ke)(* encode flat *)letrecensurenke=letrem=o_remeinifrem>=nthenkeelseflush(ensurenk)eletflush_bitske=assert(e.bits<=16);ife.bits>8then(letke=e.hold<-0;e.bits<-0;keinc_short(e.holdland0xffff)ke)elseife.bits>0then(letke=e.hold<-0;e.bits<-0;keinc_byte(e.holdland0xff)ke)elsekeletencode_flat_headerlastlenke=letk3e=assert(o_reme>=4);unsafe_set_uint16e.o(e.o_pos+0)len;unsafe_set_uint16e.o(e.o_pos+2)(lnotlen);e.o_pos<-e.o_pos+4;e.flat<-0;(* XXX(dinosaure): clean! *)keinletk2e=flush_bits(ensure4k3)einletk1e=c_bits0x02k2einletk0e=c_bits(iflastthen1else0)1k1eink0e(* encode dynamic huffman tree *)letencode_huffmandynamicke=letflushe=ife.bits>=16then(letke=e.hold<-e.holdlsr16;e.bits<-e.bits-16;keinc_short(e.holdland0xffff)ke)elseife.bits>=8then(letke=e.hold<-e.holdlsr8;e.bits<-e.bits-8;keinc_byte(e.holdland0xff)ke)elsekeinletrecgoranke=ifrank==Array.lengthdynamic.symbolsthenflusheelseletlen,code=dynamic.symbols.(rank)lsr_max_bits,dynamic.symbols.(rank)land((1lsl_max_bits)-1)in(* max_len: 7 *)c_bitscodelen(go(succrank))eingo0eletencode_zigzagdynamicke=letrecgoranke=ifrank==dynamic.h_lenthenencode_huffmandynamickeelseletke=go(succrank)einc_bitsdynamic.bltree.T.lengths.(zigzag.(rank))3keingo0eletencode_dynamic_headerlastdynamicke=(* More readable but should be optimized. *)letk5e=encode_zigzagdynamickeinletk4e=c_bits(dynamic.h_len-4)4k5einletk3e=c_bits(dynamic.h_dst-1)5k4einletk2e=c_bits(dynamic.h_lit-257)5k3einletk1e=c_bits0x22k2einletk0e=c_bits(iflastthen1else0)1k1eink0eletencode_fixed_headerlastke=letk1e=c_bits0x12keinletk0e=c_bits(iflastthen1else0)1k1eink0eletpending_bitske=assert(e.bits<=16);letk=flushkinife.bits>8then(letke=e.hold<-0;e.bits_rem<-`Rem(16-e.bits);e.bits<-0;keinc_short(e.holdland0xffff)ke)elseife.bits>0then(letke=e.hold<-0;e.bits_rem<-`Rem(8-e.bits);e.bits<-0;keinc_byte(e.holdland0xff)ke)elsekeexceptionFlush_bitsof{hold:int;bits:int}letrecblocke=function|`Blockblock->letke=matchblock.kindwith|Dynamicdynamic->encode_dynamic_headerblock.lastdynamic(fune->e.k<-encode;writee)e|Fixed->encode_fixed_headerblock.last(fune->e.k<-encode;writee)e|Flatlen->encode_flat_headerblock.lastlen(fune->e.k<-encode;write_flate)eine.blk<-block;ke|(`Flush|`Await)asv->encodeev(* TODO: not really clear. *)andflush_bits~bits~holdke=ife.bits>=16&&o_reme>1then(unsafe_set_uint16e.oe.o_pos(e.holdland0xffff);e.hold<-e.holdlsr16;e.bits<-e.bits-16;e.o_pos<-e.o_pos+2);ife.bits>=8&&o_reme>0then(unsafe_set_uint8e.oe.o_pos(e.holdland0xff);e.hold<-e.holdlsr8;e.bits<-e.bits-8;e.o_pos<-e.o_pos+1);ifbits+e.bits>31thenflush(flush_bits~bits~holdk)eelseifbits>0then(e.hold<-((holdland0xffff)lsle.bits)lore.hold;e.bits<-e.bits+(minbits16);flush_bits~bits:(min0(bits-16))~hold:(holdlsr16)ke)elsekeandwritee=leto_pos=refe.o_posinlethold=refe.holdinletbits=refe.bitsinletexceptionLeaveinletexceptionEndinletk_oke=e.k<-encode;`Okinletk_nwe=e.k<-block;`Blockinletk_continuee=writeein(* XXX(dinosaure): [k_continue] is used by [flush_bits]. When [flush_bits]
is done, it's only to prevent an integer overflow of [hold] and it does
not mean that we finish to encode the queue. [flush_bits] still continue
to recall [write] then and we ensure that we have enough space to flush
[hold] by [flush] and when the assumption of the given output has, at
least, 2 free bytes.
A bug appears when we compress with GZip layer [paper2] and when we reach
[flush_bits] but we don't have enough spaces. User give to us a new
output but:
1) in the old implementation of [flush_bits], we wrote nothing (at least
we want to write 16 bits)
2) [flush_bits] finish with [`Ok] which tells to the user that we encoded
all the queue *)letk_flush_bits~bits~holde=flush(flush_bits~bits~holdk_continue)einletrecemite=if!bits>=16then(unsafe_set_uint16e.o!o_pos!hold;hold:=!holdlsr16;bits:=!bits-16;o_pos:=!o_pos+2;ife.o_max-!o_pos+1>1thenemite)in(* [emit] is recursive to consume until [!bits] >= 16. Otherwise, process
can overflow [!hold]. *)letltree,dtree=matche.blkwith|{kind=Dynamicdynamic;_}->dynamic.ltree.T.tree,dynamic.dtree.T.tree|{kind=Fixed;_}->_static_ltree,_static_dtree|_->assertfalseintrywhilee.o_max-!o_pos+1>1&¬(Queue.is_emptye.b)doletcmd=Queue.peek_exne.binifnot(exists(Queue.codecmd)e.blk)thenraise_notraceLeave;Queue.unsafe_junke.b;ifcmd==256thenraise_notraceEnd;matchcmdland0x2000000==0with|true->letlen,v=Lookup.getltreecmdinhold:=(vlsl!bits)lor!hold;bits:=!bits+len;emite|false->(* XXX(dinosaure): explanation is needed here.
At the beginning, encode was made on a 64-bit processor. [int] is
63-bit in this architecture. By this way, in ANY context, any
_op-code_ can fit into [hold] (bigger _op-code_ is 48 bits).
However, in 32-bit processor, this assertion is false. We reach
sometimes the limit (31 bits) and must emit [short] to avoid
overflow. However, in some cases, we can not:
- store more bits into [hold]
- emit [short] into output
In this REAL bad case, we raise [Flush_bits] with delayed bits.
Then, we ask the client to flush output and store current [hold]
and delayed bits into new output. An final assertion is to have an
output bigger than 2 bytes in any case which is fair enough, I
think ...
[flush_bits] can be reached with [news] Calgary file. *)letoff,len=cmdland0xffff,(cmdlsr16)land0x1ffinletcode=_length.(len)inletlen0,v0=Lookup.getltree(code+256+1)inletlen1,v1=_extra_lbits.(code),len-_base_length.(codeland0x1f)inletcode=_distanceoffinletlen2,v2=Lookup.getdtreecodeinletlen3,v3=_extra_dbits.(codeland0x1f),off-_base_dist.(code)in(* len0_max: 15, 15 + 15 = 30. *)hold:=(v0lsl!bits)lor!hold;bits:=!bits+len0;emite;(* len1_max: 5, 15 + 5 = 20 *)hold:=(v1lsl!bits)lor!hold;bits:=!bits+len1;ife.o_max-!o_pos+1>1thenemiteelseraise_notrace(Flush_bits{bits=len2+len3;hold=(v3lsllen2)lorv2});(* len2_max: 15, 15 + 15 = 30 *)hold:=(v2lsl!bits)lor!hold;bits:=!bits+len2;ife.o_max-!o_pos+1>1thenemiteelseif!bits+len3+15>31thenraise_notrace(Flush_bits{bits=len3;hold=v3});(* len3_max: 13, 15 + 13 = 28 *)hold:=(v3lsl!bits)lor!hold;bits:=!bits+len3;ife.o_max-!o_pos+1>1thenemiteelseif!bits+15>31thenraise_notrace(Flush_bits{bits=0;hold=0});done;e.hold<-!hold;e.bits<-!bits;e.o_pos<-!o_pos;(* XXX(dinosaure): at least we need 2 bytes in any case. *)ifo_reme>1thenk_okeelseflushwriteewith|Flush_bits{bits=bits';hold=hold'}->e.hold<-!hold;e.bits<-!bits;e.o_pos<-!o_pos;k_flush_bits~bits:bits'~hold:hold'e|Leave->(matche.blkwith|{kind=Dynamicdynamic;_}->letlen,v=Lookup.getdynamic.ltree.T.tree256inhold:=(vlsl!bits)lor!hold;bits:=!bits+len;emite;e.hold<-!hold;e.bits<-!bits;e.o_pos<-!o_pos;k_nwe|{kind=Fixed;_}->letlen,v=Lookup.get_static_ltree256inhold:=(vlsl!bits)lor!hold;bits:=!bits+len;emite;e.hold<-!hold;e.bits<-!bits;e.o_pos<-!o_pos;k_nwe|_->assertfalse)|End->(matche.blkwith|{kind=Dynamicdynamic;_}->letlen,v=Lookup.getdynamic.ltree.T.tree256inhold:=(vlsl!bits)lor!hold;bits:=!bits+len;emite;e.hold<-!hold;e.bits<-!bits;e.o_pos<-!o_pos;ife.blk.lastthenpending_bitsk_okeelsek_nwe|{kind=Fixed;_}->letlen,v=Lookup.get_static_ltree256inhold:=(vlsl!bits)lor!hold;bits:=!bits+len;emite;e.hold<-!hold;e.bits<-!bits;e.o_pos<-!o_pos;ife.blk.lastthenpending_bitsk_okeelsek_nwe|_->assertfalse)andforceblke=letemite=ife.bits>=16then(unsafe_set_uint16e.oe.o_pose.hold;e.hold<-e.holdlsr16;e.bits<-e.bits-16;e.o_pos<-e.o_pos+2)inmatche.blkwith|{kind=Dynamicdynamic;_}->letlen,v=Lookup.getdynamic.ltree.T.tree256ine.hold<-(vlsle.bits)lore.hold;e.bits<-e.bits+len;emite;blocke(`Blockblk)|{kind=Fixed;_}->letlen,v=Lookup.get_static_ltree256ine.hold<-(vlsle.bits)lore.hold;e.bits<-e.bits+len;emite;blocke(`Blockblk)|_->assertfalse(* XXX(dinosaure): should never occur! *)andwrite_flate=let[@warning"-8"]Flatmax=e.blk.kindinleto_pos=refe.o_posinletflat=refe.flatinwhilee.o_max-!o_pos+1>1&¬(Queue.is_emptye.b)&&!flat<maxdoletcmd=Queue.pop_exne.binifnot(cmdland0x2000000==0)||cmd==256theninvalid_arg"Impossible to emit a copy code or a EOB in a Flat block";unsafe_set_uint8e.o!o_pos(cmdland0xff);incro_pos;incrflat;done;e.flat<-!flat;e.o_pos<-!o_pos;if!flat==maxthen(ife.blk.lastthenflush(fun_->`Ok)eelse(e.k<-block;`Block))elseifo_reme==0thenflushwrite_flateelse((* assert (Queue.is_empty e.b ) *)`Ok)andencodee=function|`Await->e.k<-encode;`Ok(* XXX(dinosaure): do nothing. *)|`Flush->(matche.blk.kindwith|Flat_->write_flate|Dynamic_|Fixed->writee)|`Blockblk->ife.blk.lasttheninvalid_arg"Impossible to make a new block when the current block is the last one";(matche.blk.kindwith|Flatmax->ife.flat<maxtheninvalid_arg"Impossible to make a new block when the current Flat block \
is not fully filled";blocke(`Blockblk)|Dynamic_|Fixed->ifo_reme>1thenforceblkeelseflush(fune->forceblke)e)letfirst_entrye=function|`Blockblk->e.k<-encode;blocke(`Blockblk)|(`Flush|`Await)asv->matche.blk.kindwith|Dynamicdynamic->encode_dynamic_headere.blk.lastdynamic(fune->e.k<-encode;encodeev)e|Fixed->encode_fixed_headere.blk.last(fune->e.k<-encode;encodeev)e|Flatlen->encode_flat_headere.blk.lastlen(fune->e.k<-encode;encodeev)eletdst_remd=o_remdletbits_remt=matcht.bits_remwith|`Remrem->rem|`Pending->invalid_arg"Encoder does not reach EOB of last block"letencoderdst~q=leto,o_pos,o_max=matchdstwith|`Manual->bigstring_empty,1,0|`Buffer_|`Channel_->bigstring_createio_buffer_size,0,io_buffer_size-1in{dst;blk={kind=Fixed;last=false;};hold=0;bits=0;bits_rem=`Pending;flat=0;o;o_pos;o_max;b=q;k=first_entry}letencodee=e.keendmoduleWDef=structtypet={raw:bigstring;mutabler:int;mutablew:int;mutablec:optint}letmax=1lsl15letmask=max-1let(=)(a:int)b=a==bletmaskv=vlandmaskletemptyt=t.r=t.wletsizet=t.w-t.rletavailablet=max-(t.w-t.r)letis_emptyt=emptytlet[@warning"-32"]make()={raw=Bigarray.Array1.createBigarray.charBigarray.c_layoutmax;r=0;w=0;c=Checkseum.Adler32.default}letfromraw={raw;r=0;w=0;c=Checkseum.Adler32.default}letupdatew=letc=Checkseum.Adler32.unsafe_digest_bigstringw.raw0maxw.cinw.c<-cletitertf=letlen=sizetinletmsk=maskt.rinletpre=max-mskinletrst=len-preinifrst>0then(fori=0topre-1dof(unsafe_get_chart.raw(msk+i))done;fori=0torst-1dof(unsafe_get_chart.rawi)done)elsefori=0tolen-1dof(unsafe_get_chart.raw(msk+i))done(* XXX(dinosaure): [unsafe_] means that [i] can be out of [r] and [w] - but
still is a valid index in [raw]. *)letunsafe_get_charti=unsafe_get_chart.raw(maski)[@@inlinealways]letm=max-1letunsafe_get_uint16ti=if(maski)==mthenifSys.big_endianthen(unsafe_get_uint8t.raw0lsl8)lorunsafe_get_uint8t.rawmelse(unsafe_get_uint8t.rawmlsl8)lorunsafe_get_uint8t.raw0elseunsafe_get_uint16t.raw(maski)[@@inlinealways]letunsafe_get_uint8ti=unsafe_get_uint8t.raw(maski)[@@inlinealways]lettailw=letmsk=maskw.winifmsk>0then(letc=Checkseum.Adler32.unsafe_digest_bigstringw.raw0mskw.cinw.w<-0;w.r<-0(* XXX(dinosaure): reset! *);w.c<-c)letfeedtbufofflen=letmsk=maskt.winletpre=max-mskinletrst=len-prein(ifrst>0then(unsafe_blitbufofft.rawmskpre;updatet;unsafe_blitbuf(off+pre)t.raw0rst)else(unsafe_blitbufofft.rawmsklen;ifmask(t.w+len)==0&&len>0thenupdatet));t.w<-t.w+lenletjunktlen=t.r<-t.r+lenletchecksumw=w.cendmoduleLz77=structtypedecode=[`Await|`Flush|`End]typesrc=[`Channelofin_channel|`Stringofstring|`Manual]let_max_match=258let_min_match=3let_lookahead=_max_match+_min_match+1let_hash_bits=15let_hash_shift=(_hash_bits+_min_match-1)/_min_matchlet_hash_size=1lsl_hash_bitslet_hash_mask=_hash_size-1typestate={src:src;mutablei:bigstring;mutablei_pos:int;mutablei_len:int;l:literals;d:distances;w:WDef.t;h:intarray;h_msk:int;b:Queue.t;mutablek:state->decode}letliteralss=s.lletdistancess=s.dletchecksums=WDef.checksums.wleteois=s.i<-bigstring_empty;s.i_pos<-0;s.i_len<-min_int(* set [s.i] with [s]. *)letsrcdsjl=if(j<0||l<0||j+l>bigstring_lengths)theninvalid_boundsjl;if(l==0)theneoidelse(d.i<-s;d.i_pos<-j;d.i_len<-j+l-1)letrefillks=matchs.srcwith|`String_->eois;ks|`Channelic->letres=input_bigstringics.i0(bigstring_lengths.i)insrcss.i0res;ks|`Manual->s.k<-k;`Awaitletflushks=s.k<-k;`Flush(* remaining bytes to read [s.i]. *)leti_rems=s.i_len-s.i_pos+1[@@inline]letsrc_rems=i_rems(* XXX(dinoaure): [lt] is not very safe! *)letrecnothings=s.k<-nothing;`Endletrecpendings=letlen=min(Queue.availables.b)(WDef.sizes.w)inletmsk=WDef.masks.w.rinletpre=WDef.max-mskinletrst=len-prein(ifrst>0then(Queue.blits.bs.w.rawmskpre;Queue.blits.bs.w.raw0rst)elseQueue.blits.bs.w.rawmsklen);WDef.iters.w(succ_literals.l);WDef.junks.wlen;ifWDef.is_emptys.wthen(WDef.tails.w;s.k<-nothing;`End)elseflushpendingsletrecfills=letrem=i_remsinifrem<=0then(ifrem<0thenpendingselserefillfills)elseletlen=min(WDef.availables.w)reminWDef.feeds.ws.is.i_poslen;s.i_pos<-s.i_pos+len;letks=ifi_rems==0thenrefillfillselsefillsin(* XXX(dinosaure): optimize this branch. TODO! *)ifWDef.sizes.w>=2then(ifQueue.availables.b<2thenflushfillselsedeffastks)elserefillfillsanddeffastks=assert(Queue.availables.b>=2);assert(WDef.sizes.w>=2);assert(WDef.sizes.w<=WDef.max);leti=refs.w.rinletlen=ref0inletdst=ref0inletexceptionMatchinletexceptionLiteralin(* XXX(dinosaure): prelude, a [match] is >= 3. *)letchr=WDef.unsafe_get_chars.w!iinQueue.push_exns.b(Queue.cmd(`Literalchr));incri;succ_literals.lchr;letchr=WDef.unsafe_get_chars.w!iinQueue.push_exns.b(Queue.cmd(`Literal(WDef.unsafe_get_chars.w!i)));incri;succ_literals.lchr;whiles.w.w-!i>=3&¬(Queue.is_fulls.b)dotryifWDef.unsafe_get_uint8s.w!i==WDef.unsafe_get_uint8s.w(!i-1)&&WDef.unsafe_get_uint16s.w(!i-1)==WDef.unsafe_get_uint16s.w(!i+1)then(len:=3;dst:=1;raise_notraceMatch);lethash=letv=WDef.unsafe_get_uint16s.w!iinWDef.unsafe_get_uint16s.w(!i+1)lxorvinletsource=s.h.(hashlands.h_msk)ins.h.(hashlands.h_msk)<-!i;dst:=!i-source;(* XXX(dinosaure): should be safe where [!i] is the newest indice in [w]. *)if!dst==0||!dst>=WDef.max(* XXX(dinosaure): deliver only valid distance *)||source+3-min_int>=!i-min_int(* XXX(dinosaure): [source] ∈ no emitted characters *)||source-min_int<s.w.r-min_int(* XXX(dinosaure): too old! *)||WDef.unsafe_get_uint16s.w!i<>WDef.unsafe_get_uint16s.wsource||WDef.unsafe_get_uint16s.w(!i+1)<>WDef.unsafe_get_uint16s.w(source+1)then(raise_notraceLiteral);len:=3;raise_notraceMatchwith|Literal->letchr=WDef.unsafe_get_chars.w!iinQueue.push_exns.b(Queue.cmd(`Literalchr));incri;succ_literals.lchr|Match->if!dst==1then(letvv=WDef.unsafe_get_uint16s.w!iinletv=WDef.unsafe_get_uint8s.w!iinwhile!len+2<=_max_match&&s.w.w-(!i+!len+2)>0(* XXX(dinosaure): stay under write cursor. *)&&WDef.unsafe_get_uint16s.w(!i+!len)==vvdolen:=!len+2done;if!len+1<=_max_match&&s.w.w-(!i+!len+1)>0&&WDef.unsafe_get_uint8s.w(!i+!len)==vthenincrlen;Queue.push_exns.b(Queue.cmd(`Copy(!dst,!len)));i:=!i+!len;succ_lengths.l!len;succ_distances.d!dst)else(letsource=!i-!dstin(* XXX(dinosaure): try to go furthermore. *)while!len+2<=_max_match&&source+!len+2-min_int<!i+!len+2-min_int(* XXX(dinosaure): stay outside non-emitted characters. *)&&s.w.w-(!i+!len+2)>0(* XXX(dinosaure): stay under write cursor. *)&&WDef.unsafe_get_uint16s.w(!i+!len)==WDef.unsafe_get_uint16s.w(source+!len)dolen:=!len+2done;if!len+1<=_max_match&&source+!len+1-min_int<!i-!len+1-min_int&&s.w.w-(!i+!len+1)>0&&WDef.unsafe_get_uint8s.w(!i+!len)==WDef.unsafe_get_uint8s.w(source+!len)thenincrlen;Queue.push_exns.b(Queue.cmd(`Copy(!dst,!len)));i:=!i+!len;succ_lengths.l!len;succ_distances.d!dst)done;WDef.junks.w(!i-s.w.r);ifQueue.is_fulls.bthenflushkselse(ifi_rems==0thenrefillfillselseks)letcompresss=s.ksletstatesrc~w~q=leti,i_pos,i_len=matchsrcwith|`Manual->bigstring_empty,1,0|`Stringx->bigstring_of_stringx,0,String.lengthx-1|`Channel_->bigstring_createio_buffer_size,1,0in{src;i;i_pos;i_len;l=make_literals();d=make_distances();w=WDef.fromw;h=Array.make(1lsl8)0;h_msk=(1lsl8)-1;b=q;k=fill}endmoduleHigher=structletcompress~w~q~i~o~refill~flush=letstate=Lz77.state`Manual~w~qinletencoder=Def.encoder`Manual~qinletkind=refDef.Fixedinletreccompress()=matchLz77.compressstatewith|`Await->letlen=refilliinLz77.srcstatei0len;compress()|`Flush->letliterals=Lz77.literalsstateinletdistances=Lz77.distancesstateinkind:=Def.Dynamic(Def.dynamic_of_frequencies~literals~distances);encode(Def.encodeencoder(`Block{Def.kind=!kind;last=false;}))|`End->Queue.push_exnqQueue.eob;pending(Def.encodeencoder(`Block{Def.kind=Def.Fixed;last=true;}))andencode=function|`Partial->letlen=(bigstring_lengtho)-Def.dst_remencoderinflusholen;Def.dstencodero0(bigstring_lengtho);encode(Def.encodeencoder`Await)|`Ok->compress()|`Block->letliterals=Lz77.literalsstateinletdistances=Lz77.distancesstateinkind:=Def.Dynamic(Def.dynamic_of_frequencies~literals~distances);encode(Def.encodeencoder(`Block{Def.kind=!kind;last=false;}))andpending=function|`Block->assertfalse(* XXX(dinosaure): should never appear. *)|`Partial->letlen=(bigstring_lengtho)-Def.dst_remencoderinflusholen;Def.dstencodero0(bigstring_lengtho);pending(Def.encodeencoder`Await)|`Ok->()inQueue.resetq;Def.dstencodero0(bigstring_lengtho);compress()letuncompress~w~i~o~refill~flush=letdecoder=Inf.decoder`Manual~o~winletrecdecompress()=matchInf.decodedecoderwith|`Await->letlen=refilliinInf.srcdecoderi0len;decompress()|`End->letlen=bigstring_lengtho-Inf.dst_remdecoderiniflen>0thenflusholen;Ok()|`Flush->letlen=bigstring_lengtho-Inf.dst_remdecoderinflusholen;Inf.flushdecoder;decompress()|`Malformederr->Error(`Msgerr)indecompress()letof_string~o~winput~flush=letdecoder=Inf.decoder(`Stringinput)~o~winletrecdecompress()=matchInf.decodedecoderwith|`Await->assertfalse|`End->letlen=bigstring_lengtho-Inf.dst_remdecoderiniflen>0thenflusholen;Ok()|`Flush->letlen=bigstring_lengtho-Inf.dst_remdecoderinflusholen;Inf.flushdecoder;decompress()|`Malformederr->Error(`Msgerr)indecompress()letto_string?(buffer=4096)~i~w~q~refill=letbuf=Buffer.createbufferinletstate=Lz77.state`Manual~q~winletencoder=Def.encoder(`Bufferbuf)~qinletkind=refDef.Fixedinletreccompress()=matchLz77.compressstatewith|`Await->letlen=refilliinLz77.srcstatei0len;compress()|`Flush->letliterals=Lz77.literalsstateinletdistances=Lz77.distancesstateinkind:=Def.Dynamic(Def.dynamic_of_frequencies~literals~distances);encode(Def.encodeencoder(`Block{Def.kind=!kind;last=false;}))|`End->Queue.push_exnqQueue.eob;pending(Def.encodeencoder(`Block{Def.kind=Def.Fixed;last=true;}))andencode=function|`Partial->assertfalse|`Ok->compress()|`Block->letliterals=Lz77.literalsstateinletdistances=Lz77.distancesstateinkind:=Def.Dynamic(Def.dynamic_of_frequencies~literals~distances);encode(Def.encodeencoder(`Block{Def.kind=!kind;last=false;}))andpending=function|`Partial|`Block->assertfalse|`Ok->()inQueue.resetq;compress();Buffer.contentsbufend