mirror of
https://github.com/vim/vim.git
synced 2025-08-26 20:03:41 -04:00
patch 9.1.0980: no support for base64 en-/decoding functions in Vim Script
Problem: no support for base64 en-/decoding functions in Vim Script (networkhermit) Solution: Add the base64_encode() and base64_decode() functions (Yegappan Lakshmanan) fixes: #16291 closes: #16330 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
48fa3198b7
commit
810785c689
@ -1,4 +1,4 @@
|
|||||||
*builtin.txt* For Vim version 9.1. Last change: 2024 Dec 03
|
*builtin.txt* For Vim version 9.1. Last change: 2024 Dec 30
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -67,6 +67,8 @@ autocmd_get([{opts}]) List return a list of autocmds
|
|||||||
balloon_gettext() String current text in the balloon
|
balloon_gettext() String current text in the balloon
|
||||||
balloon_show({expr}) none show {expr} inside the balloon
|
balloon_show({expr}) none show {expr} inside the balloon
|
||||||
balloon_split({msg}) List split {msg} as used for a balloon
|
balloon_split({msg}) List split {msg} as used for a balloon
|
||||||
|
base64_decode({string}) Blob base-64 decode {string} characters
|
||||||
|
base64_encode({blob}) String base-64 encode the bytes in {blob}
|
||||||
bindtextdomain({package}, {path})
|
bindtextdomain({package}, {path})
|
||||||
Bool bind text domain to specified path
|
Bool bind text domain to specified path
|
||||||
blob2list({blob}) List convert {blob} into a list of numbers
|
blob2list({blob}) List convert {blob} into a list of numbers
|
||||||
@ -1169,6 +1171,43 @@ autocmd_get([{opts}]) *autocmd_get()*
|
|||||||
Return type: list<dict<any>>
|
Return type: list<dict<any>>
|
||||||
|
|
||||||
|
|
||||||
|
base64_decode({string}) *base64_decode()*
|
||||||
|
Return a Blob containing the bytes decoded from the base64
|
||||||
|
characters in {string}.
|
||||||
|
|
||||||
|
The {string} argument should contain only base64-encoded
|
||||||
|
characters and should have a length that is a multiple of 4.
|
||||||
|
|
||||||
|
Returns an empty blob on error.
|
||||||
|
|
||||||
|
Examples: >
|
||||||
|
" Write the decoded contents to a binary file
|
||||||
|
call writefile(base64_decode(s), 'tools.bmp')
|
||||||
|
" Decode a base64-encoded string
|
||||||
|
echo list2str(blob2list(base64_decode(encodedstr)))
|
||||||
|
<
|
||||||
|
Can also be used as a |method|: >
|
||||||
|
GetEncodedString()->base64_decode()
|
||||||
|
<
|
||||||
|
Return type: |Blob|
|
||||||
|
|
||||||
|
|
||||||
|
base64_encode({blob}) *base64_encode()*
|
||||||
|
Return a base64-encoded String representing the bytes in
|
||||||
|
{blob}. The base64 alphabet defined in RFC 4648 is used.
|
||||||
|
|
||||||
|
Examples: >
|
||||||
|
" Encode the contents of a binary file
|
||||||
|
echo base64_encode(readblob('somefile.bin'))
|
||||||
|
" Encode a string
|
||||||
|
echo base64_encode(list2blob(str2list(somestr)))
|
||||||
|
<
|
||||||
|
Can also be used as a |method|: >
|
||||||
|
GetBinaryData()->base64_encode()
|
||||||
|
<
|
||||||
|
Return type: |String|
|
||||||
|
|
||||||
|
|
||||||
balloon_gettext() *balloon_gettext()*
|
balloon_gettext() *balloon_gettext()*
|
||||||
Return the current text in the balloon. Only for the string,
|
Return the current text in the balloon. Only for the string,
|
||||||
not used for the List. Returns an empty string if balloon
|
not used for the List. Returns an empty string if balloon
|
||||||
|
@ -6164,6 +6164,8 @@ balloon_show() builtin.txt /*balloon_show()*
|
|||||||
balloon_split() builtin.txt /*balloon_split()*
|
balloon_split() builtin.txt /*balloon_split()*
|
||||||
bar motion.txt /*bar*
|
bar motion.txt /*bar*
|
||||||
bars help.txt /*bars*
|
bars help.txt /*bars*
|
||||||
|
base64_decode() builtin.txt /*base64_decode()*
|
||||||
|
base64_encode() builtin.txt /*base64_encode()*
|
||||||
base_font_name_list mbyte.txt /*base_font_name_list*
|
base_font_name_list mbyte.txt /*base_font_name_list*
|
||||||
basic.vim syntax.txt /*basic.vim*
|
basic.vim syntax.txt /*basic.vim*
|
||||||
beep options.txt /*beep*
|
beep options.txt /*beep*
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
*todo.txt* For Vim version 9.1. Last change: 2024 Dec 16
|
*todo.txt* For Vim version 9.1. Last change: 2024 Dec 30
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -4198,8 +4198,6 @@ Vim script language:
|
|||||||
char2hex() convert char string to hex string.
|
char2hex() convert char string to hex string.
|
||||||
crypt() encrypt string
|
crypt() encrypt string
|
||||||
decrypt() decrypt string
|
decrypt() decrypt string
|
||||||
base64enc() base 64 encoding
|
|
||||||
base64dec() base 64 decoding
|
|
||||||
attributes() return file protection flags "drwxrwxrwx"
|
attributes() return file protection flags "drwxrwxrwx"
|
||||||
shorten(fname) shorten a file name, like home_replace()
|
shorten(fname) shorten a file name, like home_replace()
|
||||||
perl(cmd) call Perl and return string
|
perl(cmd) call Perl and return string
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
*usr_41.txt* For Vim version 9.1. Last change: 2024 Nov 11
|
*usr_41.txt* For Vim version 9.1. Last change: 2024 Dec 30
|
||||||
|
|
||||||
VIM USER MANUAL - by Bram Moolenaar
|
VIM USER MANUAL - by Bram Moolenaar
|
||||||
|
|
||||||
@ -1263,6 +1263,8 @@ Inter-process communication: *channel-functions*
|
|||||||
json_decode() decode a JSON string to Vim types
|
json_decode() decode a JSON string to Vim types
|
||||||
js_encode() encode an expression to a JSON string
|
js_encode() encode an expression to a JSON string
|
||||||
js_decode() decode a JSON string to Vim types
|
js_decode() decode a JSON string to Vim types
|
||||||
|
base64_encode() encode a blob into a base64 string
|
||||||
|
base64_decode() decode a base64 string into a blob
|
||||||
err_teapot() give error 418 or 503
|
err_teapot() give error 418 or 503
|
||||||
|
|
||||||
Jobs: *job-functions*
|
Jobs: *job-functions*
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
*version9.txt* For Vim version 9.1. Last change: 2024 Dec 29
|
*version9.txt* For Vim version 9.1. Last change: 2024 Dec 30
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -41629,13 +41629,15 @@ Various syntax, indent and other plugins were added.
|
|||||||
|
|
||||||
Functions: ~
|
Functions: ~
|
||||||
|
|
||||||
|
|base64_decode()| decode a base64 string into a blob
|
||||||
|
|base64_encode()| encode a blob into a base64 string
|
||||||
|bindtextdomain()| set message lookup translation base path
|
|bindtextdomain()| set message lookup translation base path
|
||||||
|diff()| diff two Lists of strings
|
|diff()| diff two Lists of strings
|
||||||
|filecopy()| copy a file {from} to {to}
|
|filecopy()| copy a file {from} to {to}
|
||||||
|foreach()| apply function to List items
|
|foreach()| apply function to List items
|
||||||
|
|getcellpixels()| get List of terminal cell pixel size
|
||||||
|getcmdcomplpat()| Shell command line completion
|
|getcmdcomplpat()| Shell command line completion
|
||||||
|getcmdprompt()| get prompt for input()/confirm()
|
|getcmdprompt()| get prompt for input()/confirm()
|
||||||
|getcellpixels()| get List of terminal cell pixel size
|
|
||||||
|getregion()| get a region of text from a buffer
|
|getregion()| get a region of text from a buffer
|
||||||
|getregionpos()| get a list of positions for a region
|
|getregionpos()| get a list of positions for a region
|
||||||
|id()| get unique identifier for a Dict, List, Object,
|
|id()| get unique identifier for a Dict, List, Object,
|
||||||
|
182
src/evalfunc.c
182
src/evalfunc.c
@ -28,6 +28,8 @@ static void f_balloon_show(typval_T *argvars, typval_T *rettv);
|
|||||||
static void f_balloon_split(typval_T *argvars, typval_T *rettv);
|
static void f_balloon_split(typval_T *argvars, typval_T *rettv);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
static void f_base64_encode(typval_T *argvars, typval_T *rettv);
|
||||||
|
static void f_base64_decode(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_bindtextdomain(typval_T *argvars, typval_T *rettv);
|
static void f_bindtextdomain(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_byte2line(typval_T *argvars, typval_T *rettv);
|
static void f_byte2line(typval_T *argvars, typval_T *rettv);
|
||||||
static void f_call(typval_T *argvars, typval_T *rettv);
|
static void f_call(typval_T *argvars, typval_T *rettv);
|
||||||
@ -1834,6 +1836,10 @@ static funcentry_T global_functions[] =
|
|||||||
NULL
|
NULL
|
||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
|
{"base64_decode", 1, 1, FEARG_1, arg1_string,
|
||||||
|
ret_blob, f_base64_decode},
|
||||||
|
{"base64_encode", 1, 1, FEARG_1, arg1_blob,
|
||||||
|
ret_string, f_base64_encode},
|
||||||
{"bindtextdomain", 2, 2, 0, arg2_string,
|
{"bindtextdomain", 2, 2, 0, arg2_string,
|
||||||
ret_bool, f_bindtextdomain},
|
ret_bool, f_bindtextdomain},
|
||||||
{"blob2list", 1, 1, FEARG_1, arg1_blob,
|
{"blob2list", 1, 1, FEARG_1, arg1_blob,
|
||||||
@ -3479,6 +3485,182 @@ f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Base64 character set
|
||||||
|
static const char_u base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
|
||||||
|
// Base64 decoding table (initialized in init_base64_dec_table() below)
|
||||||
|
static char_u base64_dec_table[256];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the base64 decoding table
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
init_base64_dec_table(void)
|
||||||
|
{
|
||||||
|
static int base64_dec_tbl_initialized = FALSE;
|
||||||
|
|
||||||
|
if (base64_dec_tbl_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Unsupported characters are set to 0xFF
|
||||||
|
vim_memset(base64_dec_table, 0xFF, sizeof(base64_dec_table));
|
||||||
|
|
||||||
|
// Initialize the index for the base64 alphabets
|
||||||
|
for (size_t i = 0; i < sizeof(base64_table) - 1; i++)
|
||||||
|
base64_dec_table[(char_u)base64_table[i]] = (char_u)i;
|
||||||
|
|
||||||
|
// base64 padding character
|
||||||
|
base64_dec_table['='] = 0;
|
||||||
|
|
||||||
|
base64_dec_tbl_initialized = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode the bytes in "blob" using base-64 encoding.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
base64_encode(blob_T *blob)
|
||||||
|
{
|
||||||
|
size_t input_len = blob->bv_ga.ga_len;
|
||||||
|
size_t encoded_len = ((input_len + 2) / 3) * 4;
|
||||||
|
char_u *data = blob->bv_ga.ga_data;
|
||||||
|
|
||||||
|
char_u *encoded = alloc(encoded_len + 1);
|
||||||
|
if (encoded == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t i, j;
|
||||||
|
for (i = 0, j = 0; i < input_len;)
|
||||||
|
{
|
||||||
|
int_u octet_a = i < input_len ? data[i++] : 0;
|
||||||
|
int_u octet_b = i < input_len ? data[i++] : 0;
|
||||||
|
int_u octet_c = i < input_len ? data[i++] : 0;
|
||||||
|
|
||||||
|
int_u triple = (octet_a << 16) | (octet_b << 8) | octet_c;
|
||||||
|
|
||||||
|
encoded[j++] = base64_table[(triple >> 18) & 0x3F];
|
||||||
|
encoded[j++] = base64_table[(triple >> 12) & 0x3F];
|
||||||
|
encoded[j++] = (!octet_b && i >= input_len) ? '='
|
||||||
|
: base64_table[(triple >> 6) & 0x3F];
|
||||||
|
encoded[j++] = (!octet_c && i >= input_len) ? '='
|
||||||
|
: base64_table[triple & 0x3F];
|
||||||
|
}
|
||||||
|
encoded[j] = NUL;
|
||||||
|
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode the string "data" using base-64 encoding.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
base64_decode(const char_u *data, blob_T *blob)
|
||||||
|
{
|
||||||
|
size_t input_len = STRLEN(data);
|
||||||
|
|
||||||
|
if (input_len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (input_len % 4 != 0)
|
||||||
|
{
|
||||||
|
// Invalid input length
|
||||||
|
semsg(_(e_invalid_argument_str), data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_base64_dec_table();
|
||||||
|
|
||||||
|
size_t decoded_len = (input_len / 4) * 3;
|
||||||
|
if (data[input_len - 1] == '=')
|
||||||
|
decoded_len--;
|
||||||
|
if (data[input_len - 2] == '=')
|
||||||
|
decoded_len--;
|
||||||
|
|
||||||
|
size_t i, j;
|
||||||
|
for (i = 0, j = 0; i < input_len;)
|
||||||
|
{
|
||||||
|
int_u sextet_a = base64_dec_table[(char_u)data[i++]];
|
||||||
|
int_u sextet_b = base64_dec_table[(char_u)data[i++]];
|
||||||
|
int_u sextet_c = base64_dec_table[(char_u)data[i++]];
|
||||||
|
int_u sextet_d = base64_dec_table[(char_u)data[i++]];
|
||||||
|
|
||||||
|
if (sextet_a == 0xFF || sextet_b == 0xFF || sextet_c == 0xFF
|
||||||
|
|| sextet_d == 0xFF)
|
||||||
|
{
|
||||||
|
// Invalid character
|
||||||
|
semsg(_(e_invalid_argument_str), data);
|
||||||
|
ga_clear(&blob->bv_ga);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_u triple = (sextet_a << 18) | (sextet_b << 12)
|
||||||
|
| (sextet_c << 6) | sextet_d;
|
||||||
|
|
||||||
|
if (j < decoded_len)
|
||||||
|
{
|
||||||
|
ga_append(&blob->bv_ga, (triple >> 16) & 0xFF);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (j < decoded_len)
|
||||||
|
{
|
||||||
|
ga_append(&blob->bv_ga, (triple >> 8) & 0xFF);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (j < decoded_len)
|
||||||
|
{
|
||||||
|
ga_append(&blob->bv_ga, triple & 0xFF);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == decoded_len)
|
||||||
|
{
|
||||||
|
// Check for invalid padding bytes (based on the
|
||||||
|
// "Base64 Malleability in Practice" ACM paper).
|
||||||
|
if ((data[input_len - 2] == '=' && ((sextet_b & 0xF) != 0))
|
||||||
|
|| ((data[input_len - 1] == '=') && ((sextet_c & 0x3) != 0)))
|
||||||
|
{
|
||||||
|
semsg(_(e_invalid_argument_str), data);
|
||||||
|
ga_clear(&blob->bv_ga);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "base64_decode(string)" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_base64_decode(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
if (check_for_string_arg(argvars, 0) == FAIL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (rettv_blob_alloc(rettv) == FAIL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char_u *str = tv_get_string_chk(&argvars[0]);
|
||||||
|
if (str != NULL)
|
||||||
|
base64_decode(str, rettv->vval.v_blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "base64_encode(blob)" function
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
f_base64_encode(typval_T *argvars, typval_T *rettv)
|
||||||
|
{
|
||||||
|
if (check_for_blob_arg(argvars, 0) == FAIL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
rettv->v_type = VAR_STRING;
|
||||||
|
rettv->vval.v_string = NULL;
|
||||||
|
|
||||||
|
blob_T *blob = argvars->vval.v_blob;
|
||||||
|
if (blob != NULL)
|
||||||
|
rettv->vval.v_string = base64_encode(blob);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the buffer from "arg" and give an error and return NULL if it is not
|
* Get the buffer from "arg" and give an error and return NULL if it is not
|
||||||
* valid.
|
* valid.
|
||||||
|
@ -4206,4 +4206,55 @@ func Test_getcellpixels_gui()
|
|||||||
endif
|
endif
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Str2Blob(s)
|
||||||
|
return list2blob(str2list(a:s))
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Blob2Str(b)
|
||||||
|
return list2str(blob2list(a:b))
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for the base64_encode() and base64_decode() functions
|
||||||
|
func Test_base64_encoding()
|
||||||
|
let lines =<< trim END
|
||||||
|
#" Test for encoding/decoding the RFC-4648 alphabets
|
||||||
|
VAR s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||||
|
for i in range(64)
|
||||||
|
call assert_equal($'{s[i]}A==', base64_encode(list2blob([i << 2])))
|
||||||
|
call assert_equal(list2blob([i << 2]), base64_decode($'{s[i]}A=='))
|
||||||
|
endfor
|
||||||
|
|
||||||
|
#" Test for encoding with padding
|
||||||
|
call assert_equal('TQ==', base64_encode(g:Str2Blob("M")))
|
||||||
|
call assert_equal('TWE=', base64_encode(g:Str2Blob("Ma")))
|
||||||
|
call assert_equal('TWFu', g:Str2Blob("Man")->base64_encode())
|
||||||
|
call assert_equal('', base64_encode(0z))
|
||||||
|
call assert_equal('', base64_encode(g:Str2Blob("")))
|
||||||
|
|
||||||
|
#" Test for decoding with padding
|
||||||
|
call assert_equal('light work.', g:Blob2Str(base64_decode("bGlnaHQgd29yay4=")))
|
||||||
|
call assert_equal('light work', g:Blob2Str(base64_decode("bGlnaHQgd29yaw==")))
|
||||||
|
call assert_equal('light wor', g:Blob2Str("bGlnaHQgd29y"->base64_decode()))
|
||||||
|
call assert_equal(0z00, base64_decode("===="))
|
||||||
|
call assert_equal(0z, base64_decode(""))
|
||||||
|
|
||||||
|
#" Test for invalid padding
|
||||||
|
call assert_equal('Hello', g:Blob2Str(base64_decode("SGVsbG8=")))
|
||||||
|
call assert_fails('call base64_decode("SGVsbG9=")', 'E475:')
|
||||||
|
call assert_fails('call base64_decode("SGVsbG9")', 'E475:')
|
||||||
|
call assert_equal('Hell', g:Blob2Str(base64_decode("SGVsbA==")))
|
||||||
|
call assert_fails('call base64_decode("SGVsbA=")', 'E475:')
|
||||||
|
call assert_fails('call base64_decode("SGVsbA")', 'E475:')
|
||||||
|
call assert_fails('call base64_decode("SGVsbA====")', 'E475:')
|
||||||
|
|
||||||
|
#" Error case
|
||||||
|
call assert_fails('call base64_decode("b")', 'E475: Invalid argument: b')
|
||||||
|
call assert_fails('call base64_decode("<<==")', 'E475: Invalid argument: <<==')
|
||||||
|
|
||||||
|
call assert_fails('call base64_encode([])', 'E1238: Blob required for argument 1')
|
||||||
|
call assert_fails('call base64_decode([])', 'E1174: String required for argument 1')
|
||||||
|
END
|
||||||
|
call v9.CheckLegacyAndVim9Success(lines)
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
980,
|
||||||
/**/
|
/**/
|
||||||
979,
|
979,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user