Skip to content

Commit

Permalink
Merge functions since there are no more options
Browse files Browse the repository at this point in the history
  • Loading branch information
groves committed Aug 4, 2022
1 parent 1fe6bcb commit 122ec1c
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 77 deletions.
102 changes: 26 additions & 76 deletions helix-view/src/base64/mod.rs
Original file line number Diff line number Diff line change
@@ -1,86 +1,37 @@
use std::ops::{BitAnd, BitOr, Shl, Shr};

pub fn encode<T: AsRef<[u8]>>(input: T) -> String {
let encoded_size =
encoded_len(input.as_ref().len()).expect("integer overflow when calculating buffer size");
let mut buf = vec![0; encoded_size];

encode_with_padding(input.as_ref(), &mut buf[..], encoded_size);

String::from_utf8(buf).expect("Invalid UTF8")
}

pub fn encoded_len(bytes_len: usize) -> Option<usize> {
let rem = bytes_len % 3;

let complete_input_chunks = bytes_len / 3;
let complete_chunk_output = complete_input_chunks.checked_mul(4);

if rem > 0 {
complete_chunk_output.and_then(|c| c.checked_add(4))
} else {
complete_chunk_output
}
}

fn encode_with_padding(input: &[u8], output: &mut [u8], expected_encoded_size: usize) {
debug_assert_eq!(expected_encoded_size, output.len());

let b64_bytes_written = encode_bytes(input, output);

let padding_bytes = add_padding(input.len(), &mut output[b64_bytes_written..]);

let encoded_bytes = b64_bytes_written
.checked_add(padding_bytes)
.expect("usize overflow when calculating b64 length");

debug_assert_eq!(expected_encoded_size, encoded_bytes);
}

pub fn add_padding(input_len: usize, output: &mut [u8]) -> usize {
// TODO base on encoded len to use cheaper mod by 4 (aka & 7)
let rem = input_len % 3;
let mut bytes_written = 0;
for _ in 0..((3 - rem) % 3) {
output[bytes_written] = PAD_BYTE;
bytes_written += 1;
}

bytes_written
}
const PAD_BYTE: u8 = b'=';
const ENCODE_TABLE: &[u8] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".as_bytes();
const LOW_SIX_BITS: u32 = 0x3F;

fn encode_bytes(input: &[u8], output: &mut [u8]) -> usize {
// complete chunks first
pub fn encode(input: &[u8]) -> String {
let rem = input.len() % 3;
let complete_chunks = input.len() / 3;
let remainder_chunk = if rem == 0 { 0 } else { 1 };
let encoded_size = (complete_chunks + remainder_chunk) * 4;

const LOW_SIX_BITS: u32 = 0x3F;
let mut output = vec![0; encoded_size];

let rem = input.len() % 3;
// will never underflow
// complete chunks first
let complete_chunk_len = input.len() - rem;

let mut input_index = 0_usize;
let mut output_index = 0_usize;
if let Some(last_complete_chunk_index) = complete_chunk_len.checked_sub(3) {
while input_index <= last_complete_chunk_index {
let chunk = &input[input_index..input_index + 3];

// populate low 24 bits from 3 bytes
let chunk_int: u32 =
(chunk[0] as u32).shl(16) | (chunk[1] as u32).shl(8) | (chunk[2] as u32);
// encode 4x 6-bit output bytes
output[output_index] = ENCODE_TABLE[chunk_int.shr(18) as usize];
output[output_index + 1] =
ENCODE_TABLE[chunk_int.shr(12_u8).bitand(LOW_SIX_BITS) as usize];
output[output_index + 2] =
ENCODE_TABLE[chunk_int.shr(6_u8).bitand(LOW_SIX_BITS) as usize];
output[output_index + 3] = ENCODE_TABLE[chunk_int.bitand(LOW_SIX_BITS) as usize];

input_index += 3;
output_index += 4;
}
while input_index < complete_chunk_len {
let chunk = &input[input_index..input_index + 3];

// populate low 24 bits from 3 bytes
let chunk_int: u32 =
(chunk[0] as u32).shl(16) | (chunk[1] as u32).shl(8) | (chunk[2] as u32);
// encode 4x 6-bit output bytes
output[output_index] = ENCODE_TABLE[chunk_int.shr(18) as usize];
output[output_index + 1] = ENCODE_TABLE[chunk_int.shr(12_u8).bitand(LOW_SIX_BITS) as usize];
output[output_index + 2] = ENCODE_TABLE[chunk_int.shr(6_u8).bitand(LOW_SIX_BITS) as usize];
output[output_index + 3] = ENCODE_TABLE[chunk_int.bitand(LOW_SIX_BITS) as usize];

input_index += 3;
output_index += 4;
}

// then leftovers
Expand All @@ -95,17 +46,16 @@ fn encode_bytes(input: &[u8], output: &mut [u8]) -> usize {
// bottom 4 bits of [1], with the 2 bottom bits as zero
output[output_index + 2] =
ENCODE_TABLE[(chunk[1].shl(2_u8) as u32).bitand(LOW_SIX_BITS) as usize];

output_index += 3;
output[output_index + 3] = PAD_BYTE;
} else if rem == 1 {
let byte = input[input_index];
output[output_index] = ENCODE_TABLE[byte.shr(2) as usize];
output[output_index + 1] =
ENCODE_TABLE[(byte.shl(4_u8) as u32).bitand(LOW_SIX_BITS) as usize];
output_index += 2;
output[output_index + 2] = PAD_BYTE;
output[output_index + 3] = PAD_BYTE;
}

output_index
String::from_utf8(output).expect("Invalid UTF8")
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion helix-view/src/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ mod provider {
impl SetClipboardCommand {
pub fn new(content: &str, clipboard_type: ClipboardType) -> Self {
Self {
encoded_content: base64::encode(content),
encoded_content: base64::encode(content.as_bytes()),
clipboard_type,
}
}
Expand Down

0 comments on commit 122ec1c

Please sign in to comment.