Browse Source

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

tags/v1.1.6
Andrew Belt 5 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 #pragma once
#include <common.hpp> #include <common.hpp>
#include <vector>




namespace rack { 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); std::string ellipsizePrefix(const std::string& s, size_t len);
bool startsWith(const std::string& str, const std::string& prefix); bool startsWith(const std::string& str, const std::string& prefix);
bool endsWith(const std::string& str, const std::string& suffix); bool endsWith(const std::string& str, const std::string& suffix);

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

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

/** Converts a byte array to a Base64-encoded string. /** Converts a byte array to a Base64-encoded string.
https://en.wikipedia.org/wiki/Base64 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. /** Converts a Base64-encoded string to a byte array.
`outLen` is set to the length of the byte array. `outLen` is set to the length of the byte array.
If non-NULL, caller must delete[] the result. 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 { struct CaseInsensitiveCompare {


+ 42
- 10
src/string.cpp View File

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




namespace rack { 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+/"; 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; size_t strLen = numBlocks * 4;
std::string str; std::string str;
str.reserve(strLen); str.reserve(strLen);
@@ -166,7 +167,7 @@ std::string toBase64(const uint8_t* data, size_t len) {
// Encode block // Encode block
uint32_t block = 0; uint32_t block = 0;
int i; 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)); 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(); size_t strLen = str.size();
if (strLen % 4 != 0) if (strLen % 4 != 0)
return NULL;
throw std::runtime_error("String length not a factor of 4");


size_t numBlocks = strLen / 4; size_t numBlocks = strLen / 4;
size_t len = numBlocks * 3; size_t len = numBlocks * 3;
@@ -193,10 +199,8 @@ uint8_t* fromBase64(const std::string& str, size_t* outLen) {
if (str[strLen - 2] == '=') if (str[strLen - 2] == '=')
len--; 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++) { for (size_t b = 0; b < numBlocks; b++) {
// Encode block // Encode block
@@ -226,8 +230,8 @@ uint8_t* fromBase64(const std::string& str, size_t* outLen) {
break; break;
} }
else { 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)); 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 string
} // namespace rack } // namespace rack

Loading…
Cancel
Save