@@ -206,6 +206,7 @@ impl LispEvaluator {
206206 "base58-decode" => self . eval_base58_decode ( args) ,
207207 "base58-encode" => self . eval_base58_encode ( args) ,
208208 "base64-decode" => self . eval_base64_decode ( args) ,
209+ "base64-decode-raw" => self . eval_base64_decode_raw ( args) ,
209210 "base64-encode" => self . eval_base64_encode ( args) ,
210211 "hex-decode" => self . eval_hex_decode ( args) ,
211212 "hex-encode" => self . eval_hex_encode ( args) ,
@@ -214,6 +215,7 @@ impl LispEvaluator {
214215 // Binary/byte operations for Borsh decoding
215216 "byte-at" => self . eval_byte_at ( args) ,
216217 "parse-u64-le" => self . eval_parse_u64_le ( args) ,
218+ "hex-to-u64-le" => self . eval_hex_to_u64_le ( args) ,
217219 "bytes-to-hex" => self . eval_bytes_to_hex ( args) ,
218220 // Error handling
219221 "try" => self . eval_try ( args) ,
@@ -4122,6 +4124,36 @@ impl LispEvaluator {
41224124 Ok ( Value :: String ( result) )
41234125 }
41244126
4127+ /// (base64-decode-raw base64-string) - Decode base64 to hex string (for binary data)
4128+ /// Returns hex representation, avoiding UTF-8 validation issues with binary data
4129+ fn eval_base64_decode_raw ( & mut self , args : & [ crate :: parser:: Argument ] ) -> Result < Value > {
4130+ if args. len ( ) != 1 {
4131+ return Err ( Error :: InvalidArguments {
4132+ tool : "base64-decode-raw" . to_string ( ) ,
4133+ reason : format ! ( "Expected 1 argument, got {}" , args. len( ) ) ,
4134+ } ) ;
4135+ }
4136+
4137+ let val = self . evaluate_expression ( & args[ 0 ] . value ) ?;
4138+ let input = match val {
4139+ Value :: String ( s) => s,
4140+ _ => {
4141+ return Err ( Error :: TypeError {
4142+ expected : "string" . to_string ( ) ,
4143+ got : val. type_name ( ) . to_string ( ) ,
4144+ } )
4145+ }
4146+ } ;
4147+
4148+ let decoded = base64:: engine:: general_purpose:: STANDARD
4149+ . decode ( input)
4150+ . map_err ( |e| Error :: ParseError ( format ! ( "Invalid base64: {}" , e) ) ) ?;
4151+
4152+ // Return as hex string to preserve binary data
4153+ let hex_string = hex:: encode ( decoded) ;
4154+ Ok ( Value :: String ( hex_string) )
4155+ }
4156+
41254157 /// (hex-encode string) - Encode string to hexadecimal
41264158 fn eval_hex_encode ( & mut self , args : & [ crate :: parser:: Argument ] ) -> Result < Value > {
41274159 if args. len ( ) != 1 {
@@ -4322,6 +4354,61 @@ impl LispEvaluator {
43224354 Ok ( Value :: Int ( value as i64 ) )
43234355 }
43244356
4357+ /// (hex-to-u64-le hex-string offset) - Parse little-endian u64 from hex string
4358+ /// offset is in bytes (each byte = 2 hex chars)
4359+ fn eval_hex_to_u64_le ( & mut self , args : & [ crate :: parser:: Argument ] ) -> Result < Value > {
4360+ if args. len ( ) != 2 {
4361+ return Err ( Error :: InvalidArguments {
4362+ tool : "hex-to-u64-le" . to_string ( ) ,
4363+ reason : format ! ( "Expected 2 arguments, got {}" , args. len( ) ) ,
4364+ } ) ;
4365+ }
4366+
4367+ let hex_val = self . evaluate_expression ( & args[ 0 ] . value ) ?;
4368+ let offset_val = self . evaluate_expression ( & args[ 1 ] . value ) ?;
4369+
4370+ let hex_str = match hex_val {
4371+ Value :: String ( s) => s,
4372+ _ => {
4373+ return Err ( Error :: TypeError {
4374+ expected : "string" . to_string ( ) ,
4375+ got : hex_val. type_name ( ) . to_string ( ) ,
4376+ } )
4377+ }
4378+ } ;
4379+
4380+ let offset = match offset_val {
4381+ Value :: Int ( i) => i as usize ,
4382+ Value :: Float ( f) => f as usize ,
4383+ _ => {
4384+ return Err ( Error :: TypeError {
4385+ expected : "number" . to_string ( ) ,
4386+ got : offset_val. type_name ( ) . to_string ( ) ,
4387+ } )
4388+ }
4389+ } ;
4390+
4391+ // Decode hex to bytes
4392+ let bytes = hex:: decode ( & hex_str)
4393+ . map_err ( |e| Error :: ParseError ( format ! ( "Invalid hex: {}" , e) ) ) ?;
4394+
4395+ // Check bounds (offset + 8 bytes)
4396+ if offset + 8 > bytes. len ( ) {
4397+ return Err ( Error :: RuntimeError ( format ! (
4398+ "hex-to-u64-le: offset {} + 8 exceeds decoded byte length {}" ,
4399+ offset,
4400+ bytes. len( )
4401+ ) ) ) ;
4402+ }
4403+
4404+ // Parse little-endian u64
4405+ let mut buf = [ 0u8 ; 8 ] ;
4406+ buf. copy_from_slice ( & bytes[ offset..offset + 8 ] ) ;
4407+ let value = u64:: from_le_bytes ( buf) ;
4408+
4409+ Ok ( Value :: Int ( value as i64 ) )
4410+ }
4411+
43254412 /// (bytes-to-hex bytes) - Convert bytes string to hex string
43264413 fn eval_bytes_to_hex ( & mut self , args : & [ crate :: parser:: Argument ] ) -> Result < Value > {
43274414 if args. len ( ) != 1 {
0 commit comments