Skip to content
Snippets Groups Projects
Commit 41eca2f7 authored by Gospodin Bodurov's avatar Gospodin Bodurov
Browse files

Merge branch 'storage' into 'master'

Crypto Storage and LoginWithNewDevice and LoginWithPreviouslyAddedDevice APIs

See merge request !97
parents 3815637b 5b2e3056
Branches
Tags
1 merge request!97Crypto Storage and LoginWithNewDevice and LoginWithPreviouslyAddedDevice APIs
Showing
with 1212 additions and 75 deletions
...@@ -6,11 +6,3 @@ Gopkg.lock ...@@ -6,11 +6,3 @@ Gopkg.lock
temp/ temp/
yarn-error.log yarn-error.log
/.project /.project
/cpp/cmake-build*
/cpp/cmake-install*
/cpp/compile_commands.json
/cpp/.clangd
/cpp/tags
/cpp/docs/doxy
/cmake-*
/compile_commands.json
/.clangd
/tags
/docs/doxy
...@@ -9,6 +9,10 @@ option(VEREIGN_USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF) ...@@ -9,6 +9,10 @@ option(VEREIGN_USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
option(VEREIGN_USE_TIME_TRACE "Use compilation profiler" OFF) option(VEREIGN_USE_TIME_TRACE "Use compilation profiler" OFF)
option(VEREIGN_ENABLE_BENCHMARKING "Enable tests benchmarks" OFF) option(VEREIGN_ENABLE_BENCHMARKING "Enable tests benchmarks" OFF)
if (UNIX AND NOT APPLE)
set(LINUX TRUE)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0.24215.1") if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0.24215.1")
message(FATAL_ERROR "Microsoft Visual C++ version MSVC 19.0.24215.1 required") message(FATAL_ERROR "Microsoft Visual C++ version MSVC 19.0.24215.1 required")
...@@ -91,6 +95,7 @@ set(_cmake_prefix_paths ...@@ -91,6 +95,7 @@ set(_cmake_prefix_paths
${VENDOR_INSTALL_DIR} ${VENDOR_INSTALL_DIR}
${VENDOR_INSTALL_DIR}/grpc ${VENDOR_INSTALL_DIR}/grpc
${VENDOR_INSTALL_DIR}/nlohmann ${VENDOR_INSTALL_DIR}/nlohmann
${VENDOR_INSTALL_DIR}/sqlite3
) )
set(CMAKE_PREFIX_PATH ${_cmake_prefix_paths} CACHE STRING "") set(CMAKE_PREFIX_PATH ${_cmake_prefix_paths} CACHE STRING "")
...@@ -115,7 +120,7 @@ find_package( ...@@ -115,7 +120,7 @@ find_package(
1.72.0 1.72.0
EXACT EXACT
REQUIRED REQUIRED
COMPONENTS regex thread system date_time COMPONENTS regex thread system date_time filesystem
) )
find_package(Protobuf CONFIG REQUIRED) find_package(Protobuf CONFIG REQUIRED)
...@@ -137,6 +142,7 @@ else() ...@@ -137,6 +142,7 @@ else()
endif() endif()
find_package(nlohmann_json 3.7.3 REQUIRED) find_package(nlohmann_json 3.7.3 REQUIRED)
find_package(SQLite3 REQUIRED)
add_subdirectory("src") add_subdirectory("src")
add_subdirectory("tests") add_subdirectory("tests")
...@@ -176,6 +182,7 @@ message(STATUS "summary of build options: ...@@ -176,6 +182,7 @@ message(STATUS "summary of build options:
Boost libs ${Boost_LIBRARIES} Boost libs ${Boost_LIBRARIES}
gRPC ${gRPC_FOUND} [${gRPC_VERSION}] (LIBS='${_grpc_libs}') gRPC ${gRPC_FOUND} [${gRPC_VERSION}] (LIBS='${_grpc_libs}')
nlohmann ${nlohmann_json_FOUND} [${nlohmann_json_VERSION}] (HEADERS='${nlohmann_json_DIR}') nlohmann ${nlohmann_json_FOUND} [${nlohmann_json_VERSION}] (HEADERS='${nlohmann_json_DIR}')
sqlite3 ${SQLite3_FOUND} [${SQLite3_VERSION}] (LIBS='${SQLite3_LIBRARIES}')
Options: Options:
VEREIGN_USE_LLD ${VEREIGN_USE_LLD} VEREIGN_USE_LLD ${VEREIGN_USE_LLD}
VEREIGN_USE_PRECOMPILED_HEADERS ${VEREIGN_USE_PRECOMPILED_HEADERS} VEREIGN_USE_PRECOMPILED_HEADERS ${VEREIGN_USE_PRECOMPILED_HEADERS}
......
#ifndef VEREIGN_VEREIGN_H_ #ifndef __VEREIGN_VEREIGN_H
#define VEREIGN_VEREIGN_H_ #define __VEREIGN_VEREIGN_H
#ifdef _WIN32 #ifdef _WIN32
#ifdef WIN_EXPORT #ifdef WIN_EXPORT
...@@ -84,8 +84,12 @@ typedef struct vereign_service vereign_service; ...@@ -84,8 +84,12 @@ typedef struct vereign_service vereign_service;
* **NOTE: On failure the `err` object must be freed with vereign_error_free method.** * **NOTE: On failure the `err` object must be freed with vereign_error_free method.**
* *
* @param listen_address gRPC listen address, for example "localhost:". * @param listen_address gRPC listen address, for example "localhost:".
* @param vereignHost Vereign restapi host. * @param vereign_host Vereign restapi host.
* @param vereignPort Vereign restapi port - https, 443... * @param vereign_port Vereign restapi port - https, 443...
* @param storage_path Full path to directory where the storage files will stay.
* If the `storage_path` is `nullptr`, a default will be used. Under linux this default is
* `$HOME/vereign`, and under windows it is `C:\Users\<user>\AppData\Local\vereign`.
*
* @param err On failure err is initialized with the reason of the failure, * @param err On failure err is initialized with the reason of the failure,
* otherwise err is set to nullptr. * otherwise err is set to nullptr.
* @returns vereign_service object if the gRPC is up and running, otherwise returns nullptr. * @returns vereign_service object if the gRPC is up and running, otherwise returns nullptr.
...@@ -94,8 +98,7 @@ PUBLIC_API vereign_service* vereign_service_start( ...@@ -94,8 +98,7 @@ PUBLIC_API vereign_service* vereign_service_start(
const char* listen_address, const char* listen_address,
const char* vereign_host, const char* vereign_host,
const char* vereign_port, const char* vereign_port,
// FIXME: public_key must come from a storage internally. const char* storage_path,
const char* public_key,
vereign_error** err vereign_error** err
); );
...@@ -122,4 +125,4 @@ PUBLIC_API void vereign_service_shutdown(vereign_service* service); ...@@ -122,4 +125,4 @@ PUBLIC_API void vereign_service_shutdown(vereign_service* service);
}; };
#endif #endif
#endif // VEREIGN_VEREIGN_H_ #endif // __VEREIGN_VEREIGN_H
Subproject commit e861100984116aacf6d84cb8a09dc0ef81041509 Subproject commit 3e82fc7d60056e08b041577e332f1ec5029633ee
...@@ -3,9 +3,11 @@ if (fmt_FOUND) ...@@ -3,9 +3,11 @@ if (fmt_FOUND)
endif() endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_definitions(-DNOGDI) add_definitions(-DNOGDI -DNOMINMAX)
endif() endif()
add_definitions(-DBOOST_FILESYSTEM_NO_DEPRECATED)
include_directories( include_directories(
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src
...@@ -45,15 +47,61 @@ if (VEREIGN_USE_PRECOMPILED_HEADERS) ...@@ -45,15 +47,61 @@ if (VEREIGN_USE_PRECOMPILED_HEADERS)
endif() endif()
set(VEREIGNLIB_SRC set(VEREIGNLIB_SRC
vereign/core/rand.cc
vereign/core/string.cc
vereign/fs/util.cc
vereign/fs/operations.cc
vereign/fs/path.cc
vereign/restapi/detail/http_reader.cc vereign/restapi/detail/http_reader.cc
vereign/restapi/client.cc vereign/restapi/client.cc
vereign/service/passport_service.cc
vereign/grpc/gen/gen.cc vereign/grpc/gen/gen.cc
vereign/grpc/json/encoder.cc vereign/grpc/json/encoder.cc
vereign/grpc/service_registry.cc vereign/grpc/service_registry.cc
vereign/grpc/server.cc vereign/grpc/server.cc
vereign/sqlite/statement.cc
vereign/sqlite/connection.cc
vereign/bytes/view_dump.cc
vereign/bytes/buffer.cc
vereign/encoding/binary.cc
vereign/encoding/base64.cc
vereign/encoding/hex.cc
vereign/crypto/rand.cc
vereign/crypto/aes.cc
vereign/crypto/rsa.cc
vereign/crypto/bio.cc
vereign/crypto/digest.cc
vereign/kvstore/lock.cc
vereign/kvstore/detail/base_crypto_storage.cc
vereign/kvstore/sqlite_storage.cc
vereign/kvstore/crypto_storage.cc
vereign/kvstore/detail/value_encoder.cc
vereign/identity/provider.cc
vereign/service/identity_service.cc
) )
if (LINUX)
list(APPEND VEREIGNLIB_SRC
vereign/kvstore/detail/linux_crypto_storage.cc
)
elseif (WIN32)
list(APPEND VEREIGNLIB_SRC
vereign/ncrypt/errors.cc
vereign/ncrypt/unique_ptr.cc
vereign/ncrypt/rsa.cc
vereign/kvstore/detail/win_crypto_storage.cc
)
endif()
file(GLOB GENERATED_SERVICES_SRC vereign/service/gen/*.cc) file(GLOB GENERATED_SERVICES_SRC vereign/service/gen/*.cc)
list(APPEND VEREIGNLIB_SRC ${GENERATED_SERVICES_SRC}) list(APPEND VEREIGNLIB_SRC ${GENERATED_SERVICES_SRC})
...@@ -67,7 +115,11 @@ target_link_libraries(vereignlib PUBLIC ...@@ -67,7 +115,11 @@ target_link_libraries(vereignlib PUBLIC
fmt::fmt fmt::fmt
gRPC::grpc++_reflection gRPC::grpc++_reflection
gRPC::grpc++ gRPC::grpc++
Boost::filesystem
$<$<CXX_COMPILER_ID:MSVC>:Boost::date_time> $<$<CXX_COMPILER_ID:MSVC>:Boost::date_time>
SQLite::SQLite3
$<$<CXX_COMPILER_ID:MSVC>:ncrypt.lib>
$<$<CXX_COMPILER_ID:MSVC>:cryptui.lib>
) )
add_library(vereign SHARED add_library(vereign SHARED
...@@ -96,6 +148,8 @@ add_executable(csandbox ${csandbox_sources}) ...@@ -96,6 +148,8 @@ add_executable(csandbox ${csandbox_sources})
target_link_libraries(csandbox target_link_libraries(csandbox
PRIVATE vereignlib PRIVATE vereignlib
$<$<CXX_COMPILER_ID:MSVC>:Boost::date_time> $<$<CXX_COMPILER_ID:MSVC>:Boost::date_time>
Boost::filesystem
# Boost::file
# Boost::thread # Boost::thread
# vereign # vereign
# fmt::fmt # fmt::fmt
......
#include "vereign/crypto/rand.hh"
#include <vereign/bytes/view.hh>
#include <vereign/bytes/buffer.hh>
#include <vereign/bytes/view_dump.hh>
#include <vereign/fs/path.hh>
#include <vereign/fs/util.hh>
#include <iostream>
auto main(int argc, char** argv) -> int {
argc = 0;
argv = nullptr;
auto path = vereign::fs::TempFilePath(vereign::fs::path::Join("tmp", "foo"), "test_db_");
std::cout << path << std::endl;
auto main(int argc, char* argv[]) -> int {
return 0; return 0;
} }
#include <vereign/bytes/buffer.hh>
#include <vereign/bytes/errors.hh>
#include <memory>
namespace vereign::bytes {
Buffer::Buffer() noexcept
: cap_{0},
size_{0},
data_{nullptr}
{
}
Buffer::Buffer(std::size_t cap)
: cap_{cap},
size_{0},
data_{nullptr}
{
if (cap == 0) {
return;
}
data_ = reinterpret_cast<uint8_t*>(std::malloc(cap));
if (data_ == nullptr) {
throw std::bad_alloc{};
}
}
Buffer::Buffer(bytes::View src)
: cap_{src.Size()},
size_{src.Size()},
data_{nullptr}
{
if (size_ == 0) {
return;
}
data_ = reinterpret_cast<uint8_t*>(std::malloc(cap_));
if (data_ == nullptr) {
throw std::bad_alloc{};
}
std::memcpy(data_, src.Data(), src.Size());
}
Buffer::Buffer(Buffer&& other) noexcept
: cap_{other.cap_},
size_{other.size_},
data_{other.data_}
{
other.cap_ = 0;
other.size_ = 0;
other.data_ = nullptr;
}
auto Buffer::operator=(Buffer&& other) noexcept -> Buffer& {
std::swap(cap_, other.cap_);
std::swap(size_, other.size_);
std::swap(data_, other.data_);
return *this;
}
Buffer::~Buffer() {
std::free(data_);
}
auto Buffer::Size() const noexcept -> std::size_t {
return size_;
}
auto Buffer::FreeCap() const noexcept -> std::size_t {
return cap_ - size_;
}
auto Buffer::Cap() const noexcept -> std::size_t {
return cap_;
}
auto Buffer::begin() noexcept -> uint8_t* {
return data_;
}
auto Buffer::begin() const noexcept -> const uint8_t* {
return data_;
}
auto Buffer::end() noexcept -> uint8_t* {
return data_ + size_;
}
auto Buffer::end() const noexcept -> const uint8_t* {
return data_ + size_;
}
void Buffer::Reserve(std::size_t size) {
if (cap_ == 0) {
cap_ = size;
data_ = reinterpret_cast<uint8_t*>(std::malloc(cap_));
if (data_ == nullptr) {
throw std::bad_alloc{};
}
return;
}
if (size <= cap_ - size_) {
return;
}
auto cap = cap_ * 2;
if (size > cap - size_) {
cap = size_ + size;
}
auto newData = reinterpret_cast<uint8_t*>(std::realloc(data_, cap));
if (newData == nullptr) {
throw std::bad_alloc{};
}
data_ = newData;
cap_ = cap;
}
void Buffer::Reset() {
size_ = 0;
}
void Buffer::IncSize(std::size_t val) {
if (size_ + val > cap_) {
throw IncrementOutOfBounds{};
}
size_ += val;
}
auto Buffer::WriteWithinCap(bytes::View src) noexcept -> std::size_t {
auto size = std::min(cap_ - size_, src.Size());
std::memcpy(data_ + size_, src.Data(), size);
size_ += size;
return size;
}
auto Buffer::Write(bytes::View src) -> std::size_t {
Reserve(src.Size());
return WriteWithinCap(src);
}
auto Buffer::View() const noexcept -> bytes::View {
return bytes::View{data_, size_};
}
auto Buffer::View(std::size_t start) const noexcept -> bytes::View {
return bytes::View{data_, size_}.Slice(start);
}
auto Buffer::operator[](std::size_t index) -> uint8_t& {
if (index >= cap_) {
throw IndexOutOfBounds{};
}
return data_[index];
}
auto Buffer::operator[](std::size_t index) const -> const uint8_t& {
if (index >= cap_) {
throw IndexOutOfBounds{};
}
return data_[index];
}
} // namespace vereign::bytes
#ifndef __VEREIGN_BYTES_BUFFER_HH
#define __VEREIGN_BYTES_BUFFER_HH
#include <vereign/bytes/view.hh>
#include <cstring>
namespace vereign::bytes {
/**
* Dynamically expandable memory buffer.
*
* The buffer is a 3-tuple - pointer, size and capacity.
* Typically used in functions for output parameters and return values.
* Provides API that is easy to use with C APIs.
*
* The buffer is move only.
*/
class Buffer {
public:
/**
* Creates empty buffer.
*/
Buffer() noexcept;
/**
* Creates a buffer with reserved memory capacity.
*
* The size of the buffer is zero.
*
* @param cap The capacity of the buffer.
*
* @throws std::bad_alloc when memory reservation fails.
*/
Buffer(std::size_t cap);
/**
* Creates a buffer by copying from source bytes view.
*
* @param src The source that will be copied from.
*
* @throws std::bad_alloc when memory reservation fails.
*/
Buffer(View src);
/**
* The buffer is movable.
*/
Buffer(Buffer&& other) noexcept;
auto operator=(Buffer&& other) noexcept -> Buffer&;
// disable copying
Buffer(const Buffer&) = delete;
auto operator=(const Buffer&) -> Buffer& = delete;
/**
* Frees the buffer memory.
*/
~Buffer();
/**
* Returns a pointer to the first byte of the buffer.
*
* Buffer::begin(), Buffer::end() pair is useful for range loops.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("foo")};
* for (const auto& byte : buf) {
* byte = 'x';
* }
*
* assert(buf.View().String() == "xxx");
* @endcode
*/
auto begin() noexcept -> uint8_t*;
/**
* Returns a pointer to the first byte of the buffer.
*
* Buffer::begin(), Buffer::end() pair is useful for range loops.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("foo bar")};
* std::string s;
*
* for (const auto& byte : buf) {
* s += byte;
* }
*
* assert(s == "foo bar");
* @endcode
*/
auto begin() const noexcept -> const uint8_t*;
/**
* Returns a pointer to the byte following the last byte in the buffer.
*
* Note that this is the last byte in the range [0, size).
* It is often used when calling C APIs.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("foo bar")};
*
* buf.Reserve(4);
* std::strncpy((char*)buf.end(), " baz", 4);
* buf.IncSize(4);
*
* assert(buf.View().String() == "foo bar baz");
* @endcode
*/
auto end() noexcept -> uint8_t*;
/**
* Returns a read only pointer to the byte following the last byte in the buffer.
*
* Note that this is the last byte in the range [0, size).
*/
auto end() const noexcept -> const uint8_t*;
/**
* Access a byte in the range of [0, cap).
*
* @param index The index of the byte to access.
*
* @throws std::runtime_error when the passed index is out of bounds.
*/
auto operator[](std::size_t index) -> uint8_t&;
/**
* Read only access a byte in the range of [0, cap).
*
* @param index The index of the byte to access.
*
* @throws std::runtime_error when the passed index is out of bounds.
*/
auto operator[](std::size_t index) const -> const uint8_t&;
/**
* Retrieve buffer size.
*
* @returns the buffer size.
*/
auto Size() const noexcept -> std::size_t;
/**
* Retrieve buffer capacity.
*
* @returns the buffer capacity.
*/
auto Cap() const noexcept -> std::size_t;
/**
* Reserve memory, so that there is at least `size` free capacity.
*
* If there is already enough free capacity, no memory allocation is done.
* The allocated memory may be bigger than what is needed.
*
* If the call is successful then it is guaranteed that `this->FreeCap() >= size`.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("foo bar")};
*
* buf.Reserve(4); // ensure there will be a free capacity for 4 bytes
* std::strncpy((char*)buf.end(), " baz", 4); // copy the bytes
* buf.IncSize(4); // update the buffer size with the newly written bytes
*
* assert(buf.View().String() == "foo bar baz");
* @endcode
*
* @param size The desired free capacity.
*
* @throws std::bad_alloc when memory allocation fails.
*/
void Reserve(std::size_t size);
/**
* Sets the buffer size to zero.
*
* This does not free any memory, so the capacity stays the intact, and the buffer can be reused.
*/
void Reset();
/**
* Increments the size of the buffer.
*
* It is typically used after some function has written bytes to the end of the buffer.
*
* @param val The value that will be added to the current size.
*/
void IncSize(std::size_t val);
/**
* Retrieve the buffer free capacity.
*
* This is equal to `this->Cap() - this->Size()`.
*/
auto FreeCap() const noexcept -> std::size_t;
/**
* Adds bytes up to the currently available buffer capacity.
*
* After the operation succeeds, the buffer size will be incremented with the number of bytes
* that have been copied.
*
* Example:
* @code
* auto buf = bytes::Buffer{3};
* buf.WriteWithinCap(bytes::View("foo bar"));
*
* // only 3 bytes are written
* assert(buf.View.String() == "foo");
* @endcode
*
* @param src The source that will be appended to the buffer.
* @returns The amount of bytes that were actually copied into the buffer.
*/
auto WriteWithinCap(bytes::View src) noexcept -> std::size_t;
/**
* Adds a source view of bytes to the buffer.
*
* If the buffer does not have enough capacity, it will be expanded.
*
* Example:
* @code
* auto buf = bytes::Buffer{3};
* buf.WriteWithinCap(bytes::View("foo bar"));
*
* // all bytes are written
* assert(buf.View.String() == "foo bar");
* @endcode
*
* @param The source that will be appended to the buffer.
* @returns The amount of bytes that were copied into the buffer. That is equal to src.Size().
*/
auto Write(bytes::View src) -> std::size_t;
/**
* Retrieve a read only view of the buffer.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("123")};
* assert(buf.View().String() == "123");
* @endcode
*
* @returns a read only view range [0, this->Size()).
*/
auto View() const noexcept -> bytes::View;
/**
* Retrieve a read only view of the buffer staring from a given offset.
*
* Example:
* @code
* auto buf = bytes::Buffer{bytes::View("123")};
* assert(buf.View(1).String() == "23");
* @endcode
*
* @returns a read only view range [start, this->Size()).
*/
auto View(std::size_t start) const noexcept -> bytes::View;
private:
std::size_t cap_;
std::size_t size_;
uint8_t* data_;
};
} // namespace vereign::bytes
#endif // __VEREIGN_BYTES_BUFFER_HH
#ifndef __VEREIGN_BYTES_BYTES_HH
#define __VEREIGN_BYTES_BYTES_HH
#include <vereign/bytes/view.hh>
#include <cstring>
namespace vereign::bytes {
class Bytes {
public:
Bytes(uint8_t* data, std::size_t size)
: size_{size},
data_{data}
{}
Bytes(const Bytes&) = default;
auto operator=(const Bytes&) -> Bytes& = default;
auto Data() const -> uint8_t* {
return data_;
}
auto CharData() const -> unsigned char* {
return data_;
}
auto Size() const -> std::size_t {
return size_;
}
private:
std::size_t size_;
uint8_t* data_;
};
inline auto Copy(Bytes dst, View src) noexcept -> std::size_t {
auto size = std::min(src.Size(), dst.Size());
std::memcpy(dst.Data(), src.Data(), size);
return size;
}
} // namespace vereign::bytes
#endif // __VEREIGN_BYTES_BYTES_HH
#ifndef __VEREIGN_BYTES_ERRORS_HH
#define __VEREIGN_BYTES_ERRORS_HH
#include <stdexcept>
namespace vereign::bytes {
class Error : public std::runtime_error {
public:
Error(const std::string& what)
: std::runtime_error{what}
{
}
};
class IndexOutOfBounds : public Error {
public:
IndexOutOfBounds()
: Error{"index out of bounds"}
{
}
};
class IncrementOutOfBounds : public Error {
public:
IncrementOutOfBounds()
: Error{"cannot increment size pass the capacity"}
{
}
};
} // namespace vereign::bytes
#endif // __VEREIGN_BYTES_ERRORS_HH
#ifndef __VEREIGN_BYTES_VIEW_HH
#define __VEREIGN_BYTES_VIEW_HH
#include <vereign/bytes/errors.hh>
#include <cstring>
#include <string>
#include <string_view>
#include <stdexcept>
#include <algorithm>
namespace vereign::bytes {
/**
* Bytes view represents a read only access to a range of bytes.
*
* The View is a 2-tuple with pointer and size.
* Typically used in functions for input parameters.
*
* **NOTE: The View does not own the memory that it references.**
*/
class View {
public:
/**
* Creates empty view.
*/
View() = default;
/**
* Creates a view from raw pointer and a size.
*
* @param data Pointer to the memory.
* @param size The size of the memory.
*/
View(const uint8_t* data, std::size_t size) noexcept
: size_{size},
data_{data}
{
}
/**
* Create a view from a string view.
*
* @param str The input string view.
*/
View(std::string_view str) noexcept
: size_{str.length()},
data_{str.length() > 0 ? reinterpret_cast<const uint8_t*>(str.data()): nullptr}
{
}
/**
* Creates a view from wide string view.
*
* @param str The input string.
*/
View(std::wstring_view str) noexcept
: size_{str.length() * sizeof(wchar_t)},
data_{size_ > 0 ? reinterpret_cast<const uint8_t*>(str.data()): nullptr}
{
}
/**
* Creates a view from void pointer and a size.
*
* @param data Pointer to the memory.
* @param size The size of the memory.
*/
View(const void* ptr, std::size_t size) noexcept
: size_{size},
data_{static_cast<const uint8_t*>(ptr)}
{
}
// default copyable.
View(const View&) = default;
auto operator=(const View&) -> View& = default;
/**
* Slice returns a new view in the interval [start, size).
*
* If the start is bigger than the size of the slice it returns empty view.
*
* @param start The beginning of the new View.
* @returns a new view in the interval [start, size).
*/
auto Slice(std::size_t start) const -> View {
if (start >= size_) {
return View(data_, 0);
}
return View(data_ + start, size_ - start);
}
/**
* Slice returns a new view in the interval [start, end).
*
* If the start is bigger than the size of the slice it returns empty view.
* If the end is bigger than the size of the slice it returns [start, size).
*
* @param start The beginning of the new View.
* @returns a new view in the interval [start, size).
*/
auto Slice(std::size_t start, std::size_t end) const -> View {
if (start >= size_) {
return View(data_, 0);
}
return View(data_ + start, std::min(size_, end) - start);
}
/**
* Retrieve a pointer to the data.
*
* @returns a pointer to the data.
*/
auto Data() const noexcept -> const uint8_t* {
return data_;
}
/**
* Retrieve a char pointer to the data.
*
* @returns a char pointer to the data.
*/
auto CharData() const noexcept -> const char* {
return reinterpret_cast<const char*>(data_);
}
/**
* Retrieve a wide char pointer to the data.
*
* @returns a wide char pointer to the data.
*/
auto WideCharData() const noexcept -> const wchar_t* {
return reinterpret_cast<const wchar_t*>(data_);
}
/**
* Retrieve view size.
*
* @returns view size.
*/
auto Size() const noexcept -> std::size_t {
return size_;
}
/**
* Retrieve a string view of the data.
*
* @returns a string view of the data.
*/
auto String() const noexcept -> std::string_view {
return std::string_view{CharData(), size_};
}
/**
* Retrieve a wide string view of the data.
*
* @returns a wide string view of the data.
*/
auto WideString() const noexcept -> std::wstring_view {
return std::wstring_view{WideCharData(), size_/sizeof(wchar_t)};
}
/**
* Binary compare the contents of two views.
*
* @returns true if the views are of the same size and if all the bytes in the two views are equal.
*/
auto operator==(View other) const noexcept -> bool {
if (size_ != other.size_) {
return false;
}
return std::memcmp(data_, other.data_, size_) == 0;
}
/**
* Binary compare the contents of two views.
*
* @returns true if the views are of different size or if the bytes in the two views are not equal.
*/
auto operator!=(View other) const noexcept -> bool {
return !(*this == other);
}
/**
* Access a single byte in the view.
*
* @param index The index of the byte that will be returned.
* @returns the byte at the specified index.
*
* @throws bytes::IndexOutOfBounds when the index is out of bounds.
*/
auto operator[](std::size_t index) const -> const uint8_t& {
if (index >= size_ ) {
throw IndexOutOfBounds{};
}
return data_[index];
}
private:
std::size_t size_ = 0;
const uint8_t* data_ = nullptr;
};
} // namespace vereign::bytes
#endif // __VEREIGN_BYTES_VIEW_HH
#include <vereign/bytes/view_dump.hh>
#include <iomanip>
namespace vereign::bytes {
namespace detail {
auto operator<<(std::ostream& os, const ViewDump& vd) -> std::ostream& {
if (vd.buf_.Size() == 0) {
os << "empty buffer\n";
return os;
}
core::IosFlagsLock os_flags(os);
os << std::hex;
for (std::size_t i = 0; i < vd.buf_.Size(); ++i) {
if (i % 16 == 0) {
os << "0x" << std::setfill('0') << std::setw(4) << i << ": ";
}
if (i % 2 == 0) {
os << " ";
}
os << std::setfill('0') << std::setw(2) << (unsigned int) vd.buf_.Data()[i];
if ((i != 0 && (i + 1) % 16 == 0) || i == vd.buf_.Size() - 1) {
int bytes = (i + 1) % 16 == 0 ? 0 : (16 - (i + 1) % 16);
os << " " << std::setfill(' ') << std::setw(2 * bytes + bytes / 2) << "";
vd.printChars(os, i - i % 16);
os << "\n";
}
}
return os;
}
void ViewDump::printChars(std::ostream& os, std::size_t offset) const {
auto seq = buf_.Slice(offset, offset + 16);
for (int i = 0; i < (int) seq.Size(); ++i) {
auto ch = seq.Data()[i];
if (std::isprint(ch) != 0) {
os << ch;
} else {
os << ".";
}
}
}
} // namespace detail
auto dump(View buf) -> detail::ViewDump {
return detail::ViewDump{buf};
}
auto dump(const Buffer& buf) -> detail::ViewDump {
return detail::ViewDump{buf.View()};
}
} // namespace vereign::bytes
#ifndef __VEREIGN_BYTES_VIEW_DUMP_HH
#define __VEREIGN_BYTES_VIEW_DUMP_HH
#include <vereign/bytes/view.hh>
#include <vereign/bytes/buffer.hh>
#include <vereign/core/io_flags_lock.hh>
#include <iostream>
namespace vereign::bytes {
namespace detail {
class ViewDump;
}
/**
* Returns a view dump object that can write the view dump into std::ostream.
*
* The dump is the good old hexadecimal format.
*
* Example:
* @code
* std::string input{"foo bar"};
* std::cout << bytes::dump(bytes::View(input)) << std::endl;
*
* // Output:
* // 0x0000: 666f 6f20 6261 72 foo bar
*
* auto buf = crypto::Rand(32);
* std::cout << bytes::dump(buf.View()) << std::endl;
*
* // Output:
* // 0x0000: 1666 855a 650a 7549 ed0f ec01 4d87 09bf .f.Ze.uI....M...
* // 0x0010: e644 dbc8 7943 37b4 185c dbab 4977 ff3f .D..yC7..\..Iw.?
*
* @endcode
*/
auto dump(View buf) -> detail::ViewDump;
/**
* Returns a dump object that can write the buffer dump into std::ostream.
*
* The dump is the good old hexadecimal format.
*
* Example:
* @code
auto buf = bytes::Buffer{bytes::View("foo bar")};
std::cout << bytes::dump(buf) << std::endl;
*
* // Output:
* // 0x0000: 666f 6f20 6261 72 foo bar
*
* auto buf = crypto::Rand(32);
* std::cout << bytes::dump(buf) << std::endl;
*
* // Output:
* // 0x0000: 1666 855a 650a 7549 ed0f ec01 4d87 09bf .f.Ze.uI....M...
* // 0x0010: e644 dbc8 7943 37b4 185c dbab 4977 ff3f .D..yC7..\..Iw.?
*
* @endcode
*/
auto dump(const Buffer& buf) -> detail::ViewDump;
namespace detail {
/**
* Helper for dumping a view to a std::ostream.
*
* Users typically will use the bytes::dump functions.
*/
class ViewDump {
public:
auto operator=(const ViewDump&) -> ViewDump& = delete;
explicit ViewDump(View buf)
: buf_(buf)
{
}
friend auto operator<<(std::ostream& os, const ViewDump& vd) -> std::ostream&;
private:
void printChars(std::ostream& os, std::size_t offset) const;
private:
View buf_;
};
} // namespace detail
} // namespace vereign::bytes
#endif // __VEREIGN_BYTES_VIEW_DUMP_HH
#ifndef __VEREIGN_CORE_HEX_HH
#define __VEREIGN_CORE_HEX_HH
#include <string>
namespace vereign {
namespace core {
namespace detail {
inline auto charToInt(char ch) -> int {
if (ch >= '0' && ch <= '9') {
return ch - '0';
}
if (ch >= 'A' && ch <= 'F') {
return ch - 'A' + 10;
}
if (ch >= 'a' && ch <= 'f') {
return ch - 'a' + 10;
}
return 0;
}
} // namespace detail
inline auto BinToHex(const unsigned char* src, std::size_t size) -> std::string {
static const char* nibbles = { "0123456789abcdef" };
std::string result;
result.reserve(size * 2);
for (std::size_t i = 0; i < size; ++i) {
result.push_back(nibbles[src[i] >> 4]);
result.push_back(nibbles[src[i] & 0x0F]);
}
return result;
}
inline auto BinToHex(const std::string& src) -> std::string {
return BinToHex((unsigned char*) src.c_str(), src.size());
}
inline void hex_to_bin(const std::string& src, unsigned char* dst) {
for (int i = 0, len = (int) src.size() - 1; i < len; i += 2) {
dst[i/2] = detail::charToInt(src[i]) * 16 + detail::charToInt(src[i + 1]);
}
}
} // namespace core
} // namespace vereign
#endif // __VEREIGN_CORE_HEX_HH
#ifndef __VEREIGN_CORE_IOS_FLAGS_LOCK_HH
#define __VEREIGN_CORE_IOS_FLAGS_LOCK_HH
#include <ios>
namespace vereign::core {
/**
* Restore the ios flags of a stream when is it self destroyed.
*/
class IosFlagsLock {
public:
IosFlagsLock(const IosFlagsLock&) = delete;
auto operator=(const IosFlagsLock&) -> IosFlagsLock& = delete;
IosFlagsLock(std::ios_base& str)
: str_(str),
flags_(str.flags())
{
}
~IosFlagsLock() {
restore();
}
void restore() {
str_.flags(flags_);
}
private:
std::ios_base& str_;
std::ios_base::fmtflags flags_;
};
} // namespace vereign::core
#endif // __TURBO_CORE_IOS_FLAGS_LOCK_HH
#ifndef __VEREIGN_LOCK_GUARD_HH
#define __VEREIGN_LOCK_GUARD_HH
namespace vereign::core {
template <class Lockable>
class LockGuard {
public:
explicit LockGuard(Lockable& lock)
: lock_{lock}
{
lock.Lock();
}
~LockGuard() noexcept {
lock_.Unlock();
}
LockGuard(const LockGuard&) = delete;
auto operator=(const LockGuard&) -> LockGuard& = delete;
private:
Lockable& lock_;
};
} // namespace vereign::kvstore
#endif // __VEREIGN_LOCK_GUARD_HH
#include <vereign/core/rand.hh>
#include <random>
namespace vereign::core {
auto RandNumber(int n) -> int {
static std::random_device dev;
static std::mt19937 rng(dev());
using Dist = std::uniform_int_distribution<std::mt19937::result_type>;
static Dist dist{};
return dist(dev, Dist::param_type{0, static_cast<unsigned long>(n) - 1} );
}
auto RandLowerAlpha(int len) -> std::string {
using namespace std::string_view_literals;
static constexpr std::string_view chars = "0123456789abcdefghijklmnopqrstuvwxyz"sv;
std::string result;
result.resize(len);
for (int i = 0; i < len; i++) {
result[i] = chars[RandNumber(chars.size())];
}
return result;
}
} // namespace vereign::core
#ifndef __VEREIGN_CORE_RAND_HH
#define __VEREIGN_CORE_RAND_HH
#include <random>
namespace vereign::core {
/**
* Generated random number in the half closed interval [0, n).
*
* @param n Upper bound of the generated random number.
* @returns a random number in the half closed interval [0, n).
*/
auto RandNumber(int n) -> int;
/**
* Generates random string with alpha lower case characters.
*
* @param len The length of the desired random string.
* @returns a random string of size len consisting of numbers 0-9 and lower case latin chars a-z.
*/
auto RandLowerAlpha(int len) -> std::string;
} // namespace vereign::core
#endif // __VEREIGN_CORE_RAND_HH
#include <vereign/core/string.hh>
#include <iostream>
#ifdef _WIN32
# include <windows.h>
# include <stringapiset.h>
#endif
namespace vereign::string {
#ifdef _WIN32
auto widen(std::string_view utf8_str) -> std::wstring {
if (utf8_str.empty()) {
return L"";
}
int num_chars = MultiByteToWideChar(CP_UTF8 , 0, utf8_str.data(), utf8_str.length(), nullptr, 0);
if (num_chars == 0) {
return std::wstring{};
}
std::wstring result;
result.resize(num_chars);
num_chars = MultiByteToWideChar(
CP_UTF8,
0,
utf8_str.data(),
utf8_str.length(),
result.data(),
num_chars
);
if (num_chars == 0) {
return L"";
}
return result;
}
auto narrow(std::wstring_view utf16_str) -> std::string {
if (utf16_str.empty()) {
return "";
}
int num_chars = WideCharToMultiByte(
CP_UTF8,
0,
utf16_str.data(),
utf16_str.length(),
nullptr,
0,
nullptr,
nullptr
);
if (num_chars == 0) {
return "";
}
std::string result;
result.resize(num_chars);
int new_size = WideCharToMultiByte(
CP_UTF8,
0,
utf16_str.data(),
utf16_str.length(),
result.data(),
num_chars,
nullptr,
nullptr
);
if (new_size == 0) {
return "";
}
result.resize(new_size);
return result;
}
#endif
auto tail(const std::string& src, std::size_t length) -> std::string {
if (length >= src.size()) {
return src;
}
return src.substr(src.size() - length);
}
} // vereign::string
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment