Browse Source

string namespace: Change base64 functions. Add compress/uncompress.

tags/v1.1.6
Andrew Belt 2 years ago
parent
commit
c53fbebd97
2 changed files with 59 additions and 12 deletions
  1. +17
    -2
      include/string.hpp
  2. +42
    -10
      src/string.cpp

+ 17
- 2
include/string.hpp View File

@@ -1,5 +1,6 @@
#pragma once
#include <common.hpp>
#include <vector>


namespace rack {
@@ -28,6 +29,7 @@ std::string ellipsize(const std::string& s, size_t len);
std::string ellipsizePrefix(const std::string& s, size_t len);
bool startsWith(const std::string& str, const std::string& prefix);
bool endsWith(const std::string& str, const std::string& suffix);

/** Extracts the directory of the path.
Example: directory("dir/file.txt") // "dir"
Calls POSIX dirname().
@@ -52,20 +54,33 @@ std::string filenameExtension(const std::string& filename);
Returns "" if the symbol is not found.
*/
std::string absolutePath(const std::string& path);

/** Scores how well a query matches a string.
A score of 0 means no match.
The score is arbitrary and is only meaningful for sorting.
*/
float fuzzyScore(const std::string& s, const std::string& query);

/** Converts a byte array to a Base64-encoded string.
https://en.wikipedia.org/wiki/Base64
*/
std::string toBase64(const uint8_t* data, size_t len);
std::string toBase64(const uint8_t* data, size_t dataLen);
std::string toBase64(const std::vector<uint8_t>& data);
/** Converts a Base64-encoded string to a byte array.
`outLen` is set to the length of the byte array.
If non-NULL, caller must delete[] the result.
*/
uint8_t* fromBase64(const std::string& str, size_t* outLen);
std::vector<uint8_t> fromBase64(const std::string& str);

/** Compress bytes with zlib.
*/
std::vector<uint8_t> compress(const uint8_t* data, size_t dataLen);
std::vector<uint8_t> compress(const std::vector<uint8_t>& data);
/** Uncompress bytes with zlib.
Unfortunately the output buffer cannot be computed from the compressed data, so you may need to hard-code the maximum expected size.
*/
void uncompress(const uint8_t* compressed, size_t compressedLen, uint8_t* data, size_t* dataLen);
void uncompress(const std::vector<uint8_t>& compressed, uint8_t* data, size_t* dataLen);


struct CaseInsensitiveCompare {


+ 42
- 10
src/string.cpp View File

@@ -4,6 +4,7 @@
#include <cctype> // for tolower and toupper
#include <algorithm> // for transform
#include <libgen.h> // for dirname and basename
#include <zlib.h>


namespace rack {
@@ -154,10 +155,10 @@ float fuzzyScore(const std::string& s, const std::string& query) {
}


std::string toBase64(const uint8_t* data, size_t len) {
std::string toBase64(const uint8_t* data, size_t dataLen) {
static const char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

size_t numBlocks = size_t((len + 2) / 3);
size_t numBlocks = size_t((dataLen + 2) / 3);
size_t strLen = numBlocks * 4;
std::string str;
str.reserve(strLen);
@@ -166,7 +167,7 @@ std::string toBase64(const uint8_t* data, size_t len) {
// Encode block
uint32_t block = 0;
int i;
for (i = 0; i < 3 && 3 * b + i < len; i++) {
for (i = 0; i < 3 && 3 * b + i < dataLen; i++) {
block |= uint32_t(data[3 * b + i]) << (8 * (2 - i));
}

@@ -180,10 +181,15 @@ std::string toBase64(const uint8_t* data, size_t len) {
}


uint8_t* fromBase64(const std::string& str, size_t* outLen) {
std::string toBase64(const std::vector<uint8_t>& data) {
return toBase64(data.data(), data.size());
}


std::vector<uint8_t> fromBase64(const std::string& str) {
size_t strLen = str.size();
if (strLen % 4 != 0)
return NULL;
throw std::runtime_error("String length not a factor of 4");

size_t numBlocks = strLen / 4;
size_t len = numBlocks * 3;
@@ -193,10 +199,8 @@ uint8_t* fromBase64(const std::string& str, size_t* outLen) {
if (str[strLen - 2] == '=')
len--;
}
if (outLen)
*outLen = len;

uint8_t* data = new uint8_t[len];
std::vector<uint8_t> data(len);

for (size_t b = 0; b < numBlocks; b++) {
// Encode block
@@ -226,8 +230,8 @@ uint8_t* fromBase64(const std::string& str, size_t* outLen) {
break;
}
else {
// Ignore invalid characters, such as whitespace.
continue;
// Since we assumed the string was a factor of 4 bytes, fail if an invalid character, such as whitespace, was found.
throw std::runtime_error("String contains non-base64 character");
}

block |= uint32_t(d) << (6 * (3 - i));
@@ -243,5 +247,33 @@ uint8_t* fromBase64(const std::string& str, size_t* outLen) {
}


std::vector<uint8_t> compress(const uint8_t* data, size_t dataLen) {
std::vector<uint8_t> compressed;
size_t outCap = ::compressBound(dataLen);
compressed.resize(outCap);
int err = ::compress2(compressed.data(), &outCap, data, dataLen, Z_BEST_COMPRESSION);
if (err)
throw std::runtime_error("Zlib error");
compressed.resize(outCap);
return compressed;
}


std::vector<uint8_t> compress(const std::vector<uint8_t>& data) {
return compress(data.data(), data.size());
}


void uncompress(const uint8_t* compressed, size_t compressedLen, uint8_t* data, size_t* dataLen) {
int err = ::uncompress(data, dataLen, compressed, compressedLen);
(void) err;
}


void uncompress(const std::vector<uint8_t>& compressed, uint8_t* data, size_t* dataLen) {
uncompress(compressed.data(), compressed.size(), data, dataLen);
}


} // namespace string
} // namespace rack

Loading…
Cancel
Save