123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Brotli_dictionary.mli *)(*****************************************************************************)(* The words *)(*****************************************************************************)letsize=122_784(* how many words of each length, 0 to 24, as a number of bits: 2^10
* words of 4 bytes, 2^5 of 24 *)letindex_bits=[|0;0;0;0;10;10;11;11;10;10;10;10;10;9;9;8;7;7;8;7;7;6;6;5;5|](* where the words of each length start: after all the shorter ones *)letoffsets:intarray=letoffsets=Array.make260inforlength=4to24dooffsets.(length+1)<-offsets.(length)+(lengthlslindex_bits.(length))done;offsets(*****************************************************************************)(* The transforms *)(*****************************************************************************)typechange=|Identity|Ferment_first|Ferment_all|Omit_firstofint|Omit_lastofintlettransforms:(string*change*string)array=leti=Identityandf=Ferment_firstanda=Ferment_allinletfirstn=Omit_firstnandlastn=Omit_lastnin[|("",i,"");("",i," ");(" ",i," ");("",first1,"");("",f," ");("",i," the ");(" ",i,"");("s ",i," ");("",i," of ");("",f,"");("",i," and ");("",first2,"");("",last1,"");(", ",i," ");("",i,", ");(" ",f," ");("",i," in ");("",i," to ");("e ",i," ");("",i,"\"");("",i,".");("",i,"\">");("",i,"\n");("",last3,"");("",i,"]");("",i," for ");("",first3,"");("",last2,"");("",i," a ");("",i," that ");(" ",f,"");("",i,". ");(".",i,"");(" ",i,", ");("",first4,"");("",i," with ");("",i,"'");("",i," from ");("",i," by ");("",first5,"");("",first6,"");(" the ",i,"");("",last4,"");("",i,". The ");("",a,"");("",i," on ");("",i," as ");("",i," is ");("",last7,"");("",last1,"ing ");("",i,"\n\t");("",i,":");(" ",i,". ");("",i,"ed ");("",first9,"");("",first7,"");("",last6,"");("",i,"(");("",f,", ");("",last8,"");("",i," at ");("",i,"ly ");(" the ",i," of ");("",last5,"");("",last9,"");(" ",f,", ");("",f,"\"");(".",i,"(");("",a," ");("",f,"\">");("",i,"=\"");(" ",i,".");(".com/",i,"");(" the ",i," of the ");("",f,"'");("",i,". This ");("",i,",");(".",i," ");("",f,"(");("",f,".");("",i," not ");(" ",i,"=\"");("",i,"er ");(" ",a," ");("",i,"al ");(" ",a,"");("",i,"='");("",a,"\"");("",f,". ");(" ",i,"(");("",i,"ful ");(" ",f,". ");("",i,"ive ");("",i,"less ");("",a,"'");("",i,"est ");(" ",f,".");("",a,"\">");(" ",i,"='");("",f,",");("",i,"ize ");("",a,".");("\xC2\xA0",i,"");(" ",i,",");("",f,"=\"");("",a,"=\"");("",i,"ous ");("",a,", ");("",f,"='");(" ",f,",");(" ",a,"=\"");(" ",a,", ");("",a,",");("",a,"(");("",a,". ");(" ",a,".");("",a,"='");(" ",a,". ");(" ",f,"=\"");(" ",a,"='");(" ",f,"='");|](* the character at [pos] to its capital, the UTF-8 way: a byte under
* 192 is a character by itself, capitalized if a to z; a byte under
* 224 starts a character of 2 bytes (Latin, Greek, Cyrillic), over, of
* 3; their capitals are guessed by flipping a bit or two of the last
* byte. How many bytes the character has. *)letferment(word:Bytes.t)(pos:int):int=letflipimask=ifi<Bytes.lengthwordthenBytes.setwordi(Char.chr(Char.code(Bytes.getwordi)lxormask))inletc=Char.code(Bytes.getwordpos)inifc<192thenbeginifc>=Char.code'a'&&c<=Char.code'z'thenflippos32;1endelseifc<224thenbeginflip(pos+1)32;2endelsebeginflip(pos+2)5;3endlettransform(id:int)(word:string):string=ifid<0||id>=Array.lengthtransformsthenfailwith"Brotli: a transform that doesn't exist";letprefix,change,suffix=transforms.(id)inletn=String.lengthwordinletchanged=matchchangewith|Identity->word|Omit_firstk->ifk>nthen""elseString.subwordk(n-k)|Omit_lastk->ifk>nthen""elseString.subword0(n-k)|Ferment_first|Ferment_all->letb=Bytes.of_stringwordinletpos=ref0inwhile!pos<n&&(!pos=0||change=Ferment_all)dopos:=!pos+fermentb!posdone;Bytes.to_stringbinprefix^changed^suffix(*****************************************************************************)(* Entry point *)(*****************************************************************************)letword(dictionary:string)~(length:int)~(id:int):string=ifString.lengthdictionary<>sizethenfailwith"Brotli: not the dictionary (it has 122,784 bytes)";iflength<4||length>24thenfailwith"Brotli: a dictionary word shorter than 4 bytes or longer than 24";letindex=idland((1lslindex_bits.(length))-1)intransform(idlsrindex_bits.(length))(String.subdictionary(offsets.(length)+(index*length))length)