123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601moduleBigarray=Bigarray_compat(* XXX(dinosaure): MirageOS compatibility. *)typebigstring=(char,Bigarray.int8_unsigned_elt,Bigarray.c_layout)Bigarray.Array1.ttypeerror=[`Malformedofstring|`Invalid_argumentofstring|`Invalid_dictionary]letpf=Format.fprintfletpp_errorppf=function|`Malformederr->pfppf"%s"err|`Invalid_argumenterr->pfppf"%s"err|`Invalid_dictionary->pfppf"Invalid dictionary"let(<.>)fg=funx->f(gx)letbigstring_lengthx=Bigarray.Array1.dimx[@@inline]letbigstring_createl=Bigarray.Array1.createBigarray.charBigarray.c_layoutlletbigstring_subbufofflen=Bigarray.Array1.subbufofflenletbigstring_empty=bigstring_create0(* XXX(dinosaure): we want to control which exception is raised if we want to have
a bad access. In this case, [Out_of_bound]. *)exceptionOut_of_boundexternalunsafe_get_char:bigstring->int->char="%caml_ba_unsafe_ref_1"letget_charbufofs=ifofs<0||ofs>bigstring_lengthbuf-1thenraiseOut_of_bound;unsafe_get_charbufofsexternalunsafe_get_int16:bigstring->int->int="%caml_bigstring_get16u"letget_int16bufofs=ifofs<0||ofs>bigstring_lengthbuf-2thenraiseOut_of_bound;unsafe_get_int16bufofsexternalunsafe_get_int8:bigstring->int->int="%caml_ba_unsafe_ref_1"letget_int8bufofs=ifofs<0||ofs>bigstring_lengthbuf-1thenraiseOut_of_bound;unsafe_get_int8bufofsexternalunsafe_set_int8:bigstring->int->int->unit="%caml_ba_unsafe_set_1"letset_int8bufofsx=ifofs<0||ofs>bigstring_lengthbuf-1thenraiseOut_of_bound;unsafe_set_int8bufofsxexternalunsafe_get_int32:bigstring->int->int32="%caml_bigstring_get32"externalunsafe_get_int64:bigstring->int->int64="%caml_bigstring_get64"letget_int32bufofs=ifofs<0||ofs>bigstring_lengthbuf-4thenraiseOut_of_bound;unsafe_get_int32bufofsletget_int64bufofs=ifofs<0||ofs>bigstring_lengthbuf-8thenraiseOut_of_bound;unsafe_get_int64bufofsexternalunsafe_set_int32:bigstring->int->int32->unit="%caml_bigstring_set32"letset_int32bufofsx=ifofs<0||ofs>bigstring_lengthbuf-4thenraiseOut_of_bound;unsafe_set_int32bufofsxexternalswap16:int->int="%bswap16"(* XXX(dinosaure): assume that LZO does need [memcpy] behaviour. *)letunsafe_blitsrcsrc_offdstdst_offlen=letlen0=lenland3inletlen1=lenasr2infori=0tolen1-1doleti=i*4inletv=unsafe_get_int32src(src_off+i)inunsafe_set_int32dst(dst_off+i)vdone;fori=0tolen0-1doleti=len1*4+iinletv=unsafe_get_int8src(src_off+i)inunsafe_set_int8dst(dst_off+i)vdoneletblitsrcsrc_offdstdst_offlen=iflen<0||src_off<0||src_off>bigstring_lengthsrc-len||dst_off<0||dst_off>bigstring_lengthdst-lenthenraiseOut_of_bound;unsafe_blitsrcsrc_offdstdst_offlenexternalbytes_unsafe_set_int32:bytes->int->int32->unit="%caml_bytes_set32u"externalbytes_unsafe_set_int8:bytes->int->int->unit="%bytes_unsafe_set"letunsafe_bigstring_to_stringbufofslen=letres=Bytes.createleninletlen0=lenland3inletlen1=lenasr2infori=0tolen1-1doleti=i*4inletv=unsafe_get_int32buf(ofs+i)inbytes_unsafe_set_int32resivdone;fori=0tolen0-1doleti=len1*4+iinletv=unsafe_get_int8buf(ofs+i)inbytes_unsafe_set_int8resivdone;Bytes.unsafe_to_stringresletbigstring_to_stringbufofslen=ifofs<0||len<0||ofs>bigstring_lengthbuf-lenthenraiseOut_of_bound;unsafe_bigstring_to_stringbufofslenletunsafe_get_int16_le=ifSys.big_endianthenfunbufoff->swap16(unsafe_get_int16bufoff)elsefunbufoff->unsafe_get_int16bufoffletunsafe_get_int16_be=ifSys.big_endianthenfunbufoff->unsafe_get_int16bufoffelsefunbufoff->swap16(unsafe_get_int16bufoff)letunsafe_get_int16bufofs=function|`LE->unsafe_get_int16_lebufofs|`BE->unsafe_get_int16_bebufofsletget_int16bufofsendian=ifofs<0||ofs>bigstring_lengthbuf-2thenraiseOut_of_bound;unsafe_get_int16bufofsendianletkstrfkfmt=Format.kasprintfkfmttypesub={off:int;len:int;}moduleState:sigtypet=privateintvalof_int:int->tval_0:tval_3:tend=structtypet=intletof_intx=xlet_0=0let_3=3endtype('a,'error)t=|Return:'a->('a,'error)t|Bind:('a,'error)t*('a->('b,'error)t)->('b,'error)t|State:(state,'error)t|Transmit:int*state->(unit,'error)t|Count:(int,'error)t|Copy:sub*state->(unit,'error)t|Fail:'error->('a,'error)t|Peek:'avalue->('a,'error)t|Junk:'avalue->(unit,'error)t|Fix:(('a,'error)t->('a,'error)t)->('a,'error)t|Lazy:('a,'error)tLazy.t->('a,'error)tand'avalue=|Byte:charvalue|Short:[`LE|`BE]->intvalueandstate=State.ttypev={i:bigstring;mutablei_pos:int;mutableo:bigstring;mutableo_pos:int;mutablestate:State.t}lettransmitvlen=blitv.iv.i_posv.ov.o_poslen;v.i_pos<-v.i_pos+len;v.o_pos<-v.o_pos+len;Ok()letcopyv~off~len=blitv.o(v.o_pos-off)v.ov.o_poslen;v.o_pos<-v.o_pos+len;Ok()lettransmit_to_bufferbufvlen=letres=bigstring_to_stringv.iv.i_posleninBuffer.add_stringbufres;v.i_pos<-v.i_pos+len;v.o_pos<-v.o_pos+len;Ok()letcopy_to_bufferbufv~off~len=letrecgoofflen=iflen=0thenOk()elseletpos=Buffer.lengthbuf-offinletrem=Buffer.lengthbuf-posinletcpy=minremleninletres=Buffer.subbufposcpyinBuffer.add_stringbufres;go(off+cpy)(len-cpy)inifBuffer.lengthbuf>=offthengoofflenelseError`Invalid_dictionaryletcountt=letres=ref0inletidx=reft.i_posinletmax=bigstring_lengtht.iinwhilenot(!idx>max-4)&&get_int32t.i!idx=0ldoidx:=!idx+4;res:=!res+4done;while!idx+1<=max&&get_int8t.i!idx=0doincridx;incrresdone;if!idx<maxthen(t.i_pos<-!idx+1;Ok(!res*255+get_int8t.i!idx))elseError(`Malformed"Invalid input")type('a,'b)k=|Okof'a|Errorof'b|Kontinuationof(unit->('a,'b)t)let(>>=):('a,'err)result->('a->('b,'err)result)->('b,'err)result=funxf->matchxwith|Okx->fx|Errorerr->Errorerrletcopy_done~transmitt=letstate=(t.state:>int)intransmitt(stateland3)letrun:transmit:(v->int->(unit,'error)result)->copy:(v->off:int->len:int->(unit,'error)result)->('a,'error)t->v->('a,'error)result=fun~transmit~copyfibert->letrecgo:typea.v->(a,([>`Malformedofstring]as'error))t->(a,'error)k=funt->function|Failerr->Errorerr|Returnv->Okv|PeekByte->Ok(get_chart.it.i_pos)|JunkByte->ift.i_pos<bigstring_lengtht.ithen(t.i_pos<-t.i_pos+1;Ok())elseraiseOut_of_bound|Peek(Shortendian)->Ok(get_int16t.it.i_posendian)|Junk(Short_)->ift.i_pos+1<bigstring_lengtht.ithen(t.i_pos<-t.i_pos+2;Ok())elseraiseOut_of_bound|Bind(x,f)->(matchgotxwith|Okv->got(fv)|Error_aserr->err|Kontinuationx->got(Bind(x(),f)))|Fixfix->(* XXX(dinosaure): [Kontinuation] exists to break the stack-overflow with [js_of_ocaml] but
it was not implemented yet. *)letrecm=lazy(fixr)andr=Lazymingotr|State->Okt.state|Count->(matchcounttwithOkv->Okv|Errorerr->Errorerr)|Transmit(len,state)->t.state<-state;(matchtransmittlenwithOkv->Okv|Errorerr->Errorerr)|Lazym->got(Lazy.forcem)|Copy({off;len;},state)->t.state<-state;letfiber=copyt~off~len:(len+2)>>=fun()->copy_done~transmittinmatchfiberwith|Okv->Okv|Errorerr->Errorerrinletrecunrolltfiber:_result=matchgotfiberwith|Okv->Okv|Errorerr->Errorerr|Kontinuationfiber->unrollt(fiber())inunrolltfibermoduleDSL=structletreturnx=Returnxletbindxf=Bind(x,f)let(>>=)xf=Bind(x,f)letpeekv=Peekvletjunkv=Junkvletbyte=Byteletstate=Statelettransmit~lenstate=Transmit(len,state)letcount=Countletcopy~off~lenstate=Copy({off;len;},state)letleshort=Short`LEletbeshort=Short`BEletend_of_lzo=Return()letfixf=Fixfletmalformedffmt=kstrf(funs->Fail(`Malformeds))fmtletreadv=peekv>>=funr->junkv>>=fun()->returnrendletfiber:(unit,[>error])t=letopenDSLinfix@@funm->readbyte>>=funchr->state>>=funstate->matchchr,(state:>int)land3with|'\001'..'\015',0->transmit(Char.codechr+3)state>>=fun()->m|'\000',0->count>>=funcount->letlen=3+15+countintransmit~lenState._3>>=fun()->m|'\000'..'\015',(1|2|3)->letd,state=Char.codechrlsr2,State.of_int(Char.codechr)inreadbyte>>=funh->letoff=(Char.codehlsl2)+d+1incopy~off~len:2state>>=fun()->m|'\016'..'\031',_->letlength=Char.codechrland0b111inletwith_lengthlen=readleshort>>=funs->letoff=leth=(Char.codechrland8)lsr3in16384+(hlsl14)+(slsr2)inletstate=State.of_int(sland0xff)inifoff=16384thenend_of_lzoelsecopy~off~lenstate>>=fun()->miniflength=0thencount>>=funcount->with_length(7+count)elsewith_lengthlength|'\032'..'\063',_->letwith_lengthlen=readleshort>>=funs->letstate=State.of_int(sland0xff)inletoff=succ(slsr2)incopy~off~lenstate>>=fun()->minletlength=Char.codechrland0b11111iniflength=0thencount>>=funcount->with_length(31+count)elsewith_lengthlength|'\064'..'\255',_->letstate=State.of_int(Char.codechr)inletlen,d=(Char.codechrlsr5)-1,(* t = (t >> 5) - 1 *)((Char.codechrlsr2)land7)(* m_pos = (t >> 2) & 7 *)inreadbyte>>=funh->letoff=(Char.codehlsl3)+d+1incopy~off~lenstate>>=fun()->m|_->assertfalse(* TODO: replace it by something else to ensure exhaustive pattern-matching. *)letfiber:(unit,[>error])t=letopenDSLinpeekbyte>>=funchr->matchchrwith|'\016'->malformedf"No dictionary at offset 0 available"|'\000'..'\017'->fiber|'\018'->junkbyte>>=fun()->transmit~len:1State._0>>=fun()->fiber|'\019'->junkbyte>>=fun()->transmit~len:2State._0>>=fun()->fiber|'\020'->junkbyte>>=fun()->transmit~len:3State._0>>=fun()->fiber|'\021'->junkbyte>>=fun()->transmit~len:4State._0>>=fun()->fiber|'\022'..'\255'aschr->letlen=Char.codechr-17injunkbyte>>=fun()->transmit~lenState._0letuncompressinputoutput:(bigstring,[>error])result=letv={i=input;i_pos=0;o=output;o_pos=0;state=State._0}inmatchrun~transmit~copyfibervwith|Ok()->Ok(bigstring_suboutput0v.o_pos)(* TODO(dinosaure): we can replace it by [unsafe_sub]. *)|Error(#erroraserr)->Errorerr|exceptionOut_of_bound->Error(`Invalid_argument"Input is malformed or output is not large enough")letuncompress_with_buffer?(chunk=0x1000)input:(string,[>error])result=letv={i=input;i_pos=0;o=bigstring_empty;o_pos=0;state=State._0}inletbuf=Buffer.createchunkinlettransmitvlen=transmit_to_bufferbufvleninletcopyv~off~len=copy_to_bufferbufv~off~leninmatchrun~transmit~copyfibervwith|Ok()->Ok(Buffer.contentsbuf)|Error(#erroraserr)->Errorerr|exceptionOut_of_bound->Error(`Malformed"Malformed input")(* inflate *)let_m3_marker=32let_m4_marker=16let_m2_max_len=8let_m3_max_len=33let_m4_max_len=9let_m2_max_offset=0x0800let_m3_max_offset=0x4000let(.%[])bufofs=get_int8bufofslet(.%[]<-)bufofsv=set_int8bufofsvexternalswap32:int32->int32="caml_int32_bswap"letindex=[|0;1;2;53;3;7;54;27;4;38;41;8;34;55;48;28;62;5;39;46;44;42;22;9;24;35;59;56;49;18;29;11;63;52;6;26;37;40;33;47;61;45;43;21;23;58;17;10;51;25;36;32;60;20;57;16;50;31;19;15;30;14;13;12;|]letctzv=letneg=Int64.neginlet(land)=Int64.logandinlet(*)=Int64.mulinlet(>>)=Int64.shift_right_logicalinletidx=((vland(negv))*0x022fdd63cc95386dL)>>58inindex.(Int64.to_intidx)letget_int32_le=ifSys.big_endianthenfunbufoff->swap32(get_int32bufoff)elsefunbufoff->get_int32bufoffletrecord_match~off~lenout_data_anchorout_pos=letout_pos=refout_posiniflen<=_m2_max_len&&off<=_m2_max_offsetthen(letoff=off-1inout_data.%[!out_pos]<-((len-1)lsl5)lor((offland7)lsl2);incrout_pos;out_data.%[!out_pos]<-offasr3;incrout_pos)elseifoff<=_m3_max_offsetthen(letoff=off-1iniflen<=_m3_max_lenthen(out_data.%[!out_pos]<-_m3_markerlor(len-2);incrout_pos)else(letlen=ref(len-_m3_max_len)inout_data.%[!out_pos]<-_m3_markerlor0;incrout_pos;while!len>255dolen:=!len-255;out_data.%[!out_pos]<-0;incrout_posdone;out_data.%[!out_pos]<-!len;incrout_pos);out_data.%[!out_pos]<-offlsl2;incrout_pos;out_data.%[!out_pos]<-offasr6;incrout_pos)else(letoff=off-0x4000iniflen<=_m4_max_lenthen(out_data.%[!out_pos]<-_m4_markerlor((offasr11)land8)lor(len-2);incrout_pos)else(letlen=ref(len-_m4_max_len)inout_data.%[!out_pos]<-_m4_markerlor((offasr11)land8);incrout_pos;while!len>255dolen:=!len-255;out_data.%[!out_pos]<-0;incrout_posdone;out_data.%[!out_pos]<-!len;incrout_pos);out_data.%[!out_pos]<-offlsl2;incrout_pos;out_data.%[!out_pos]<-offasr6;incrout_pos);!out_posletrecord_literals~off~lenin_dataout_data_anchorout_pos=letout_pos=refout_posinletin_pos=refoffiniflen>0then(iflen<=3then(out_data.%[!out_pos-2]<-out_data.%[!out_pos-2]lorlen;unsafe_blitin_dataoffout_data!out_pos4;out_pos:=!out_pos+len)elseiflen<=16then(out_data.%[!out_pos]<-(len-3);incrout_pos;unsafe_blitin_dataoffout_data!out_pos8;unsafe_blitin_data(off+8)out_data(!out_pos+8)8;out_pos:=!out_pos+len)else(iflen<=18then(out_data.%[!out_pos]<-len-3;incrout_pos)else(letlen'=ref(len-18)inout_data.%[!out_pos]<-0;incrout_pos;while!len'>255dolen':=!len'-255;out_data.%[!out_pos]<-0;incrout_posdone;out_data.%[!out_pos]<-!len';incrout_pos);unsafe_blitin_dataoffout_data!out_poslen;out_pos:=!out_pos+len;in_pos:=!in_pos+len));!out_pos,!in_posletrecord_trailer~off~lenin_dataout_dataout_pos=letout_pos=refout_posiniflen>0then(if!out_pos=0&&len<238then(out_data.%[!out_pos]<-17+len;incrout_pos)elseiflen<=3then(out_data.%[!out_pos-2]<-out_data.%[!out_pos-2]lorlen)elseiflen<=18then(out_data.%[!out_pos]<-len-3;incrout_pos)else(letlen'=ref(len-18)inout_data.%[!out_pos]<-0;incrout_pos;while!len'>255dolen':=!len'-255;out_data.%[!out_pos]<-0;incrout_posdone;out_data.%[!out_pos]<-!len';incrout_pos);unsafe_blitin_dataoffout_data!out_poslen);out_pos:=!out_pos+len;out_data.%[!out_pos]<-_m4_markerlor1;incrout_pos;out_data.%[!out_pos]<-0;incrout_pos;out_data.%[!out_pos]<-0;incrout_pos;!out_posletcompressin_datain_posin_lenout_dataout_posout_lentwrkmem=letidx_end=max0(in_len-20)inletrecliteralidx0idx1opt=(* literal: *)letidx0=idx0+(1+((idx0-idx1)asr5))in(* TODO: check [lsr]. *)nextidx0idx1optandnextidx0idx1opt=(* next: *)ifidx0-in_pos>=idx_endthen(* break *)(letidx1=idx1-tandt=0in(in_len-(idx1-in_pos-t),op))elseletv=get_int32_lein_dataidx0inletindex=Int32.(logand(shift_right(mul0x1824429dlv)(32-14))(sub(shift_left1l14)1l))inletindex=Int32.to_intindexinletreference=Bigarray.Array1.getwrkmemindex+in_posinBigarray.Array1.setwrkmemindex(idx0-in_pos);ifv<>get_int32_lein_datareferencethenliteralidx0idx1optelse(letidx1=idx1-tinlett=0inletunrecorded=idx0-idx1inletop,idx1=record_literals~off:idx1~len:unrecordedin_dataout_dataout_posopinletlen=ref4inwhileidx0+!len-in_pos<idx_end&&get_int64in_data(idx0+!len)=get_int64in_data(reference+!len)dolen:=!len+8done(* XXX(dinosaure): it seems that [minilzo] does not call [ctz] at the end of [progl].
May be we do an unsafe access! TODO! *);ifidx0+!len-in_pos<in_lenthenlen:=!len+(ctz(Int64.logxor(get_int64in_data(idx0+!len))(get_int64in_data(reference+!len)))/8);letop=record_match~off:(idx0-reference)~len:!lenout_dataout_posopinnext(idx0+!len)(idx0+!len)opt)inletidx0=in_pos+(ift<4then4-telse0)inliteralidx0in_posout_posttypewrkmem=(int,Bigarray.int16_unsigned_elt,Bigarray.c_layout)Bigarray.Array1.tletmake_wrkmem()=Bigarray.Array1.createBigarray.int16_unsignedBigarray.c_layout(1lsl14)moduleWrkmem=structletmemsettv=Bigarray.Array1.filltvendletcompressin_datain_lenout_dataout_lenwrkmem=letrecgoidxlenout_post=iflen<=20thentraileridxlenout_postelse(* len > 20 *)(letll=minlen49152inif(t+ll)lsr5<=0thentraileridxlenout_postelse(Wrkmem.memsetwrkmem0;lett,out_pos=compressin_dataidxllout_dataout_posout_lentwrkmemingo(idx+ll)(len-ll)out_post))andtraileridxlenout_post=lett=t+leninletout_pos=record_trailer~off:(in_len-t)~len:tin_dataout_dataout_posinout_posintrygo0in_len00withOut_of_bound->invalid_arg"lzo: output is not large enough"letcompressin_dataout_datawrkmem=Wrkmem.memsetwrkmem0;compressin_data(bigstring_lengthin_data)out_data(bigstring_lengthout_data)wrkmem