@@ -28,6 +28,8 @@ static void f_balloon_show(typval_T *argvars, typval_T *rettv);
2828static void f_balloon_split (typval_T * argvars , typval_T * rettv );
2929# endif
3030#endif
31+ static void f_base64_encode (typval_T * argvars , typval_T * rettv );
32+ static void f_base64_decode (typval_T * argvars , typval_T * rettv );
3133static void f_bindtextdomain (typval_T * argvars , typval_T * rettv );
3234static void f_byte2line (typval_T * argvars , typval_T * rettv );
3335static void f_call (typval_T * argvars , typval_T * rettv );
@@ -1834,6 +1836,10 @@ static funcentry_T global_functions[] =
18341836 NULL
18351837#endif
18361838 },
1839+ {"base64_decode" , 1 , 1 , FEARG_1 , arg1_string ,
1840+ ret_blob , f_base64_decode },
1841+ {"base64_encode" , 1 , 1 , FEARG_1 , arg1_blob ,
1842+ ret_string , f_base64_encode },
18371843 {"bindtextdomain" , 2 , 2 , 0 , arg2_string ,
18381844 ret_bool , f_bindtextdomain },
18391845 {"blob2list" , 1 , 1 , FEARG_1 , arg1_blob ,
@@ -3479,6 +3485,182 @@ f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
34793485# endif
34803486#endif
34813487
3488+ // Base64 character set
3489+ static const char_u base64_table [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
3490+
3491+ // Base64 decoding table (initialized in init_base64_dec_table() below)
3492+ static char_u base64_dec_table [256 ];
3493+
3494+ /*
3495+ * Initialize the base64 decoding table
3496+ */
3497+ static void
3498+ init_base64_dec_table (void )
3499+ {
3500+ static int base64_dec_tbl_initialized = FALSE;
3501+
3502+ if (base64_dec_tbl_initialized )
3503+ return ;
3504+
3505+ // Unsupported characters are set to 0xFF
3506+ vim_memset (base64_dec_table , 0xFF , sizeof (base64_dec_table ));
3507+
3508+ // Initialize the index for the base64 alphabets
3509+ for (size_t i = 0 ; i < sizeof (base64_table ) - 1 ; i ++ )
3510+ base64_dec_table [(char_u )base64_table [i ]] = (char_u )i ;
3511+
3512+ // base64 padding character
3513+ base64_dec_table ['=' ] = 0 ;
3514+
3515+ base64_dec_tbl_initialized = TRUE;
3516+ }
3517+
3518+ /*
3519+ * Encode the bytes in "blob" using base-64 encoding.
3520+ */
3521+ static char_u *
3522+ base64_encode (blob_T * blob )
3523+ {
3524+ size_t input_len = blob -> bv_ga .ga_len ;
3525+ size_t encoded_len = ((input_len + 2 ) / 3 ) * 4 ;
3526+ char_u * data = blob -> bv_ga .ga_data ;
3527+
3528+ char_u * encoded = alloc (encoded_len + 1 );
3529+ if (encoded == NULL )
3530+ return NULL ;
3531+
3532+ size_t i , j ;
3533+ for (i = 0 , j = 0 ; i < input_len ;)
3534+ {
3535+ int_u octet_a = i < input_len ? data [i ++ ] : 0 ;
3536+ int_u octet_b = i < input_len ? data [i ++ ] : 0 ;
3537+ int_u octet_c = i < input_len ? data [i ++ ] : 0 ;
3538+
3539+ int_u triple = (octet_a << 16 ) | (octet_b << 8 ) | octet_c ;
3540+
3541+ encoded [j ++ ] = base64_table [(triple >> 18 ) & 0x3F ];
3542+ encoded [j ++ ] = base64_table [(triple >> 12 ) & 0x3F ];
3543+ encoded [j ++ ] = (!octet_b && i >= input_len ) ? '='
3544+ : base64_table [(triple >> 6 ) & 0x3F ];
3545+ encoded [j ++ ] = (!octet_c && i >= input_len ) ? '='
3546+ : base64_table [triple & 0x3F ];
3547+ }
3548+ encoded [j ] = NUL ;
3549+
3550+ return encoded ;
3551+ }
3552+
3553+ /*
3554+ * Decode the string "data" using base-64 encoding.
3555+ */
3556+ static void
3557+ base64_decode (const char_u * data , blob_T * blob )
3558+ {
3559+ size_t input_len = STRLEN (data );
3560+
3561+ if (input_len == 0 )
3562+ return ;
3563+
3564+ if (input_len % 4 != 0 )
3565+ {
3566+ // Invalid input length
3567+ semsg (_ (e_invalid_argument_str ), data );
3568+ return ;
3569+ }
3570+
3571+ init_base64_dec_table ();
3572+
3573+ size_t decoded_len = (input_len / 4 ) * 3 ;
3574+ if (data [input_len - 1 ] == '=' )
3575+ decoded_len -- ;
3576+ if (data [input_len - 2 ] == '=' )
3577+ decoded_len -- ;
3578+
3579+ size_t i , j ;
3580+ for (i = 0 , j = 0 ; i < input_len ;)
3581+ {
3582+ int_u sextet_a = base64_dec_table [(char_u )data [i ++ ]];
3583+ int_u sextet_b = base64_dec_table [(char_u )data [i ++ ]];
3584+ int_u sextet_c = base64_dec_table [(char_u )data [i ++ ]];
3585+ int_u sextet_d = base64_dec_table [(char_u )data [i ++ ]];
3586+
3587+ if (sextet_a == 0xFF || sextet_b == 0xFF || sextet_c == 0xFF
3588+ || sextet_d == 0xFF )
3589+ {
3590+ // Invalid character
3591+ semsg (_ (e_invalid_argument_str ), data );
3592+ ga_clear (& blob -> bv_ga );
3593+ return ;
3594+ }
3595+
3596+ int_u triple = (sextet_a << 18 ) | (sextet_b << 12 )
3597+ | (sextet_c << 6 ) | sextet_d ;
3598+
3599+ if (j < decoded_len )
3600+ {
3601+ ga_append (& blob -> bv_ga , (triple >> 16 ) & 0xFF );
3602+ j ++ ;
3603+ }
3604+ if (j < decoded_len )
3605+ {
3606+ ga_append (& blob -> bv_ga , (triple >> 8 ) & 0xFF );
3607+ j ++ ;
3608+ }
3609+ if (j < decoded_len )
3610+ {
3611+ ga_append (& blob -> bv_ga , triple & 0xFF );
3612+ j ++ ;
3613+ }
3614+
3615+ if (j == decoded_len )
3616+ {
3617+ // Check for invalid padding bytes (based on the
3618+ // "Base64 Malleability in Practice" ACM paper).
3619+ if ((data [input_len - 2 ] == '=' && ((sextet_b & 0xF ) != 0 ))
3620+ || ((data [input_len - 1 ] == '=' ) && ((sextet_c & 0x3 ) != 0 )))
3621+ {
3622+ semsg (_ (e_invalid_argument_str ), data );
3623+ ga_clear (& blob -> bv_ga );
3624+ return ;
3625+ }
3626+ }
3627+ }
3628+ }
3629+
3630+ /*
3631+ * "base64_decode(string)" function
3632+ */
3633+ static void
3634+ f_base64_decode (typval_T * argvars , typval_T * rettv )
3635+ {
3636+ if (check_for_string_arg (argvars , 0 ) == FAIL )
3637+ return ;
3638+
3639+ if (rettv_blob_alloc (rettv ) == FAIL )
3640+ return ;
3641+
3642+ char_u * str = tv_get_string_chk (& argvars [0 ]);
3643+ if (str != NULL )
3644+ base64_decode (str , rettv -> vval .v_blob );
3645+ }
3646+
3647+ /*
3648+ * "base64_encode(blob)" function
3649+ */
3650+ static void
3651+ f_base64_encode (typval_T * argvars , typval_T * rettv )
3652+ {
3653+ if (check_for_blob_arg (argvars , 0 ) == FAIL )
3654+ return ;
3655+
3656+ rettv -> v_type = VAR_STRING ;
3657+ rettv -> vval .v_string = NULL ;
3658+
3659+ blob_T * blob = argvars -> vval .v_blob ;
3660+ if (blob != NULL )
3661+ rettv -> vval .v_string = base64_encode (blob );
3662+ }
3663+
34823664/*
34833665 * Get the buffer from "arg" and give an error and return NULL if it is not
34843666 * valid.
0 commit comments