Compare commits
10 commits
0493911702
...
23228d7090
Author | SHA1 | Date | |
---|---|---|---|
23228d7090 | |||
903d516af8 | |||
c5e302c9b0 | |||
![]() |
bd8cb8200b | ||
![]() |
26f0e5ed4a | ||
![]() |
beabb1bb0f | ||
![]() |
a5cac7522b | ||
d044800b1f | |||
![]() |
313b877553 | ||
841160d2d5 |
8 changed files with 249 additions and 73 deletions
48
README.md
Normal file
48
README.md
Normal file
|
@ -0,0 +1,48 @@
|
|||
Contents
|
||||
========
|
||||
- [Introduction](#introduction)
|
||||
- [Usage](#usage)
|
||||
|
||||
# Introduction
|
||||
This is a Base64 encoding library as described in [RFC4648](https://www.rfc-editor.org/rfc/rfc4648).
|
||||
This library encodes and decodes random data into ASCII characters using an appropriate
|
||||
Base64 library. It is designed to leverage the abstractions in Rust's std library
|
||||
in order to be generic over io streams. That is to say, you can read from anything
|
||||
implementing **Read** and write the encoded or decoded output to anything which
|
||||
implements **Write**.
|
||||
|
||||
# Usage
|
||||
Add the crate to your `Cargo.toml` file.
|
||||
```Toml
|
||||
# Cargo.toml
|
||||
[dependencies]
|
||||
b64 = { git = "https://git.hitchhiker-linux.org/jeang3nie/b64_rs.git" }
|
||||
```
|
||||
## Encoding
|
||||
Encoding 'Hello, World!' into a new `String`, wrapping at 76 characters and using
|
||||
the default alphabet.
|
||||
```
|
||||
use {
|
||||
std::io::Read,
|
||||
b64::Encoder,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let mut encoder = Encoder::new("Hello, World!".as_bytes(), vec![], None, Some(76));
|
||||
encoder.encode().unwrap();
|
||||
assert_eq!(encoder.output(), b"SGVsbG8sIFdvcmxkIQ==\n");
|
||||
}
|
||||
```
|
||||
|
||||
## Decoding
|
||||
```
|
||||
use {
|
||||
std::io::Read,
|
||||
b64::Decoder,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let mut decoder = Decoder::new("SGVsbG8sIFdvcmxkIQ==".as_bytes(), vec![], None, false);
|
||||
assert_eq!(decoder.decode().unwrap(), b"Hello, World!");
|
||||
}
|
||||
```
|
101
src/decode.rs
101
src/decode.rs
|
@ -3,23 +3,47 @@ use {
|
|||
std::io::{ErrorKind, Read, Write},
|
||||
};
|
||||
|
||||
/// Decodes b64 encoded data
|
||||
/// # Exammple
|
||||
/// ```
|
||||
/// # use {
|
||||
/// # std::io::Read,
|
||||
/// # b64::Decoder,
|
||||
/// # };
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// let mut decoder = Decoder::new("SGVsbG8sIFdvcmxkIQ==".as_bytes(), vec![], None, false);
|
||||
/// assert_eq!(decoder.decode().unwrap(), b"Hello, World!");
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct Decoder<R: Read, W: Write> {
|
||||
reader: R,
|
||||
writer: W,
|
||||
alphabet: B64Alphabet,
|
||||
ignore_whitespace: bool,
|
||||
}
|
||||
|
||||
impl<R: Read, W: Write> Decoder<R, W> {
|
||||
pub fn new(reader: R, writer: W, alphabet: Option<B64Alphabet>) -> Self {
|
||||
pub fn new(
|
||||
reader: R,
|
||||
writer: W,
|
||||
alphabet: Option<B64Alphabet>,
|
||||
ignore_whitespace: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
reader,
|
||||
writer,
|
||||
alphabet: alphabet.unwrap_or_default(),
|
||||
ignore_whitespace,
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes the bytes provided by `self.reader` and writes the resulting
|
||||
/// bytes into `self.writer`.
|
||||
/// # Important
|
||||
/// Both reader and writer should be buffered for good performance, as the
|
||||
/// process of decoding will perform a series of very short read and write
|
||||
/// operations.
|
||||
/// # Errors
|
||||
/// - io failure will return `Error::Io`
|
||||
/// - a character not in the alphabet, or encountering any character after
|
||||
|
@ -28,19 +52,30 @@ impl<R: Read, W: Write> Decoder<R, W> {
|
|||
/// `Error::MissingPadding`
|
||||
/// - `intError` should never be returned. If this error is recieved the code
|
||||
/// is somehow broken. Please file a bug.
|
||||
pub fn decode(&mut self) -> Result<(), Error> {
|
||||
pub fn decode(mut self) -> Result<W, Error> {
|
||||
let mut byte_reader = self.reader.bytes();
|
||||
loop {
|
||||
let mut in_buf = [0_u8; 4];
|
||||
let mut out_buf = [0_u8; 3];
|
||||
let mut num = 0_u32;
|
||||
let mut n_bytes = 0;
|
||||
loop {
|
||||
n_bytes += match self.reader.read(&mut in_buf) {
|
||||
Ok(n) => n,
|
||||
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
break;
|
||||
while n_bytes < 4 {
|
||||
match byte_reader.next() {
|
||||
Some(Ok(b)) => {
|
||||
if self.ignore_whitespace && b.is_ascii_whitespace() {
|
||||
continue;
|
||||
} else if b == b'\n' || b == b'\r' {
|
||||
continue;
|
||||
} else {
|
||||
in_buf[n_bytes] = b;
|
||||
n_bytes += 1;
|
||||
}
|
||||
}
|
||||
Some(Err(e)) if e.kind() == ErrorKind::UnexpectedEof => break,
|
||||
Some(Err(e)) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Some(Err(e)) => return Err(e.into()),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
match n_bytes {
|
||||
0 => break,
|
||||
|
@ -49,16 +84,15 @@ impl<R: Read, W: Write> Decoder<R, W> {
|
|||
}
|
||||
let mut bytes = 0;
|
||||
for (i, &c) in in_buf.iter().enumerate() {
|
||||
let c = c.into();
|
||||
num <<= 6;
|
||||
if c == self.alphabet.pad() {
|
||||
continue;
|
||||
}
|
||||
if i != bytes {
|
||||
return Err(Error::IllegalChar(c));
|
||||
return Err(Error::IllegalChar(c.into()));
|
||||
}
|
||||
let Some(idx) = self.alphabet.get(c) else {
|
||||
return Err(Error::IllegalChar(c));
|
||||
return Err(Error::IllegalChar(c.into()));
|
||||
};
|
||||
num |= u32::try_from(idx)?;
|
||||
bytes += 1;
|
||||
|
@ -70,27 +104,44 @@ impl<R: Read, W: Write> Decoder<R, W> {
|
|||
}
|
||||
self.writer.write_all(&out_buf[0..olen])?;
|
||||
}
|
||||
Ok(())
|
||||
Ok(self.writer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufReader, Read},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn decode() {
|
||||
let mut decoder = Decoder::new("SGVsbG8sIFdvcmxk".as_bytes(), vec![], None);
|
||||
decoder.decode().unwrap();
|
||||
assert_eq!(String::from_utf8(decoder.writer).unwrap(), "Hello, World");
|
||||
decoder = Decoder::new("SGVsbG8sIFdvcmxkIQ==".as_bytes(), vec![], None);
|
||||
decoder.decode().unwrap();
|
||||
assert_eq!(String::from_utf8(decoder.writer).unwrap(), "Hello, World!");
|
||||
decoder = Decoder::new("SGVsbG8sIFdvcmxkIQo=".as_bytes(), vec![], None);
|
||||
decoder.decode().unwrap();
|
||||
assert_eq!(
|
||||
String::from_utf8(decoder.writer).unwrap(),
|
||||
"Hello, World!\n"
|
||||
);
|
||||
let mut decoder = Decoder::new("SGVsbG8sIFdvcmxk".as_bytes(), vec![], None, false);
|
||||
assert_eq!(decoder.decode().unwrap(), b"Hello, World");
|
||||
decoder = Decoder::new("SGVsbG8sIFdvcmxkIQ==".as_bytes(), vec![], None, false);
|
||||
assert_eq!(decoder.decode().unwrap(), b"Hello, World!");
|
||||
decoder = Decoder::new("SGVsbG8sIFdvcmxkIQo=".as_bytes(), vec![], None, false);
|
||||
assert_eq!(decoder.decode().unwrap(), b"Hello, World!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ignore_whitespace() {
|
||||
let decoder = Decoder::new(" SG\tVsbG8sIFdvcmxkIQ==".as_bytes(), vec![], None, true);
|
||||
assert_eq!(decoder.decode().unwrap(), b"Hello, World!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_wrapped() {
|
||||
let infile = File::open("testdata/lorem_b64.txt").unwrap();
|
||||
let reader = BufReader::new(infile);
|
||||
let mut outfile = vec![];
|
||||
File::open("testdata/lorem.txt")
|
||||
.unwrap()
|
||||
.read_to_end(&mut outfile)
|
||||
.unwrap();
|
||||
let decoder = Decoder::new(reader, vec![], None, false);
|
||||
assert_eq!(decoder.decode().unwrap(), outfile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
use {
|
||||
crate::{error::Error, B64Alphabet},
|
||||
std::{
|
||||
fmt::Write,
|
||||
io::{ErrorKind, Read},
|
||||
},
|
||||
std::io::{ErrorKind, Read, Write},
|
||||
};
|
||||
|
||||
/// Encodes arbitraty data as b64 encoded ASCII text
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use {
|
||||
/// # std::io::Read,
|
||||
/// # b64::Encoder,
|
||||
/// # };
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// let mut encoder = Encoder::new("Hello, World!".as_bytes(), vec![], None, Some(76));
|
||||
/// encoder.encode().unwrap();
|
||||
/// assert_eq!(encoder.output(), b"SGVsbG8sIFdvcmxkIQ==\n");
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct Encoder<R: Read, W: Write> {
|
||||
reader: R,
|
||||
writer: W,
|
||||
|
@ -16,6 +28,10 @@ pub struct Encoder<R: Read, W: Write> {
|
|||
impl<R: Read, W: Write> Encoder<R, W> {
|
||||
/// Creates a new encoder with the given reader and writer. If alphabet is
|
||||
/// `None` the encoder will use the default rfc4648 alphabet.
|
||||
/// # Important
|
||||
/// Both reader and writer should be buffered for best performance, as the
|
||||
/// encoder will pull single bytes from the reader and write three bytes at
|
||||
/// a time into the writer.
|
||||
pub fn new(reader: R, writer: W, alphabet: Option<B64Alphabet>, wrap: Option<usize>) -> Self {
|
||||
Self {
|
||||
reader,
|
||||
|
@ -25,6 +41,11 @@ impl<R: Read, W: Write> Encoder<R, W> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn output(self) -> W {
|
||||
self.writer
|
||||
}
|
||||
|
||||
#[allow(clippy::needless_range_loop)]
|
||||
pub fn encode(&mut self) -> Result<(), Error> {
|
||||
let mut total: usize = 0;
|
||||
loop {
|
||||
|
@ -41,6 +62,11 @@ impl<R: Read, W: Write> Encoder<R, W> {
|
|||
break;
|
||||
}
|
||||
if n_bytes == 0 {
|
||||
if let Some(wrap) = self.wrap {
|
||||
if total % wrap != 0 {
|
||||
writeln!(self.writer)?;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (idx, n) in ibuf.iter().enumerate() {
|
||||
|
@ -62,58 +88,64 @@ impl<R: Read, W: Write> Encoder<R, W> {
|
|||
}
|
||||
if let Some(wrap) = self.wrap {
|
||||
for idx in 0..=3 {
|
||||
write!(self.writer, "{}", obuf[idx])?;
|
||||
self.writer.write_all(&[obuf[idx]])?;
|
||||
total += 1;
|
||||
if total % wrap == 0 {
|
||||
writeln!(self.writer)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
write!(self.writer, "{}{}{}{}", obuf[0], obuf[1], obuf[2], obuf[3])?;
|
||||
self.writer.write_all(&obuf)?;
|
||||
}
|
||||
if outlen < 4 {
|
||||
if let Some(wrap) = self.wrap {
|
||||
if total % wrap != 0 {
|
||||
writeln!(self.writer)?;
|
||||
}
|
||||
} else {
|
||||
writeln!(self.writer)?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.writer.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> Encoder<R, String> {
|
||||
pub fn output(self) -> String {
|
||||
self.writer
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::fs::{self, File};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::BufReader,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn encode() {
|
||||
let mut encoder = Encoder::new("Hello, World".as_bytes(), String::new(), None, None);
|
||||
let mut encoder = Encoder::new("Hello, World".as_bytes(), vec![], None, None);
|
||||
encoder.encode().unwrap();
|
||||
assert_eq!(encoder.output(), "SGVsbG8sIFdvcmxk");
|
||||
assert_eq!(encoder.writer, b"SGVsbG8sIFdvcmxk");
|
||||
encoder = Encoder {
|
||||
reader: "Hello, World!".as_bytes(),
|
||||
writer: String::new(),
|
||||
writer: vec![],
|
||||
alphabet: B64Alphabet::default(),
|
||||
wrap: None,
|
||||
};
|
||||
encoder.encode().unwrap();
|
||||
assert_eq!(encoder.output(), "SGVsbG8sIFdvcmxkIQ==");
|
||||
encoder = Encoder::new("Hello, World!\n".as_bytes(), String::new(), None, None);
|
||||
assert_eq!(encoder.writer, b"SGVsbG8sIFdvcmxkIQ==\n");
|
||||
encoder = Encoder::new("Hello, World!\n".as_bytes(), vec![], None, None);
|
||||
encoder.encode().unwrap();
|
||||
assert_eq!(encoder.output(), "SGVsbG8sIFdvcmxkIQo=");
|
||||
assert_eq!(encoder.writer, b"SGVsbG8sIFdvcmxkIQo=\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrapping() {
|
||||
let infile = File::open("src/testdata/lorem.txt").unwrap();
|
||||
let outfile = fs::read_to_string("src/testdata/lorem_b64.txt").unwrap();
|
||||
let mut encoder = Encoder::new(infile, String::new(), None, Some(76));
|
||||
let infile = File::open("testdata/lorem.txt").unwrap();
|
||||
let reader = BufReader::new(infile);
|
||||
let outfile = fs::read_to_string("testdata/lorem_b64.txt").unwrap();
|
||||
let mut encoder = Encoder::new(reader, vec![], None, Some(76));
|
||||
encoder.encode().unwrap();
|
||||
assert_eq!(encoder.output(), outfile);
|
||||
assert_eq!(encoder.writer, outfile.as_bytes());
|
||||
}
|
||||
}
|
||||
|
|
33
src/lib.rs
33
src/lib.rs
|
@ -1,22 +1,29 @@
|
|||
#[warn(clippy::all, clippy::pedantic)]
|
||||
pub mod decode;
|
||||
pub mod encode;
|
||||
pub mod error;
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
mod decode;
|
||||
mod encode;
|
||||
mod error;
|
||||
|
||||
pub use {decode::Decoder, encode::Encoder, error::Error as B64Error};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
/// Defines the character set used for encoding and decoding
|
||||
pub struct B64Alphabet {
|
||||
items: [char; 64],
|
||||
pad: char,
|
||||
items: [u8; 64],
|
||||
pad: u8,
|
||||
}
|
||||
|
||||
/// The most common Base64 alphabet as defined in [RFC4648](https://www.rfc-editor.org/rfc/rfc4648)
|
||||
pub static B64_RFC4648_ALPHABET: B64Alphabet = B64Alphabet {
|
||||
items: [
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
|
||||
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
||||
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
|
||||
'2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
|
||||
b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O',
|
||||
b'P', b'Q', b'R', b'S', b'T', b'U', b'V', b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd',
|
||||
b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l', b'm', b'n', b'o', b'p', b'q', b'r', b's',
|
||||
b't', b'u', b'v', b'w', b'x', b'y', b'z', b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7',
|
||||
b'8', b'9', b'+', b'/',
|
||||
],
|
||||
pad: '=',
|
||||
pad: b'=',
|
||||
};
|
||||
|
||||
impl Default for B64Alphabet {
|
||||
|
@ -26,7 +33,7 @@ impl Default for B64Alphabet {
|
|||
}
|
||||
|
||||
impl B64Alphabet {
|
||||
pub(crate) fn get(&self, c: char) -> Option<usize> {
|
||||
pub(crate) fn get(&self, c: u8) -> Option<usize> {
|
||||
for (idx, x) in self.items.iter().enumerate() {
|
||||
if *x == c {
|
||||
return Some(idx);
|
||||
|
@ -35,7 +42,7 @@ impl B64Alphabet {
|
|||
None
|
||||
}
|
||||
|
||||
pub(crate) fn pad(&self) -> char {
|
||||
pub(crate) fn pad(&self) -> u8 {
|
||||
self.pad
|
||||
}
|
||||
}
|
||||
|
|
1
src/testdata/lorem.txt
vendored
1
src/testdata/lorem.txt
vendored
|
@ -1 +0,0 @@
|
|||
Lorem ipsum odor amet, consectetuer adipiscing elit. Mauris praesent senectus vivamus urna donec magna bibendum aenean. Nam nec sodales ex cursus inceptos vitae non habitant consectetur. Ex montes quis pellentesque tempor neque. Class ipsum fringilla mauris quam tempus. Nullam habitasse arcu ac nascetur class ad in. Senectus nostra arcu habitant arcu blandit potenti. Congue penatibus sollicitudin ullamcorper ridiculus semper. Ac porttitor bibendum nam; rhoncus pellentesque natoque pretium sit feugiat. Litora convallis maecenas elit netus blandit mus duis gravida sollicitudin.
|
11
src/testdata/lorem_b64.txt
vendored
11
src/testdata/lorem_b64.txt
vendored
|
@ -1,11 +0,0 @@
|
|||
TG9yZW0gaXBzdW0gb2RvciBhbWV0LCBjb25zZWN0ZXR1ZXIgYWRpcGlzY2luZyBlbGl0LiBNYXVy
|
||||
aXMgcHJhZXNlbnQgc2VuZWN0dXMgdml2YW11cyB1cm5hIGRvbmVjIG1hZ25hIGJpYmVuZHVtIGFl
|
||||
bmVhbi4gTmFtIG5lYyBzb2RhbGVzIGV4IGN1cnN1cyBpbmNlcHRvcyB2aXRhZSBub24gaGFiaXRh
|
||||
bnQgY29uc2VjdGV0dXIuIEV4IG1vbnRlcyBxdWlzIHBlbGxlbnRlc3F1ZSB0ZW1wb3IgbmVxdWUu
|
||||
IENsYXNzIGlwc3VtIGZyaW5naWxsYSBtYXVyaXMgcXVhbSB0ZW1wdXMuIE51bGxhbSBoYWJpdGFz
|
||||
c2UgYXJjdSBhYyBuYXNjZXR1ciBjbGFzcyBhZCBpbi4gU2VuZWN0dXMgbm9zdHJhIGFyY3UgaGFi
|
||||
aXRhbnQgYXJjdSBibGFuZGl0IHBvdGVudGkuIENvbmd1ZSBwZW5hdGlidXMgc29sbGljaXR1ZGlu
|
||||
IHVsbGFtY29ycGVyIHJpZGljdWx1cyBzZW1wZXIuIEFjIHBvcnR0aXRvciBiaWJlbmR1bSBuYW07
|
||||
IHJob25jdXMgcGVsbGVudGVzcXVlIG5hdG9xdWUgcHJldGl1bSBzaXQgZmV1Z2lhdC4gTGl0b3Jh
|
||||
IGNvbnZhbGxpcyBtYWVjZW5hcyBlbGl0IG5ldHVzIGJsYW5kaXQgbXVzIGR1aXMgZ3JhdmlkYSBz
|
||||
b2xsaWNpdHVkaW4uCg==
|
9
testdata/lorem.txt
vendored
Normal file
9
testdata/lorem.txt
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
Lorem ipsum odor amet, consectetuer adipiscing elit. Hendrerit eu semper lectus amet est proin. Tempus himenaeos at fusce lacus habitasse sociosqu torquent varius arcu. Odio netus fermentum nisl natoque per cubilia himenaeos urna. Elit venenatis eros risus vulputate duis interdum. Mauris dis ad pharetra dui aptent. Imperdiet orci auctor condimentum adipiscing arcu. Nullam tempor magna odio volutpat nisi. Condimentum scelerisque risus faucibus; duis sollicitudin nullam.
|
||||
|
||||
Condimentum ex fringilla tempus ultricies consectetur odio egestas venenatis vulputate. Sem sapien pellentesque ornare; viverra scelerisque consequat. Platea posuere mi senectus felis dolor dictumst mattis ultricies est. Malesuada elit adipiscing suspendisse est a. Justo luctus turpis tempus leo finibus rutrum nostra magnis aliquam. Felis posuere molestie praesent porta justo nisi. Etiam aptent conubia consectetur dis; penatibus elementum ut.
|
||||
|
||||
Morbi nostra netus ad nunc egestas neque nascetur fusce. Consequat ultrices scelerisque ut rhoncus volutpat, hendrerit convallis massa. Tortor himenaeos nullam malesuada suspendisse consectetur potenti volutpat. In suscipit sit maximus; lacinia eu nulla porta. Tempus commodo libero auctor cras bibendum sit. Metus aptent mauris nascetur venenatis diam metus. Inceptos mi ultrices class morbi donec. Orci pulvinar risus accumsan faucibus litora duis commodo commodo.
|
||||
|
||||
Aliquam etiam habitasse fames massa, hendrerit purus interdum nullam. Curabitur placerat tortor placerat nec adipiscing habitasse. Massa litora interdum pretium fusce nascetur primis faucibus magna. Dui curabitur molestie justo ullamcorper leo molestie mauris. Inceptos malesuada taciti litora libero maecenas neque nam laoreet. Tristique vivamus eget maecenas; porta fames curae mollis cras. Ipsum vulputate ullamcorper et nascetur nascetur vel orci.
|
||||
|
||||
Curae et odio; urna eros pulvinar malesuada eget dignissim. Cursus fermentum lectus phasellus tempor posuere vulputate quam. Mauris commodo commodo mauris inceptos metus varius urna sagittis. Ligula duis erat ipsum pretium eu facilisis. Duis lobortis proin facilisi ad suscipit vestibulum hac tortor interdum. Ultrices tincidunt maximus aptent phasellus in ullamcorper nisl varius dis. Venenatis enim potenti potenti sodales massa id elementum.
|
41
testdata/lorem_b64.txt
vendored
Normal file
41
testdata/lorem_b64.txt
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
TG9yZW0gaXBzdW0gb2RvciBhbWV0LCBjb25zZWN0ZXR1ZXIgYWRpcGlzY2luZyBlbGl0LiBIZW5k
|
||||
cmVyaXQgZXUgc2VtcGVyIGxlY3R1cyBhbWV0IGVzdCBwcm9pbi4gVGVtcHVzIGhpbWVuYWVvcyBh
|
||||
dCBmdXNjZSBsYWN1cyBoYWJpdGFzc2Ugc29jaW9zcXUgdG9ycXVlbnQgdmFyaXVzIGFyY3UuIE9k
|
||||
aW8gbmV0dXMgZmVybWVudHVtIG5pc2wgbmF0b3F1ZSBwZXIgY3ViaWxpYSBoaW1lbmFlb3MgdXJu
|
||||
YS4gRWxpdCB2ZW5lbmF0aXMgZXJvcyByaXN1cyB2dWxwdXRhdGUgZHVpcyBpbnRlcmR1bS4gTWF1
|
||||
cmlzIGRpcyBhZCBwaGFyZXRyYSBkdWkgYXB0ZW50LiBJbXBlcmRpZXQgb3JjaSBhdWN0b3IgY29u
|
||||
ZGltZW50dW0gYWRpcGlzY2luZyBhcmN1LiBOdWxsYW0gdGVtcG9yIG1hZ25hIG9kaW8gdm9sdXRw
|
||||
YXQgbmlzaS4gQ29uZGltZW50dW0gc2NlbGVyaXNxdWUgcmlzdXMgZmF1Y2lidXM7IGR1aXMgc29s
|
||||
bGljaXR1ZGluIG51bGxhbS4KCkNvbmRpbWVudHVtIGV4IGZyaW5naWxsYSB0ZW1wdXMgdWx0cmlj
|
||||
aWVzIGNvbnNlY3RldHVyIG9kaW8gZWdlc3RhcyB2ZW5lbmF0aXMgdnVscHV0YXRlLiBTZW0gc2Fw
|
||||
aWVuIHBlbGxlbnRlc3F1ZSBvcm5hcmU7IHZpdmVycmEgc2NlbGVyaXNxdWUgY29uc2VxdWF0LiBQ
|
||||
bGF0ZWEgcG9zdWVyZSBtaSBzZW5lY3R1cyBmZWxpcyBkb2xvciBkaWN0dW1zdCBtYXR0aXMgdWx0
|
||||
cmljaWVzIGVzdC4gTWFsZXN1YWRhIGVsaXQgYWRpcGlzY2luZyBzdXNwZW5kaXNzZSBlc3QgYS4g
|
||||
SnVzdG8gbHVjdHVzIHR1cnBpcyB0ZW1wdXMgbGVvIGZpbmlidXMgcnV0cnVtIG5vc3RyYSBtYWdu
|
||||
aXMgYWxpcXVhbS4gRmVsaXMgcG9zdWVyZSBtb2xlc3RpZSBwcmFlc2VudCBwb3J0YSBqdXN0byBu
|
||||
aXNpLiBFdGlhbSBhcHRlbnQgY29udWJpYSBjb25zZWN0ZXR1ciBkaXM7IHBlbmF0aWJ1cyBlbGVt
|
||||
ZW50dW0gdXQuCgpNb3JiaSBub3N0cmEgbmV0dXMgYWQgbnVuYyBlZ2VzdGFzIG5lcXVlIG5hc2Nl
|
||||
dHVyIGZ1c2NlLiBDb25zZXF1YXQgdWx0cmljZXMgc2NlbGVyaXNxdWUgdXQgcmhvbmN1cyB2b2x1
|
||||
dHBhdCwgaGVuZHJlcml0IGNvbnZhbGxpcyBtYXNzYS4gVG9ydG9yIGhpbWVuYWVvcyBudWxsYW0g
|
||||
bWFsZXN1YWRhIHN1c3BlbmRpc3NlIGNvbnNlY3RldHVyIHBvdGVudGkgdm9sdXRwYXQuIEluIHN1
|
||||
c2NpcGl0IHNpdCBtYXhpbXVzOyBsYWNpbmlhIGV1IG51bGxhIHBvcnRhLiBUZW1wdXMgY29tbW9k
|
||||
byBsaWJlcm8gYXVjdG9yIGNyYXMgYmliZW5kdW0gc2l0LiBNZXR1cyBhcHRlbnQgbWF1cmlzIG5h
|
||||
c2NldHVyIHZlbmVuYXRpcyBkaWFtIG1ldHVzLiBJbmNlcHRvcyBtaSB1bHRyaWNlcyBjbGFzcyBt
|
||||
b3JiaSBkb25lYy4gT3JjaSBwdWx2aW5hciByaXN1cyBhY2N1bXNhbiBmYXVjaWJ1cyBsaXRvcmEg
|
||||
ZHVpcyBjb21tb2RvIGNvbW1vZG8uCgpBbGlxdWFtIGV0aWFtIGhhYml0YXNzZSBmYW1lcyBtYXNz
|
||||
YSwgaGVuZHJlcml0IHB1cnVzIGludGVyZHVtIG51bGxhbS4gQ3VyYWJpdHVyIHBsYWNlcmF0IHRv
|
||||
cnRvciBwbGFjZXJhdCBuZWMgYWRpcGlzY2luZyBoYWJpdGFzc2UuIE1hc3NhIGxpdG9yYSBpbnRl
|
||||
cmR1bSBwcmV0aXVtIGZ1c2NlIG5hc2NldHVyIHByaW1pcyBmYXVjaWJ1cyBtYWduYS4gRHVpIGN1
|
||||
cmFiaXR1ciBtb2xlc3RpZSBqdXN0byB1bGxhbWNvcnBlciBsZW8gbW9sZXN0aWUgbWF1cmlzLiBJ
|
||||
bmNlcHRvcyBtYWxlc3VhZGEgdGFjaXRpIGxpdG9yYSBsaWJlcm8gbWFlY2VuYXMgbmVxdWUgbmFt
|
||||
IGxhb3JlZXQuIFRyaXN0aXF1ZSB2aXZhbXVzIGVnZXQgbWFlY2VuYXM7IHBvcnRhIGZhbWVzIGN1
|
||||
cmFlIG1vbGxpcyBjcmFzLiBJcHN1bSB2dWxwdXRhdGUgdWxsYW1jb3JwZXIgZXQgbmFzY2V0dXIg
|
||||
bmFzY2V0dXIgdmVsIG9yY2kuCgpDdXJhZSBldCBvZGlvOyB1cm5hIGVyb3MgcHVsdmluYXIgbWFs
|
||||
ZXN1YWRhIGVnZXQgZGlnbmlzc2ltLiBDdXJzdXMgZmVybWVudHVtIGxlY3R1cyBwaGFzZWxsdXMg
|
||||
dGVtcG9yIHBvc3VlcmUgdnVscHV0YXRlIHF1YW0uIE1hdXJpcyBjb21tb2RvIGNvbW1vZG8gbWF1
|
||||
cmlzIGluY2VwdG9zIG1ldHVzIHZhcml1cyB1cm5hIHNhZ2l0dGlzLiBMaWd1bGEgZHVpcyBlcmF0
|
||||
IGlwc3VtIHByZXRpdW0gZXUgZmFjaWxpc2lzLiBEdWlzIGxvYm9ydGlzIHByb2luIGZhY2lsaXNp
|
||||
IGFkIHN1c2NpcGl0IHZlc3RpYnVsdW0gaGFjIHRvcnRvciBpbnRlcmR1bS4gVWx0cmljZXMgdGlu
|
||||
Y2lkdW50IG1heGltdXMgYXB0ZW50IHBoYXNlbGx1cyBpbiB1bGxhbWNvcnBlciBuaXNsIHZhcml1
|
||||
cyBkaXMuIFZlbmVuYXRpcyBlbmltIHBvdGVudGkgcG90ZW50aSBzb2RhbGVzIG1hc3NhIGlkIGVs
|
||||
ZW1lbnR1bS4K
|
Loading…
Add table
Reference in a new issue