Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eighty-eels-lose.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-native-encoding': 'patch'
---

Use std::vector instead of raw pointers, use base64 implementation from https://github.com/tobiaslocker/base64
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ function YEET(inputBuffer: Uint8Array) {
- ✅ You can use this library with [Development Builds](https://docs.expo.dev/development/introduction/).
- ❌ This library can't be used in the "Expo Go" app because it [requires custom native code](https://docs.expo.dev/workflow/customizing/).

## Acknowledgements

Base64 is implemented using https://github.com/tobiaslocker/base64 under MIT license

## Contributing

See the [contributing guide](./CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
Expand Down
12 changes: 6 additions & 6 deletions cpp/ReactNativeEncodingArrayBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

namespace facebook::react {

ReactNativeEncodingArrayBuffer::ReactNativeEncodingArrayBuffer(uint8_t *data, size_t size)
: jsi::MutableBuffer(), data_(data), size_(size) {}
ReactNativeEncodingArrayBuffer::ReactNativeEncodingArrayBuffer(std::vector<uint8_t> data, size_t size)
: jsi::MutableBuffer(), data_(std::move(data)), size_(size) {}

std::shared_ptr<ReactNativeEncodingArrayBuffer> ReactNativeEncodingArrayBuffer::fromString(const std::string &str) {
auto buffer = new uint8_t[str.size()];
std::copy(str.data(), str.data() + str.size(), buffer);
return std::make_shared<ReactNativeEncodingArrayBuffer>(buffer, str.size());
std::vector buffer(str.begin(), str.end());
auto size = buffer.size();
return std::make_shared<ReactNativeEncodingArrayBuffer>(std::move(buffer), size);
}

uint8_t *ReactNativeEncodingArrayBuffer::data() {
return data_;
return data_.data();
}

size_t ReactNativeEncodingArrayBuffer::size() const {
Expand Down
6 changes: 4 additions & 2 deletions cpp/ReactNativeEncodingArrayBuffer.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
#pragma once

#include <vector>

#include <jsi/jsi.h>

namespace facebook::react {

class ReactNativeEncodingArrayBuffer : public jsi::MutableBuffer {
public:
explicit ReactNativeEncodingArrayBuffer(uint8_t *data, size_t size);
explicit ReactNativeEncodingArrayBuffer(std::vector<uint8_t> data, size_t size);

static std::shared_ptr<ReactNativeEncodingArrayBuffer> fromString(const std::string &str);

[[nodiscard]] size_t size() const override;
uint8_t *data() override;

private:
uint8_t *data_;
std::vector<uint8_t> data_;
size_t size_;
};

Expand Down
1 change: 1 addition & 0 deletions encoding-core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(CMAKE_VERBOSE_MAKEFILE on)
add_library(ReactNativeEncodingCore SHARED
${CMAKE_CURRENT_SOURCE_DIR}/ReactNativeEncodingBase64.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ReactNativeEncodingBase64.h
${CMAKE_CURRENT_SOURCE_DIR}/base64.hpp
${CMAKE_CURRENT_SOURCE_DIR}/ReactNativeEncodingHex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ReactNativeEncodingHex.h)

Expand Down
92 changes: 4 additions & 88 deletions encoding-core/ReactNativeEncodingBase64.cpp
Original file line number Diff line number Diff line change
@@ -1,95 +1,11 @@
#include "ReactNativeEncodingBase64.h"

static const uint8_t base64DecodingTable[128] = {
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, /* 0 - 15 */
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, /* 16 - 31 */
99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 62, 99, 99, 99, 63, /* 32 - 47 */
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 99, 99, 99, 64, 99, 99, /* 48 - 63 */
99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 64 - 79 */
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 99, 99, 99, 99, 99, /* 80 - 95 */
99, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 96 - 111 */
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 99, 99, 99, 99, 99 /* 112 - 127 */
};
std::string decodeFromBase64BufferToUtf8String(const uint8_t *data, const size_t size) {
bool pad = data[size - 1] == (uint8_t)'=';
size_t offset;

if (pad) {
offset = ((size / 4) - 1) * 4;
} else {
offset = (size / 4) * 4;
}

bool isPad1 = data[offset + 2] != (uint8_t)'=';

std::string decodedStr;
decodedStr.reserve(offset + (isPad1 ? 2 : 1));

for (auto p = (uint8_t *)data; p != data + offset; p += 4) {
uint8_t b1 = base64DecodingTable[p[0]];
uint8_t b2 = base64DecodingTable[p[1]];
uint8_t b3 = base64DecodingTable[p[2]];
uint8_t b4 = base64DecodingTable[p[3]];

uint32_t quartet = unsigned(b1) << 18 | unsigned(b2) << 12 | unsigned(b3) << 6 | b4;

decodedStr.push_back((char)(quartet >> 16));
decodedStr.push_back((char)((quartet >> 8) & 0xFF));
decodedStr.push_back((char)(quartet & 0xFF));
}

if (pad) {
uint8_t b1 = base64DecodingTable[data[offset]];
uint8_t b2 = base64DecodingTable[data[offset + 1]];

uint32_t quartet = unsigned(b1) << 18 | unsigned(b2) << 12;

decodedStr.push_back((char)(quartet >> 16));

if (isPad1) {
uint8_t b3 = base64DecodingTable[data[offset + 2]];

decodedStr.push_back((char)(((quartet | (unsigned(b3) << 6)) >> 8) & 0xFF));
}
}

return decodedStr;
std::string_view str_view(reinterpret_cast<const char *>(data), size);
return base64::from_base64(str_view);
}

static const std::string base64EncodingTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string encodeFromUtf8BufferToBase64String(const uint8_t *data, const size_t size) {
size_t pad = size % 3;
size_t last = size - pad;

size_t encodedStrSize = ((size + 2) / 3) * 4;
std::string encodedStr(encodedStrSize, '=');

int i = 0;
for (auto p = (uint8_t *)data; p != data + last; p += 3) {
uint32_t triple = unsigned(p[0]) << 16 | unsigned(p[1]) << 8 | p[2];

encodedStr[i++] = base64EncodingTable[triple >> 18];
encodedStr[i++] = base64EncodingTable[(triple >> 12) & 0x3F];
encodedStr[i++] = base64EncodingTable[(triple >> 6) & 0x3F];
encodedStr[i++] = base64EncodingTable[triple & 0x3F];
}

if (pad) {
uint8_t *p = (uint8_t *)data + last;

if (pad == 1) {
auto triple = unsigned(p[0]);

encodedStr[i++] = base64EncodingTable[triple >> 2];
encodedStr[i++] = base64EncodingTable[(triple << 4) & 0x3F];
} else if (pad == 2) {
auto triple = unsigned(p[0]) << 8 | p[1];

encodedStr[i++] = base64EncodingTable[triple >> 10];
encodedStr[i++] = base64EncodingTable[(triple >> 4) & 0x3F];
encodedStr[i++] = base64EncodingTable[(triple << 2) & 0x3F];
}
}

return encodedStr;
std::string_view str_view(reinterpret_cast<const char *>(data), size);
return base64::to_base64(str_view);
}
2 changes: 2 additions & 0 deletions encoding-core/ReactNativeEncodingBase64.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once

#include <base64.hpp>
#include <cstdint>
#include <string>
#include <string_view>

std::string decodeFromBase64BufferToUtf8String(const uint8_t *data, size_t size);
std::string encodeFromUtf8BufferToBase64String(const uint8_t *data, size_t size);
Loading