char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
f2e5e0e
main
1use std:: cell:: RefCell ; 2use std:: collections:: HashMap ; 3use std:: convert:: Infallible ; 4use std:: io; 5use std:: rc:: Rc ; 6 7use avril_core:: serde_v8::{ JsBuffer , ToJsBuffer }; 8use avril_core::{ Extension , Op , v8}; 9use encoding_rs::{ CoderResult , Decoder , DecoderResult , Encoding , REPLACEMENT , UTF_8 }; 10 11type DecodeArgs =( Option < u64 >, String , bool , bool , JsBuffer , bool ); 12 13struct State { 14decoder : Decoder , 15fatal : bool , 16} 17 18impl State { 19fn decode ( & mut self , bytes : & [ u8 ], stream : bool ) -> io:: Result <( String , bool )> { 20let capacity =self 21. decoder 22. max_utf8_buffer_length ( bytes. len ()) 23. ok_or_else ( || io:: Error :: other ( "Decoded string is too large" )) ?; 24let mut output =String :: new (); 25 output. try_reserve ( capacity). map_err ( io:: Error :: other) ?; 26let invalid =if self . fatal { 27let ( result, _) = 28self . decoder 29. decode_to_string_without_replacement ( bytes, & mut output, !stream); 30match result{ 31DecoderResult :: InputEmpty =>false , 32// Browsers and WPT discard the bad chunk's remainder but retain codec state. 33DecoderResult :: Malformed ( _, _) =>true , 34DecoderResult :: OutputFull =>{ 35return Err ( io:: Error :: other ( "Decoder output exceeded its size bound" )); 36} 37} 38} else { 39let ( result, _, _) =self . decoder . decode_to_string ( bytes, & mut output, !stream); 40if result ==CoderResult :: OutputFull { 41return Err ( io:: Error :: other ( "Decoder output exceeded its size bound" )); 42} 43false 44}; 45Ok (( output, invalid)) 46} 47} 48 49# [ derive ( Default )] 50struct Decoders { 51next : u64 , 52states : HashMap < u64 , State >, 53} 54 55pub fn init () ->Extension { 56let decoders =Rc :: new ( RefCell :: new ( Decoders :: default ())); 57let decode = decoders. clone (); 58Extension { 59name : "ext:encoding" , 60dependencies : & [ "ext:web" , "ext:webstreams" ], 61ops : vec! [ 62Op :: new ( "op_encoding_label" , |label : String |{ 63Ok ::< _ , Infallible >( 64Encoding :: for_label ( label. as_bytes ()) 65. filter ( |encoding|* encoding !=REPLACEMENT ) 66. map ( |encoding| encoding. name (). to_ascii_lowercase ()), 67) 68}), 69Op :: new ( 70"op_encoding_decode" , 71move |( id, label, fatal, ignore_bom, bytes, stream): DecodeArgs |{ 72let mut decoders = decode. borrow_mut (); 73let mut state =if let Some ( id) = id{ 74 decoders 75. states 76. remove ( & id) 77. ok_or_else ( || io:: Error :: other ( "Decoder is closed" )) ? 78} else { 79let encoding =Encoding :: for_label ( label. as_bytes ()) 80. filter ( |encoding|* encoding !=REPLACEMENT ) 81. ok_or_else ( || io:: Error :: other ( "Invalid encoding label" )) ?; 82let decoder =if ignore_bom{ 83 encoding. new_decoder_without_bom_handling () 84} else { 85 encoding. new_decoder_with_bom_removal () 86}; 87State { decoder, fatal} 88}; 89let ( text, invalid) = state. decode ( & bytes, stream) ?; 90let id =if stream{ 91let id =match id{ 92Some ( id) => id, 93None =>{ 94let id = decoders 95. next 96. checked_add ( 1 ) 97. filter ( |id|* id <=9_007_199_254_740_991 ) 98. ok_or_else ( ||{ 99 io:: Error :: other ( "Encoding resource IDs exhausted" ) 100}) ?; 101 decoders. next = id; 102 id 103} 104}; 105 decoders. states . insert ( id, state); 106Some ( id) 107} else { 108None 109}; 110Ok ::< _ , io:: Error >(( text, invalid, id)) 111}, 112), 113Op :: new ( "op_encoding_close" , move |id : u64 |{ 114 decoders. borrow_mut (). states . remove ( & id); 115Ok ::< _ , Infallible >(()) 116}), 117Op :: try_raw ( "op_encoding_decode_utf8" , |scope, args|{ 118let bytes: JsBuffer = 119 avril_core:: serde_v8:: from_v8 ( scope, args. get ( 0 )). map_err ( io:: Error :: other) ?; 120// Body collection already owns fixed, unshared bytes; no snapshot or decoder state. 121let text =if bytes. is_ascii () { 122 v8:: String :: new_from_one_byte ( scope, & bytes, v8:: NewStringType :: Normal ) 123} else { 124let ( text, _) =UTF_8 . decode_with_bom_removal ( & bytes); 125 v8:: String :: new ( scope, & text) 126} 127. ok_or_else ( || io:: Error :: other ( "Decoded string is too large" )) ?; 128Ok ::< _ , io:: Error >( text. into ()) 129}), 130Op :: new ( "op_encoding_encode" , |text : String |{ 131Ok ::< _ , Infallible >( ToJsBuffer :: from ( text. into_bytes ())) 132}), 133Op :: try_raw ( "op_encoding_encode_into" , |scope, args|{ 134let text = v8:: Local ::< v8:: String >:: try_from ( args. get ( 0 )) 135. map_err ( |_| io:: Error :: other ( "Expected an encoding source string" )) ?; 136let mut destination: JsBuffer = 137 avril_core:: serde_v8:: from_v8 ( scope, args. get ( 1 )). map_err ( io:: Error :: other) ?; 138let mut read =0 ; 139let written = text. write_utf8_v2 ( 140 scope, 141& mut destination, 142 v8:: WriteFlags :: kReplaceInvalidUtf8, 143Some ( & mut read), 144); 145# [ derive ( serde :: Serialize )] 146struct Counts { 147read : usize , 148written : usize , 149} 150 avril_core:: serde_v8:: to_v8 ( scope, Counts { read, written}) 151. map_err ( io:: Error :: other) 152}), 153], 154modules : & [( 155"ext:encoding/main.js" , 156include_str! ( concat! ( env! ( "OUT_DIR" ), "/encoding.js" )), 157)], 158entry_point : Some ( "ext:encoding/main.js" ), 159} 160}