| @@ -57,6 +57,7 @@ carla-discovery-posix32 | |||||
| carla-discovery-posix64 | carla-discovery-posix64 | ||||
| source/tests/ANSI | source/tests/ANSI | ||||
| source/tests/Base64 | |||||
| source/tests/CarlaString | source/tests/CarlaString | ||||
| source/tests/Print | source/tests/Print | ||||
| source/tests/RtList | source/tests/RtList | ||||
| @@ -15,7 +15,9 @@ | |||||
| * For a full copy of the GNU General Public License see the GPL.txt file | * For a full copy of the GNU General Public License see the GPL.txt file | ||||
| */ | */ | ||||
| #if 1 | |||||
| #include "standalone/carla_standalone.cpp" | |||||
| #if 0 | |||||
| #include "CarlaDefines.hpp" | #include "CarlaDefines.hpp" | ||||
| #include "CarlaMIDI.h" | #include "CarlaMIDI.h" | ||||
| #include "ladspa_rdf.hpp" | #include "ladspa_rdf.hpp" | ||||
| @@ -30,6 +32,7 @@ | |||||
| #include "CarlaUtils.hpp" | #include "CarlaUtils.hpp" | ||||
| #include "CarlaBackendUtils.hpp" | #include "CarlaBackendUtils.hpp" | ||||
| #include "CarlaBase64Utils.hpp" | |||||
| #include "CarlaJuceUtils.hpp" | #include "CarlaJuceUtils.hpp" | ||||
| #include "CarlaLibUtils.hpp" | #include "CarlaLibUtils.hpp" | ||||
| #include "CarlaOscUtils.hpp" | #include "CarlaOscUtils.hpp" | ||||
| @@ -0,0 +1,106 @@ | |||||
| /* | |||||
| * Carla Tests | |||||
| * Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the GPL.txt file | |||||
| */ | |||||
| #include "CarlaBase64Utils.hpp" | |||||
| #include "CarlaString.hpp" | |||||
| int main() | |||||
| { | |||||
| CARLA_ASSERT(std::strlen(kBase64) == 64); | |||||
| struct Blob { | |||||
| char s[4]; | |||||
| int i; | |||||
| double d; | |||||
| char padding[100]; | |||||
| void* ptr; | |||||
| Blob() | |||||
| : s{'1', 's', 't', 0}, | |||||
| i(228), | |||||
| d(3.33333333333), | |||||
| ptr((void*)0x500) {} | |||||
| } blob; | |||||
| // binary -> base64 | |||||
| void* const test0 = &blob; | |||||
| size_t test0Len = sizeof(Blob); | |||||
| char buf0[carla_base64_encoded_len(test0Len) + 1]; | |||||
| carla_base64_encode((const uint8_t*)test0, test0Len, buf0); | |||||
| printf("BINARY '%s'\n", buf0); | |||||
| char buf0dec[carla_base64_decoded_max_len(buf0)]; | |||||
| carla_base64_decode(buf0, (uint8_t*)buf0dec); | |||||
| Blob blobTester; | |||||
| blobTester.s[0] = 0; | |||||
| blobTester.i = 0; | |||||
| blobTester.d = 9999.99999999999999; | |||||
| std::memcpy(&blobTester, buf0dec, sizeof(Blob)); | |||||
| CARLA_ASSERT(std::strcmp(blobTester.s, "1st") == 0); | |||||
| CARLA_ASSERT(blobTester.i == 228); | |||||
| CARLA_ASSERT(blobTester.d == 3.33333333333); | |||||
| // string -> base64 | |||||
| const char* const test1 = "Hello World!"; | |||||
| size_t test1Len = std::strlen(test1); | |||||
| char buf1[carla_base64_encoded_len(test1Len) + 1]; | |||||
| carla_base64_encode((const uint8_t*)test1, test1Len, buf1); | |||||
| printf("'%s' => '%s'\n", test1, buf1); | |||||
| // base64 -> string | |||||
| const char* const test2 = "SGVsbG8gV29ybGQh"; | |||||
| char buf2[carla_base64_decoded_max_len(test2)]; | |||||
| carla_base64_decode(test2, (uint8_t*)buf2); | |||||
| printf("'%s' => '%s'\n", test2, buf2); | |||||
| printf("'%s' == '%s'\n", buf1, test2); | |||||
| printf("'%s' == '%s'\n", buf2, test1); | |||||
| CARLA_ASSERT(std::strcmp(buf1, test2) == 0); | |||||
| CARLA_ASSERT(std::strcmp(buf2, test1) == 0); | |||||
| // ----------------------------------------------------------------- | |||||
| blob.s[0] = 'X'; | |||||
| blob.i = 92320; | |||||
| blob.d = 9999887.99999999999999; | |||||
| CarlaString string; | |||||
| string.importBinaryAsBase64<Blob>(&blob); | |||||
| Blob* blob3 = string.exportAsBase64Binary<Blob>(); | |||||
| CARLA_ASSERT(std::strcmp(blob3->s, blob.s) == 0); | |||||
| CARLA_ASSERT(blob3->i == blob.i); | |||||
| CARLA_ASSERT(blob3->d == blob.d); | |||||
| CARLA_ASSERT(blob3->ptr == blob.ptr); | |||||
| delete blob3; | |||||
| // ----------------------------------------------------------------- | |||||
| return 0; | |||||
| } | |||||
| @@ -14,16 +14,19 @@ BUILD_CXX_FLAGS += -I../backend -I../includes -I../utils -Wall -Wextra | |||||
| ANSI_CXX_FLAGS = -ansi -pedantic -pedantic-errors -Wunused-parameter -Wuninitialized -Wno-vla | ANSI_CXX_FLAGS = -ansi -pedantic -pedantic-errors -Wunused-parameter -Wuninitialized -Wno-vla | ||||
| ANSI_CXX_FLAGS += -Wcast-qual -Wconversion -Wsign-conversion -Wlogical-op -Waggregate-return | ANSI_CXX_FLAGS += -Wcast-qual -Wconversion -Wsign-conversion -Wlogical-op -Waggregate-return | ||||
| ANSI_CXX_FLAGS += -std=c++11 -Wzero-as-null-pointer-constant | ANSI_CXX_FLAGS += -std=c++11 -Wzero-as-null-pointer-constant | ||||
| ANSI_CXX_FLAGS += -DVESTIGE_HEADER | |||||
| ANSI_CXX_FLAGS += -DVESTIGE_HEADER -shared -fPIC | |||||
| TARGETS = ANSI CarlaString RtList Thread Print | |||||
| TARGETS = ANSI_ Base64 CarlaString RtList Thread Print | |||||
| all: $(TARGETS) RUN | all: $(TARGETS) RUN | ||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| ANSI: ANSI.cpp | |||||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(ANSI_CXX_FLAGS) $(LINK_FLAGS) -o $@ | |||||
| ANSI_: ANSI.cpp | |||||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(ANSI_CXX_FLAGS) $(LINK_FLAGS) -o ANSI # $@ | |||||
| Base64: Base64.cpp | |||||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | |||||
| CarlaString: CarlaString.cpp | CarlaString: CarlaString.cpp | ||||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | ||||
| @@ -44,6 +47,7 @@ GL_: GL.cpp | |||||
| RUN: $(TARGETS) | RUN: $(TARGETS) | ||||
| # ./CarlaString && ./RtList && ./Thread | # ./CarlaString && ./RtList && ./Thread | ||||
| # ./Base64 | |||||
| # ./GL | # ./GL | ||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| @@ -0,0 +1,185 @@ | |||||
| /* | |||||
| * Carla base64 utils imported from qemu source code | |||||
| * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk> | |||||
| * Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the GPL.txt file | |||||
| */ | |||||
| #ifndef __CARLA_BASE64_UTILS_HPP__ | |||||
| #define __CARLA_BASE64_UTILS_HPP__ | |||||
| #include "CarlaUtils.hpp" | |||||
| #include <cctype> | |||||
| #include <cstdint> | |||||
| static const char kBase64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |||||
| /** | |||||
| * Calculate length of base64-encoded data | |||||
| * | |||||
| * @v rawLen Raw data length | |||||
| * @ret encodedLen Encoded string length (excluding NUL) | |||||
| */ | |||||
| static inline | |||||
| size_t carla_base64_encoded_len(const size_t rawLen) | |||||
| { | |||||
| return (((rawLen + 3 - 1) / 3) * 4); | |||||
| } | |||||
| /** | |||||
| * Calculate maximum length of base64-decoded string | |||||
| * | |||||
| * @v encoded Encoded string | |||||
| * @v maxRawLen Maximum length of raw data | |||||
| * | |||||
| * Note that the exact length of the raw data cannot be known until | |||||
| * the string is decoded. | |||||
| */ | |||||
| static inline | |||||
| size_t carla_base64_decoded_max_len(const char* const encoded) | |||||
| { | |||||
| return (((std::strlen(encoded) + 4 - 1) / 4) * 3); | |||||
| } | |||||
| /** | |||||
| * Base64-encode data | |||||
| * | |||||
| * @v raw Raw data | |||||
| * @v len Length of raw data | |||||
| * @v encoded Buffer for encoded string | |||||
| * | |||||
| * The buffer must be the correct length for the encoded string. | |||||
| * Use something like | |||||
| * | |||||
| * char buf[carla_base64_encoded_len(len) + 1]; | |||||
| * | |||||
| * (the +1 is for the terminating NUL) to provide a buffer of the correct size. | |||||
| */ | |||||
| static inline | |||||
| void carla_base64_encode(const uint8_t* const raw, const size_t len, char* const encoded) | |||||
| { | |||||
| const uint8_t* rawBytes = (const uint8_t*)raw; | |||||
| uint8_t* encodedBytes = (uint8_t*)encoded; | |||||
| size_t rawBitLen = 8*len; | |||||
| unsigned int bit; | |||||
| unsigned int tmp; | |||||
| for (bit = 0; bit < rawBitLen; bit += 6) | |||||
| { | |||||
| tmp = (rawBytes[bit/8] << (bit % 8)) | (rawBytes[bit/8 + 1] >> (8 - (bit % 8))); | |||||
| tmp = (tmp >> 2) & 0x3f; | |||||
| *(encodedBytes++) = kBase64[tmp]; | |||||
| } | |||||
| for (; (bit % 8) != 0; bit += 6) | |||||
| *(encodedBytes++) = '='; | |||||
| *(encodedBytes++) = '\0'; | |||||
| carla_debug("Base64-encoded to \"%s\":\n", encoded); | |||||
| CARLA_ASSERT(std::strlen(encoded) == carla_base64_encoded_len(len)); | |||||
| } | |||||
| /** | |||||
| * Base64-decode string | |||||
| * | |||||
| * @v encoded Encoded string | |||||
| * @v raw Raw data | |||||
| * @ret len Length of raw data, or 0 | |||||
| * | |||||
| * The buffer must be large enough to contain the decoded data. | |||||
| * Use something like | |||||
| * | |||||
| * char buf[carla_base64_decoded_max_len(encoded)]; | |||||
| * | |||||
| * to provide a buffer of the correct size. | |||||
| */ | |||||
| static inline | |||||
| unsigned int carla_base64_decode(const char* const encoded, uint8_t* const raw) | |||||
| { | |||||
| char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |||||
| const uint8_t* encodedBytes = (const uint8_t*)encoded; | |||||
| uint8_t* rawBytes = (uint8_t*)raw; | |||||
| uint8_t encodedByte; | |||||
| unsigned int bit = 0; | |||||
| unsigned int padCount = 0; | |||||
| /* Zero the raw data */ | |||||
| std::memset(raw, 0, carla_base64_decoded_max_len(encoded)); | |||||
| /* Decode string */ | |||||
| while ((encodedByte = *(encodedBytes++)) > 0) | |||||
| { | |||||
| /* Ignore whitespace characters */ | |||||
| if (std::isspace(encodedByte)) | |||||
| continue; | |||||
| /* Process pad characters */ | |||||
| if (encodedByte == '=') | |||||
| { | |||||
| if (padCount >= 2) | |||||
| { | |||||
| carla_debug("Base64-encoded string \"%s\" has too many pad characters", encoded); | |||||
| return 0; | |||||
| } | |||||
| padCount++; | |||||
| bit -= 2; /* unused_bits = ( 2 * padCount ) */ | |||||
| continue; | |||||
| } | |||||
| if (padCount) | |||||
| { | |||||
| carla_debug("Base64-encoded string \"%s\" has invalid pad sequence", encoded); | |||||
| return 0; | |||||
| } | |||||
| /* Process normal characters */ | |||||
| char* match = std::strchr(base64, encodedByte); | |||||
| if (match == nullptr) | |||||
| { | |||||
| carla_debug("Base64-encoded string \"%s\" contains invalid character '%c'", encoded, encodedByte); | |||||
| return 0; | |||||
| } | |||||
| int decoded = match - base64; | |||||
| /* Add to raw data */ | |||||
| decoded <<= 2; | |||||
| rawBytes[bit / 8] |= (decoded >> (bit % 8)); | |||||
| rawBytes[bit / 8 + 1] |= (decoded << (8 - (bit % 8))); | |||||
| bit += 6; | |||||
| } | |||||
| /* Check that we decoded a whole number of bytes */ | |||||
| if ((bit % 8) != 0) | |||||
| { | |||||
| carla_debug("Base64-encoded string \"%s\" has invalid bit length %d", encoded, bit); | |||||
| return 0; | |||||
| } | |||||
| unsigned int len = bit/8; | |||||
| carla_debug("Base64-decoded \"%s\" to: \"%s\"\n", encoded, raw); | |||||
| CARLA_ASSERT(len <= carla_base64_decoded_max_len(encoded)); | |||||
| /* Return length in bytes */ | |||||
| return len; | |||||
| } | |||||
| #endif // __CARLA_BASE64_UTILS_HPP__ | |||||
| @@ -18,6 +18,7 @@ | |||||
| #ifndef __CARLA_STRING_HPP__ | #ifndef __CARLA_STRING_HPP__ | ||||
| #define __CARLA_STRING_HPP__ | #define __CARLA_STRING_HPP__ | ||||
| #include "CarlaBase64Utils.hpp" | |||||
| #include "CarlaJuceUtils.hpp" | #include "CarlaJuceUtils.hpp" | ||||
| // ------------------------------------------------- | // ------------------------------------------------- | ||||
| @@ -250,6 +251,71 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| void toBase64() | |||||
| { | |||||
| importBinaryAsBase64((const uint8_t*)buffer, bufferLen); | |||||
| } | |||||
| void fromBase64() | |||||
| { | |||||
| uint8_t buffer2[carla_base64_decoded_max_len(buffer)]; | |||||
| if (unsigned int len = carla_base64_decode(buffer, buffer2)) | |||||
| _dup((char*)buffer2, len); | |||||
| else | |||||
| clear(); | |||||
| } | |||||
| void importBinaryAsBase64(const uint8_t* const raw, const size_t rawLen) | |||||
| { | |||||
| const size_t rawBufferSize = carla_base64_encoded_len(rawLen) + 1; | |||||
| char rawBuffer[rawBufferSize]; | |||||
| carla_base64_encode(raw, rawLen, rawBuffer); | |||||
| _dup(rawBuffer, rawBufferSize-1); | |||||
| } | |||||
| template<typename T> | |||||
| void importBinaryAsBase64(const T* const t) | |||||
| { | |||||
| const size_t tSize = sizeof(T); | |||||
| importBinaryAsBase64((const uint8_t*)t, tSize); | |||||
| } | |||||
| size_t exportAsBase64Binary(uint8_t** const rawPtr) | |||||
| { | |||||
| uint8_t binaryBuffer[carla_base64_decoded_max_len(buffer)]; | |||||
| if (unsigned int len = carla_base64_decode(buffer, binaryBuffer)) | |||||
| { | |||||
| uint8_t* const binaryBufferHeap = new uint8_t[len]; | |||||
| std::memcpy(binaryBufferHeap, binaryBuffer, len); | |||||
| *rawPtr = binaryBufferHeap; | |||||
| return len; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| template<typename T> | |||||
| T* exportAsBase64Binary() | |||||
| { | |||||
| uint8_t binaryBuffer[carla_base64_decoded_max_len(buffer)]; | |||||
| if (unsigned int len = carla_base64_decode(buffer, binaryBuffer)) | |||||
| { | |||||
| CARLA_ASSERT_INT2(len == sizeof(T), len, sizeof(T)); | |||||
| T* const t = new T(); | |||||
| std::memcpy(t, binaryBuffer, len); | |||||
| return t; | |||||
| } | |||||
| return nullptr; | |||||
| } | |||||
| // --------------------------------------------- | // --------------------------------------------- | ||||
| // public operators | // public operators | ||||