Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file binary_writer.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)openBinary_error_typesletraiseerror=Stdlib.raise(Write_errorerror)(** Imperative state of the binary writer. *)typewriter_state={mutablebuffer:Bytes.t;(** The buffer where to write. *)mutableoffset:int;(** The offset of the next byte to be written in [buffer]. *)mutableallowed_bytes:Uint_option.t;(** Maximum number of bytes that are allowed to be write in [buffer]
(after [offset]) before to fail (unless it is [unlimited_bytes]). *)}letmake_writer_statebuffer~offset~allowed_bytes=ifallowed_bytes<0||allowed_bytes>Bytes.lengthbuffer-offsetthenNoneelseletallowed_bytes=Uint_option.someallowed_bytesinSome{buffer;offset;allowed_bytes}letunlimited_bytes=Uint_option.is_noneletlimited_bytes=Uint_option.is_someletcheck_allowed_bytesstatesize=iflimited_bytesstate.allowed_bytesthen(letallowed_bytes=Uint_option.getstate.allowed_bytesinifallowed_bytes<sizethenraiseSize_limit_exceeded;state.allowed_bytes<-Uint_option.(some(allowed_bytes-size)))(** [may_resize state size] will first ensure there is enough
space in [state.buffer] for writing [size] bytes (starting at
[state.offset]).
When the buffer does not have enough space for writing [size] bytes,
but still has enough [allowed_bytes], it will replace the buffer
with a buffer large enough.
@raise [Binary_error.Write_error Size_limit_exceeded] when there is
not enough allowed bytes to write [size] bytes. *)letmay_resizestatesize=check_allowed_bytesstatesize;letbuffer_len=Bytes.lengthstate.bufferinifbuffer_len-state.offset<sizethen(letnew_buffer=Bytes.create(max(2*buffer_len)(buffer_len+size))inBytes.blitstate.buffer0new_buffer0state.offset;state.buffer<-new_buffer);state.offset<-state.offset+size(** Writer for all the atomic types. *)moduleAtom=structletcheck_int_rangeminvmax=ifv<min||max<vthenraise(Invalid_int{min;v;max})letcheck_float_rangeminvmax=ifv<min||max<vthenraise(Invalid_float{min;v;max})letset_intkindbufferofsv=matchkindwith|`Int31|`Uint30->TzEndian.set_int32bufferofs(Int32.of_intv)|`Int16|`Uint16->TzEndian.set_int16bufferofsv|`Int8|`Uint8->TzEndian.set_int8bufferofsvletintkindstatev=check_int_range(Binary_size.min_intkind)v(Binary_size.max_intkind);letofs=state.offsetinmay_resizestate(Binary_size.integer_to_sizekind);set_intkindstate.bufferofsvletint8=int`Int8letuint8=int`Uint8letint16=int`Int16letuint16=int`Uint16letuint30=int`Uint30letint31=int`Int31letboolstatev=uint8state(ifvthen255else0)letint32statev=letofs=state.offsetinmay_resizestateBinary_size.int32;TzEndian.set_int32state.bufferofsvletint64statev=letofs=state.offsetinmay_resizestateBinary_size.int64;TzEndian.set_int64state.bufferofsvletranged_int~minimum~maximumstatev=check_int_rangeminimumvmaximum;letv=ifminimum>=0thenv-minimumelsevinmatchBinary_size.range_to_size~minimum~maximumwith|`Uint8->uint8statev|`Uint16->uint16statev|`Uint30->uint30statev|`Int8->int8statev|`Int16->int16statev|`Int31->int31statevletnstatev=ifZ.signv<0thenraiseInvalid_natural;ifZ.equalvZ.zerothenuint8state0x00elseletbits=Z.numbitsvinletget_chunkposlen=Z.to_int(Z.extractvposlen)inletlength=Binary_length.n_lengthvinletoffset=state.offsetinmay_resizestatelength;fori=0tolength-1doletpos=i*7inletchunk_len=ifi=length-1thenbits-poselse7inTzEndian.set_int8state.buffer(offset+i)((ifi=length-1then0x00else0x80)lorget_chunkposchunk_len)doneletzstatev=letsign=Z.signv<0inletbits=Z.numbitsvinifZ.equalvZ.zerothenuint8state0x00elseletv=Z.absvinletget_chunkposlen=Z.to_int(Z.extractvposlen)inletlength=Binary_length.z_lengthvinletoffset=state.offsetinmay_resizestatelength;TzEndian.set_int8state.bufferoffset((ifsignthen0x40else0x00)lor(ifbits>6then0x80else0x00)lorget_chunk06);fori=1tolength-1doletpos=6+((i-1)*7)inletchunk_len=ifi=length-1thenbits-poselse7inTzEndian.set_int8state.buffer(offset+i)((ifi=length-1then0x00else0x80)lorget_chunkposchunk_len)doneletfloatstatev=letofs=state.offsetinmay_resizestateBinary_size.float;TzEndian.set_doublestate.bufferofsvletranged_float~minimum~maximumstatev=check_float_rangeminimumvmaximum;floatstatevletstring_enumtblarrstatev=letvalue=trysnd(Hashtbl.findtblv)withNot_found->raiseNo_case_matchedinmatchBinary_size.enum_sizearrwith|`Uint30->uint30statevalue|`Uint16->uint16statevalue|`Uint8->uint8statevalueletfixed_kind_byteslengthstates=ifBytes.lengths<>lengththenraise(Invalid_bytes_length{expected=length;found=Bytes.lengths});letofs=state.offsetinmay_resizestatelength;Bytes.blits0state.bufferofslengthletfixed_kind_stringlengthstates=ifString.lengths<>lengththenraise(Invalid_string_length{expected=length;found=String.lengths});letofs=state.offsetinmay_resizestatelength;Bytes.blit_strings0state.bufferofslengthlettag=function`Uint8->uint8|`Uint16->uint16end(** Main recursive writing function. *)letrecwrite_rec:typea.aEncoding.t->writer_state->a->unit=funestatevalue->letopenEncodinginmatche.encodingwith|Null->()|Empty->()|Constant_->()|Ignore->()|Bool->Atom.boolstatevalue|Int8->Atom.int8statevalue|Uint8->Atom.uint8statevalue|Int16->Atom.int16statevalue|Uint16->Atom.uint16statevalue|Int31->Atom.int31statevalue|Int32->Atom.int32statevalue|Int64->Atom.int64statevalue|N->Atom.nstatevalue|Z->Atom.zstatevalue|Float->Atom.floatstatevalue|Bytes(`Fixedn)->Atom.fixed_kind_bytesnstatevalue|Bytes`Variable->letlength=Bytes.lengthvalueinAtom.fixed_kind_byteslengthstatevalue|String(`Fixedn)->Atom.fixed_kind_stringnstatevalue|String`Variable->letlength=String.lengthvalueinAtom.fixed_kind_stringlengthstatevalue|Padded(e,n)->write_recestatevalue;Atom.fixed_kind_stringnstate(String.maken'\000')|RangedInt{minimum;maximum}->Atom.ranged_int~minimum~maximumstatevalue|RangedFloat{minimum;maximum}->Atom.ranged_float~minimum~maximumstatevalue|String_enum(tbl,arr)->Atom.string_enumtblarrstatevalue|Array(Somemax_length,_e)whenArray.lengthvalue>max_length->raiseArray_too_long|Array(_,e)->Array.iter(write_recestate)value|List(Somemax_length,_e)whenList.lengthvalue>max_length->raiseList_too_long|List(_,e)->List.iter(write_recestate)value|Obj(Req{encoding=e;_})->write_recestatevalue|Obj(Opt{kind=`Dynamic;encoding=e;_})->(matchvaluewith|None->Atom.boolstatefalse|Somevalue->Atom.boolstatetrue;write_recestatevalue)|Obj(Opt{kind=`Variable;encoding=e;_})->(matchvaluewithNone->()|Somevalue->write_recestatevalue)|Obj(Dft{encoding=e;_})->write_recestatevalue|Objs{left;right;_}->let(v1,v2)=valueinwrite_recleftstatev1;write_recrightstatev2|Tupe->write_recestatevalue|Tups{left;right;_}->let(v1,v2)=valueinwrite_recleftstatev1;write_recrightstatev2|Conv{encoding=e;proj;_}->write_recestate(projvalue)|Union{tag_size;match_case;_}->let(Matched(tag,e,value))=match_casevalueinAtom.tagtag_sizestatetag;write_recestatevalue|Dynamic_size{kind;encoding=e}->letinitial_offset=state.offsetin(* place holder for [size] *)Atom.intkindstate0;write_with_limit(Binary_size.max_intkind)estatevalue;(* patch the written [size] *)Atom.set_intkindstate.bufferinitial_offset(state.offset-initial_offset-Binary_size.integer_to_sizekind)|Check_size{limit;encoding=e}->write_with_limitlimitestatevalue|Describe{encoding=e;_}->write_recestatevalue|Splitted{encoding=e;_}->write_recestatevalue|Mu{fix;_}->write_rec(fixe)statevalue|Delayedf->write_rec(f())statevalueandwrite_with_limit:typea.int->aEncoding.t->writer_state->a->unit=funlimitestatevalue->(* backup the current limit *)letold_limit=state.allowed_bytesin(* install the new limit (only if smaller than the current limit) *)letlimit=ifunlimited_bytesstate.allowed_bytesthenlimitelseletold_limit=Uint_option.getstate.allowed_bytesinminold_limitlimitinstate.allowed_bytes<-Uint_option.somelimit;write_recestatevalue;(* restore the previous limit (minus the read bytes) *)ifunlimited_bytesold_limitthenstate.allowed_bytes<-Uint_option.noneelseletremaining=Uint_option.getstate.allowed_bytesinletread=limit-remaininginstate.allowed_bytes<-Uint_option.(some(getold_limit-read))(** ******************** *)(** Various entry points *)letwrite_exnevstate=write_recestatev;state.offsetletwriteevstate=tryOk(write_exnevstate)withWrite_errorerr->Errorerrletwrite_optevstate=trySome(write_exnevstate)withWrite_error_->Noneletto_bytes_exn?(buffer_size=128)ev=matchEncoding.classifyewith|`Fixedn->(* Preallocate the complete buffer *)letstate={buffer=Bytes.createn;offset=0;allowed_bytes=Uint_option.somen;}inwrite_recestatev;state.buffer|`Dynamic|`Variable->(* Preallocate a minimal buffer and let's not hardcode a
limit to its extension. *)letstate={buffer=Bytes.createbuffer_size;offset=0;allowed_bytes=Uint_option.none;}inwrite_recestatev;Bytes.substate.buffer0state.offsetletto_bytes_opt?buffer_sizeev=Option.iter(funbuffer_size->ifbuffer_size<0thenStdlib.raise(Invalid_argument"Data_encoding.Binary_writer.to_bytes_opt: negative length"))buffer_size;trySome(to_bytes_exn?buffer_sizeev)withWrite_error_->Noneletto_bytes?buffer_sizeev=Option.iter(funbuffer_size->ifbuffer_size<0thenStdlib.raise(Invalid_argument"Data_encoding.Binary_writer.to_bytes: negative length"))buffer_size;tryOk(to_bytes_exn?buffer_sizeev)withWrite_errorerr->Errorerrletto_bytes_exn?buffer_sizeev=Option.iter(funbuffer_size->ifbuffer_size<0thenStdlib.raise(Invalid_argument"Data_encoding.Binary_writer.to_bytes: negative length"))buffer_size;to_bytes_exn?buffer_sizeevletto_string_opt?buffer_sizeev=Option.mapBytes.unsafe_to_string(to_bytes_opt?buffer_sizeev)letto_string?buffer_sizeev=Result.mapBytes.unsafe_to_string(to_bytes?buffer_sizeev)letto_string_exn?buffer_sizeev=Bytes.unsafe_to_string(to_bytes_exn?buffer_sizeev)