Compare commits
88 Commits
release-d2
...
release-d2
Author | SHA1 | Date | |
---|---|---|---|
257e857116 | |||
0035faa416 | |||
5c34c26080 | |||
b6f8c9e242 | |||
0698353fbf | |||
9576f78abf | |||
7b07edd9e4 | |||
a5b01bb0d7 | |||
1c5fed05bf | |||
d4983cf3c6 | |||
fc246ee396 | |||
167e470091 | |||
dae719f78a | |||
df96407669 | |||
17762b40b7 | |||
4f4ec089fd | |||
f58c658be1 | |||
e92e980fde | |||
71b6c72c46 | |||
da75443d4c | |||
a45692fa4c | |||
112c2c4212 | |||
f8fb458e32 | |||
20f4d50ad6 | |||
0eaf54bd22 | |||
978dd70770 | |||
9a49761c01 | |||
880e6e49d6 | |||
4a221e52db | |||
4f1593a0ed | |||
18166f6123 | |||
228b6dd031 | |||
a1a0abe83b | |||
77ece05bf1 | |||
9e624619b3 | |||
5c5c62dc55 | |||
53358d2e03 | |||
c178a2273b | |||
f86d0e697a | |||
4d806021d0 | |||
98a0c42040 | |||
0eb33f823c | |||
2dad1688b5 | |||
f1110bd849 | |||
b1a0fcbc57 | |||
e3e00b1716 | |||
faaddd1234 | |||
f37515707f | |||
86652ca8d4 | |||
819959745d | |||
f91874182e | |||
dfb17c851b | |||
e2952ec8c1 | |||
9560ccf476 | |||
e7ea76a7ac | |||
bae54a906b | |||
b0f268f371 | |||
b39735bb08 | |||
6af681bad6 | |||
9b84d9d8e0 | |||
4694bb9dd7 | |||
f758566041 | |||
cef5fcd86f | |||
8e297f32d4 | |||
be16229bf7 | |||
11e500520a | |||
00e645e7a3 | |||
3ff4a59373 | |||
5265a94a80 | |||
b3fa531aa0 | |||
8753d39b66 | |||
ed0bf268ba | |||
d0f5819072 | |||
d2e7528dae | |||
1d07890668 | |||
82a07737ec | |||
9091f9bd02 | |||
5d95b188d8 | |||
a4000f6497 | |||
12c5339295 | |||
4064592acc | |||
b9c2f3631d | |||
d2ec3b8350 | |||
19422ced3e | |||
540e67fcd8 | |||
89854a584a | |||
8b74920270 | |||
a74cd1c926 |
@ -5,6 +5,7 @@ project(nostalgia)
|
||||
set(NOSTALGIA_BUILD_TYPE "Native" CACHE STRING "The type of build to produce(Native/GBA)")
|
||||
set(NOSTALGIA_IDE_BUILD ON CACHE STRING "Build for IDE's to run")
|
||||
set(NOSTALGIA_QT_PATH "" CACHE STRING "Path to Qt Libraries")
|
||||
set(NOSTALGIA_BUILD_PLAYER ON CACHE BOOL "Build Player")
|
||||
set(NOSTALGIA_BUILD_STUDIO ON CACHE BOOL "Build Studio")
|
||||
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
|
||||
@ -37,6 +38,7 @@ if(NOT OX_BARE_METAL)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
# enable ccache
|
||||
find_program(CCACHE_PROGRAM ccache)
|
||||
if(CCACHE_PROGRAM)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
|
||||
@ -116,11 +118,11 @@ endif()
|
||||
|
||||
enable_testing()
|
||||
|
||||
add_subdirectory(deps/ox)
|
||||
include_directories(SYSTEM deps/ox/src)
|
||||
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
|
||||
add_subdirectory(deps/gbastartup)
|
||||
endif()
|
||||
|
||||
add_subdirectory(deps/ox)
|
||||
include_directories(deps/ox/src)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
17
Jenkinsfile
vendored
17
Jenkinsfile
vendored
@ -1,17 +0,0 @@
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'make conan'
|
||||
sh 'make configure-debug configure-release'
|
||||
sh 'make'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh 'make test'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
Makefile
8
Makefile
@ -31,7 +31,7 @@ build:
|
||||
.PHONY: pkg-gba
|
||||
pkg-gba:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target install;)
|
||||
${ENV_RUN} ./scripts/gba-pkg
|
||||
${ENV_RUN} ./scripts/gba-pkg sample_project
|
||||
.PHONY: install
|
||||
install:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target install;)
|
||||
@ -40,9 +40,9 @@ clean:
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target clean;)
|
||||
.PHONY: purge
|
||||
purge:
|
||||
${ENV_RUN} ${RM_RF} build .current_build
|
||||
${ENV_RUN} ${RM_RF} build .current_build dist
|
||||
.PHONY: test
|
||||
test:
|
||||
test: build
|
||||
$(foreach file, $(wildcard build/*), cmake --build $(file) --target test;)
|
||||
|
||||
.PHONY: run
|
||||
@ -86,7 +86,7 @@ devenv-shell:
|
||||
|
||||
.PHONY: conan
|
||||
conan:
|
||||
@mkdir -p conanbuild && cd conanbuild && conan install --build missing ../
|
||||
@mkdir -p conanbuild && cd conanbuild && conan install ../ --build=missing
|
||||
|
||||
.PHONY: configure-release
|
||||
configure-release:
|
||||
|
14
README.md
14
README.md
@ -2,8 +2,18 @@
|
||||
|
||||
## Setup
|
||||
|
||||
### Linux
|
||||
|
||||
Make sure conan is using the C++11 version of libstdc++.
|
||||
|
||||
conan profile update settings.compiler.libcxx=libstdc++11 default
|
||||
|
||||
### macOS
|
||||
|
||||
Run something along the lines of the following to let CMake know where Qt is installed. You may need to adjust this location.
|
||||
Install and use gmake instead of the make that comes with the system.
|
||||
|
||||
export NOSTALGIA_QT_PATH=/usr/local/Cellar/qt5/5.8.0_2/
|
||||
## Build
|
||||
|
||||
Build options: release, debug, gba, gba-debug
|
||||
|
||||
make purge conan configure-{gba,release,debug} install
|
||||
|
@ -2,8 +2,8 @@ from conans import ConanFile, CMake
|
||||
|
||||
class NostalgiaConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
requires = "jsoncpp/1.9.0@theirix/stable", "sdl2/2.0.10@bincrafters/stable"#, "qt/5.14.0@bincrafters/stable" # comma-separated list of requirements
|
||||
requires = "jsoncpp/1.9.2", "sdl2/2.0.10@bincrafters/stable"
|
||||
generators = "cmake", "cmake_find_package", "cmake_paths"
|
||||
|
||||
def requirements(self):
|
||||
pass
|
||||
#default_options = {
|
||||
# "sdl2:nas": False
|
||||
#}
|
||||
|
2
deps/gbastartup/CMakeLists.txt
vendored
2
deps/gbastartup/CMakeLists.txt
vendored
@ -1,4 +1,5 @@
|
||||
enable_language(C ASM)
|
||||
|
||||
add_library(
|
||||
GbaStartup
|
||||
gba_crt0.s
|
||||
@ -7,4 +8,5 @@ add_library(
|
||||
|
||||
target_link_libraries(
|
||||
GbaStartup
|
||||
OxStd
|
||||
)
|
||||
|
22
deps/gbastartup/cstartup.cpp
vendored
22
deps/gbastartup/cstartup.cpp
vendored
@ -6,17 +6,33 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/heapmgr.hpp>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
|
||||
// this warning is too dumb to realize that it can actually confirm the hard
|
||||
// coded address aligns with the requirement of HeapSegment, so it must be
|
||||
// suppressed
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
|
||||
#define MEM_WRAM_BEGIN reinterpret_cast<uint8_t*>(0x02000000)
|
||||
#define MEM_WRAM_END reinterpret_cast<uint8_t*>(0x0203FFFF)
|
||||
|
||||
#define HEAP_BEGIN reinterpret_cast<ox::heapmgr::HeapSegment*>(MEM_WRAM_BEGIN)
|
||||
// set size to half of WRAM
|
||||
#define HEAP_SIZE ((MEM_WRAM_END - MEM_WRAM_BEGIN) / 2)
|
||||
#define HEAP_END reinterpret_cast<ox::heapmgr::HeapSegment*>(MEM_WRAM_BEGIN + HEAP_SIZE)
|
||||
|
||||
extern void (*__preinit_array_start[]) (void);
|
||||
extern void (*__preinit_array_end[]) (void);
|
||||
extern void (*__init_array_start[]) (void);
|
||||
extern void (*__init_array_end[]) (void);
|
||||
|
||||
namespace nostalgia::core {
|
||||
namespace ox::heapmgr {
|
||||
|
||||
void initHeap();
|
||||
void initHeap(char *heapBegin, char *heapEnd);
|
||||
|
||||
}
|
||||
|
||||
@ -38,7 +54,7 @@ int main(int argc, const char **argv);
|
||||
|
||||
int c_start() {
|
||||
const char *args[2] = {"", "rom.oxfs"};
|
||||
nostalgia::core::initHeap();
|
||||
ox::heapmgr::initHeap(ox::bit_cast<char*>(HEAP_BEGIN), ox::bit_cast<char*>(HEAP_END));
|
||||
return main(2, args);
|
||||
}
|
||||
|
||||
|
2
deps/ox/src/ox/CMakeLists.txt
vendored
2
deps/ox/src/ox/CMakeLists.txt
vendored
@ -1,5 +1,7 @@
|
||||
if(${OX_USE_STDLIB})
|
||||
add_subdirectory(clargs)
|
||||
add_subdirectory(claw)
|
||||
add_subdirectory(oc)
|
||||
endif()
|
||||
add_subdirectory(fs)
|
||||
add_subdirectory(mc)
|
||||
|
14
deps/ox/src/ox/claw/CMakeLists.txt
vendored
Normal file
14
deps/ox/src/ox/claw/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
add_library(
|
||||
OxClaw
|
||||
read.cpp
|
||||
write.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
OxClaw
|
||||
OxMetalClaw
|
||||
OxOrganicClaw
|
||||
)
|
||||
|
||||
add_subdirectory(test)
|
12
deps/ox/src/ox/claw/claw.hpp
vendored
Normal file
12
deps/ox/src/ox/claw/claw.hpp
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "read.hpp"
|
||||
#include "write.hpp"
|
19
deps/ox/src/ox/claw/format.hpp
vendored
Normal file
19
deps/ox/src/ox/claw/format.hpp
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ox {
|
||||
|
||||
enum class ClawFormat: int {
|
||||
None,
|
||||
Metal,
|
||||
Organic,
|
||||
};
|
||||
|
||||
}
|
68
deps/ox/src/ox/claw/read.cpp
vendored
Normal file
68
deps/ox/src/ox/claw/read.cpp
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "read.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
ValErr<ClawHeader> readHeader(const char *buff, std::size_t buffLen) noexcept {
|
||||
const auto s1End = ox_strchr(buff, ';', buffLen);
|
||||
if (!s1End) {
|
||||
return OxError(1);
|
||||
}
|
||||
const auto s1Size = s1End - buff;
|
||||
String fmt(buff, s1Size);
|
||||
buff += s1Size + 1;
|
||||
buffLen -= s1Size + 1;
|
||||
|
||||
const auto s2End = ox_strchr(buff, ';', buffLen);
|
||||
if (!s2End) {
|
||||
return OxError(1);
|
||||
}
|
||||
const auto s2Size = s2End - buff;
|
||||
String typeName(buff, s2Size);
|
||||
buff += s2Size + 1;
|
||||
buffLen -= s2Size + 1;
|
||||
|
||||
const auto s3End = ox_strchr(buff, ';', buffLen);
|
||||
if (!s3End) {
|
||||
return OxError(1);
|
||||
}
|
||||
const auto s3Size = s3End - buff;
|
||||
String versionStr(buff, s3Size);
|
||||
buff += s3Size + 1;
|
||||
buffLen -= s3Size + 1;
|
||||
|
||||
ClawHeader hdr;
|
||||
if (fmt == "M1") {
|
||||
hdr.fmt = ClawFormat::Metal;
|
||||
} else if (fmt == "O1") {
|
||||
hdr.fmt = ClawFormat::Organic;
|
||||
} else {
|
||||
return OxError(1);
|
||||
}
|
||||
hdr.typeName = typeName;
|
||||
hdr.typeVersion = ox_atoi(versionStr.c_str());
|
||||
hdr.data = buff;
|
||||
hdr.dataSize = buffLen;
|
||||
return hdr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ValErr<Vector<char>> stripClawHeader(const char *buff, std::size_t buffLen) noexcept {
|
||||
auto header = detail::readHeader(buff, buffLen);
|
||||
oxReturnError(header);
|
||||
Vector<char> out(header.value.dataSize);
|
||||
ox_memcpy(out.data(), header.value.data, out.size());
|
||||
return ox::move(out);
|
||||
}
|
||||
|
||||
}
|
57
deps/ox/src/ox/claw/read.hpp
vendored
Normal file
57
deps/ox/src/ox/claw/read.hpp
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/mc/read.hpp>
|
||||
#include <ox/oc/read.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "format.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct ClawHeader {
|
||||
String typeName;
|
||||
int typeVersion = -1;
|
||||
ClawFormat fmt = ClawFormat::None;
|
||||
const char *data = nullptr;
|
||||
std::size_t dataSize = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] ValErr<ClawHeader> readHeader(const char *buff, std::size_t buffLen) noexcept;
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] ValErr<Vector<char>> stripClawHeader(const char *buff, std::size_t buffLen) noexcept;
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error readClaw(char *buff, std::size_t buffLen, T *val) {
|
||||
auto header = detail::readHeader(buff, buffLen);
|
||||
oxReturnError(header);
|
||||
switch (header.value.fmt) {
|
||||
case ClawFormat::Metal:
|
||||
{
|
||||
MetalClawReader reader(bit_cast<uint8_t*>(header.value.data), buffLen);
|
||||
return model(&reader, val);
|
||||
}
|
||||
case ClawFormat::Organic:
|
||||
{
|
||||
OrganicClawReader reader(bit_cast<uint8_t*>(header.value.data), buffLen);
|
||||
return model(&reader, val);
|
||||
}
|
||||
case ClawFormat::None:
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
}
|
14
deps/ox/src/ox/claw/test/CMakeLists.txt
vendored
Normal file
14
deps/ox/src/ox/claw/test/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
add_executable(
|
||||
ClawTest
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
ClawTest
|
||||
OxClaw
|
||||
)
|
||||
|
||||
add_test("Test\\ ClawTest\\ ClawHeaderReader" ClawTest ClawHeaderReader)
|
||||
add_test("Test\\ ClawTest\\ ClawHeaderReader2" ClawTest ClawHeaderReader2)
|
||||
add_test("Test\\ ClawTest\\ ClawWriter" ClawTest ClawWriter)
|
||||
add_test("Test\\ ClawTest\\ ClawReader" ClawTest ClawReader)
|
206
deps/ox/src/ox/claw/test/tests.cpp
vendored
Normal file
206
deps/ox/src/ox/claw/test/tests.cpp
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ox/claw/format.hpp>
|
||||
#include <ox/claw/read.hpp>
|
||||
#include <ox/claw/write.hpp>
|
||||
#include <ox/mc/mc.hpp>
|
||||
#include <ox/model/model.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
union TestUnion {
|
||||
static constexpr auto TypeName = "TestUnion";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool;
|
||||
uint32_t Int = 5;
|
||||
char String[32];
|
||||
};
|
||||
|
||||
struct TestStructNest {
|
||||
static constexpr auto TypeName = "TestStructNest";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool = false;
|
||||
uint32_t Int = 0;
|
||||
ox::BString<32> String = "";
|
||||
};
|
||||
|
||||
struct TestStruct {
|
||||
static constexpr auto TypeName = "TestStruct";
|
||||
static constexpr auto Fields = 16;
|
||||
bool Bool = false;
|
||||
int32_t Int = 0;
|
||||
int32_t Int1 = 0;
|
||||
int32_t Int2 = 0;
|
||||
int32_t Int3 = 0;
|
||||
int32_t Int4 = 0;
|
||||
int32_t Int5 = 0;
|
||||
int32_t Int6 = 0;
|
||||
int32_t Int7 = 0;
|
||||
int32_t Int8 = 0;
|
||||
TestUnion Union;
|
||||
char *CString = nullptr;
|
||||
ox::BString<32> String = "";
|
||||
uint32_t List[4] = {0, 0, 0, 0};
|
||||
TestStructNest EmptyStruct;
|
||||
TestStructNest Struct;
|
||||
|
||||
~TestStruct() {
|
||||
delete[] CString;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestUnion *obj) {
|
||||
io->template setTypeInfo<TestUnion>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", ox::SerStr(obj->String)));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStructNest *obj) {
|
||||
io->template setTypeInfo<TestStructNest>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStruct *obj) {
|
||||
io->template setTypeInfo<TestStruct>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("Int1", &obj->Int1));
|
||||
oxReturnError(io->field("Int2", &obj->Int2));
|
||||
oxReturnError(io->field("Int3", &obj->Int3));
|
||||
oxReturnError(io->field("Int4", &obj->Int4));
|
||||
oxReturnError(io->field("Int5", &obj->Int5));
|
||||
oxReturnError(io->field("Int6", &obj->Int6));
|
||||
oxReturnError(io->field("Int7", &obj->Int7));
|
||||
oxReturnError(io->field("Int8", &obj->Int8));
|
||||
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
|
||||
oxReturnError(io->field("CString", ox::SerStr(&obj->CString)));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
oxReturnError(io->field("List", obj->List, 4));
|
||||
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
|
||||
oxReturnError(io->field("Struct", &obj->Struct));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
std::map<std::string, ox::Error(*)()> tests = {
|
||||
{
|
||||
{
|
||||
"ClawHeaderReader",
|
||||
[] {
|
||||
ox::String hdr = "O1;com.drinkingtea.ox.claw.test.Header;2;";
|
||||
auto [ch, err] = ox::detail::readHeader(hdr.c_str(), hdr.len() + 1);
|
||||
oxAssert(err, "Error parsing header");
|
||||
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
|
||||
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong");
|
||||
oxAssert(ch.typeVersion == 2, "Type version wrong");
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"ClawHeaderReader2",
|
||||
[] {
|
||||
ox::String hdr = "M1;com.drinkingtea.ox.claw.test.Header2;3;";
|
||||
auto [ch, err] = ox::detail::readHeader(hdr.c_str(), hdr.len() + 1);
|
||||
oxAssert(err, "Error parsing header");
|
||||
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
|
||||
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong");
|
||||
oxAssert(ch.typeVersion == 3, "Type version wrong");
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"ClawWriter",
|
||||
[] {
|
||||
// This test doesn't confirm much, but it does show that the writer
|
||||
// doesn't segfault
|
||||
TestStruct ts;
|
||||
oxReturnError(ox::writeClaw(&ts, ox::ClawFormat::Metal));
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"ClawReader",
|
||||
[] {
|
||||
TestStruct testIn, testOut;
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.Union.Int = 42;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.CString = new char[ox_strlen("c-string") + 1];
|
||||
ox_strcpy(testIn.CString, "c-string");
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal);
|
||||
oxAssert(err, "writeMC failed");
|
||||
oxAssert(ox::readClaw(buff.data(), buff.size(), &testOut), "writeMC failed");
|
||||
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
|
||||
|
||||
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
||||
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
||||
oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch");
|
||||
oxAssert(testIn.Int2 == testOut.Int2, "Int2 value mismatch");
|
||||
oxAssert(testIn.Int3 == testOut.Int3, "Int3 value mismatch");
|
||||
oxAssert(testIn.Int4 == testOut.Int4, "Int4 value mismatch");
|
||||
oxAssert(testIn.Int5 == testOut.Int5, "Int5 value mismatch");
|
||||
oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch");
|
||||
oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch");
|
||||
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
|
||||
oxAssert(ox_strcmp(testIn.CString, testOut.CString) == 0, "CString value mismatch");
|
||||
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
|
||||
oxAssert(testIn.String == testOut.String, "String value mismatch");
|
||||
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
|
||||
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
||||
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
||||
oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.String == testOut.EmptyStruct.String, "EmptyStruct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch");
|
||||
oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch");
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 0) {
|
||||
auto testName = args[1];
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName]();
|
||||
} else {
|
||||
retval = 1;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
23
deps/ox/src/ox/claw/write.cpp
vendored
Normal file
23
deps/ox/src/ox/claw/write.cpp
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "write.hpp"
|
||||
|
||||
namespace ox::detail {
|
||||
|
||||
struct versioned_type {
|
||||
static constexpr int TypeVersion = 4;
|
||||
};
|
||||
|
||||
struct unversioned_type {
|
||||
};
|
||||
|
||||
static_assert(type_version<versioned_type>::value == 4);
|
||||
static_assert(type_version<unversioned_type>::value == -1);
|
||||
|
||||
}
|
104
deps/ox/src/ox/claw/write.hpp
vendored
Normal file
104
deps/ox/src/ox/claw/write.hpp
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/mc/write.hpp>
|
||||
#include <ox/oc/write.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "format.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct TypeInfoCatcher {
|
||||
|
||||
const char *name = nullptr;
|
||||
|
||||
template<typename T = void>
|
||||
constexpr void setTypeInfo(const char *name = T::TypeName, int = T::Fields) noexcept {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
constexpr ox::Error field(...) noexcept {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::Write;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr int getTypeVersion(int version = T::TypeVersion) noexcept {
|
||||
return version;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr int getTypeVersion(...) noexcept {
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<typename T, typename = int>
|
||||
struct type_version {
|
||||
static constexpr auto value = -1;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct type_version<T, decltype((void) T::TypeVersion, -1)> {
|
||||
static constexpr auto value = T::TypeVersion;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr const char *getTypeName(T *t) noexcept {
|
||||
TypeInfoCatcher tnc;
|
||||
model(&tnc, t);
|
||||
return tnc.name;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<String> writeClawHeader(T *t, ClawFormat fmt) noexcept {
|
||||
String out;
|
||||
switch (fmt) {
|
||||
case ClawFormat::Metal:
|
||||
out += "M1;";
|
||||
break;
|
||||
case ClawFormat::Organic:
|
||||
out += "O1;";
|
||||
break;
|
||||
default:
|
||||
return OxError(1);
|
||||
}
|
||||
out += detail::getTypeName(t);
|
||||
out += ";";
|
||||
const auto tn = detail::type_version<T>::value;
|
||||
if (tn > -1) {
|
||||
out += tn;
|
||||
}
|
||||
out += ";";
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<Vector<char>> writeClaw(T *t, ClawFormat fmt) {
|
||||
auto [header, headerErr] = detail::writeClawHeader(t, fmt);
|
||||
oxReturnError(headerErr);
|
||||
const auto [data, dataErr] = fmt == ClawFormat::Metal ? writeMC(t) : writeOC(t);
|
||||
oxReturnError(dataErr);
|
||||
ox::Vector<char> out(header.len() + data.size());
|
||||
memcpy(out.data(), header.data(), header.len());
|
||||
memcpy(out.data() + header.len(), data.data(), data.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
11
deps/ox/src/ox/fs/CMakeLists.txt
vendored
11
deps/ox/src/ox/fs/CMakeLists.txt
vendored
@ -10,11 +10,12 @@ add_library(
|
||||
)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
target_link_libraries(
|
||||
OxFS PUBLIC
|
||||
$<$<CXX_COMPILER_ID:Clang>:c++fs>
|
||||
$<$<CXX_COMPILER_ID:GNU>:stdc++fs>
|
||||
)
|
||||
if(NOT APPLE)
|
||||
target_link_libraries(
|
||||
OxFS PUBLIC
|
||||
stdc++fs
|
||||
)
|
||||
endif()
|
||||
set_property(
|
||||
TARGET
|
||||
OxFS
|
||||
|
6
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
6
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
@ -13,6 +13,8 @@
|
||||
#include <ox/ptrarith/nodebuffer.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename InodeId_t>
|
||||
@ -131,7 +133,7 @@ template<typename FileStore, typename InodeId_t>
|
||||
ox::Error Directory<FileStore, InodeId_t>::init() noexcept {
|
||||
constexpr auto Size = sizeof(Buffer);
|
||||
oxTrace("ox::fs::Directory::init") << "Initializing Directory with Inode ID:" << m_inodeId;
|
||||
oxReturnError(m_fs.write(m_inodeId, nullptr, Size));
|
||||
oxReturnError(m_fs.write(m_inodeId, nullptr, Size, FileType_Directory));
|
||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||
if (!buff.valid()) {
|
||||
m_size = 0;
|
||||
@ -254,7 +256,7 @@ ox::Error Directory<FileStore, InodeId_t>::write(PathIterator path, InodeId_t in
|
||||
oxTrace("ox::fs::Directory::write") << "Attempting to write Directory entry:" << name->data();
|
||||
oxTrace("ox::fs::Directory::write") << "Attempting to write Directory to FileStore";
|
||||
oxReturnError(val->init(inode, name->data(), val.size()));
|
||||
return m_fs.write(m_inodeId, cpy, cpy->size());
|
||||
return m_fs.write(m_inodeId, cpy, cpy->size(), FileType_Directory);
|
||||
}
|
||||
}
|
||||
|
||||
|
72
deps/ox/src/ox/fs/filesystem/filelocation.hpp
vendored
72
deps/ox/src/ox/fs/filesystem/filelocation.hpp
vendored
@ -23,21 +23,23 @@ enum class FileAddressType: int8_t {
|
||||
class FileAddress {
|
||||
|
||||
template<typename T>
|
||||
friend ox::Error modelRead(T*, FileAddress*);
|
||||
|
||||
template<typename T>
|
||||
friend ox::Error modelWrite(T*, FileAddress*);
|
||||
friend ox::Error model(T*, FileAddress*);
|
||||
|
||||
public:
|
||||
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
|
||||
static constexpr auto Fields = 2;
|
||||
|
||||
protected:
|
||||
FileAddressType m_type = FileAddressType::None;
|
||||
union {
|
||||
union Data {
|
||||
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress.Data";
|
||||
static constexpr auto Fields = 3;
|
||||
char *path;
|
||||
const char *constPath;
|
||||
uint64_t inode;
|
||||
} m_data;
|
||||
};
|
||||
|
||||
protected:
|
||||
FileAddressType m_type = FileAddressType::None;
|
||||
Data m_data;
|
||||
|
||||
public:
|
||||
FileAddress();
|
||||
@ -93,55 +95,19 @@ class FileAddress {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error modelRead(T *io, FileAddress *fa) {
|
||||
io->setTypeInfo("ox::FileAddress", FileAddress::Fields);
|
||||
decltype(fa->m_data.inode) inode = 0;
|
||||
const auto strSize = io->stringLength() + 1;
|
||||
auto path = new char[strSize];
|
||||
oxReturnError(io->field("path", SerStr(path, strSize - 1)));
|
||||
oxReturnError(io->field("inode", &inode));
|
||||
if (strSize) {
|
||||
fa->m_data.path = path;
|
||||
fa->m_type = FileAddressType::Path;
|
||||
} else {
|
||||
fa->m_data.inode = inode;
|
||||
fa->m_type = FileAddressType::Inode;
|
||||
delete[] path;
|
||||
}
|
||||
ox::Error model(T *io, FileAddress::Data *obj) {
|
||||
io->template setTypeInfo<FileAddress::Data>();
|
||||
oxReturnError(io->field("path", SerStr(&obj->path)));
|
||||
oxReturnError(io->field("constPath", SerStr(&obj->path)));
|
||||
oxReturnError(io->field("inode", &obj->inode));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error modelWrite(T *io, FileAddress *fa) {
|
||||
io->setTypeInfo("ox::FileAddress", FileAddress::Fields);
|
||||
switch (fa->m_type) {
|
||||
case FileAddressType::Path:
|
||||
case FileAddressType::ConstPath:
|
||||
{
|
||||
decltype(fa->m_data.inode) blank = 0;
|
||||
const auto strSize = ox_strlen(fa->m_data.constPath) + 1;
|
||||
auto path = ox_malloca(strSize, char, 0);
|
||||
memcpy(path.get(), fa->m_data.constPath, strSize);
|
||||
oxReturnError(io->field("path", SerStr(path.get(), strSize - 1)));
|
||||
oxReturnError(io->field("inode", &blank));
|
||||
break;
|
||||
}
|
||||
case FileAddressType::Inode:
|
||||
{
|
||||
char blankPath[1] = "";
|
||||
oxReturnError(io->field("path", SerStr(blankPath, 0)));
|
||||
oxReturnError(io->field("inode", &fa->m_data.inode));
|
||||
break;
|
||||
}
|
||||
case FileAddressType::None:
|
||||
{
|
||||
char blankPath[1] = "";
|
||||
decltype(fa->m_data.inode) blankInode = 0;
|
||||
oxReturnError(io->field("path", SerStr(blankPath, 0)));
|
||||
oxReturnError(io->field("inode", &blankInode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
ox::Error model(T *io, FileAddress *fa) {
|
||||
io->template setTypeInfo<FileAddress>();
|
||||
oxReturnError(io->field("type", bit_cast<int8_t*>(&fa->m_type)));
|
||||
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,11 @@ Error PassThroughFS::mkdir(const char *path, bool recursive) {
|
||||
const auto u8p = p.u8string();
|
||||
oxTrace("ox::fs::PassThroughFS::mkdir") << u8p.c_str();
|
||||
if (recursive) {
|
||||
success = std::filesystem::create_directories(p);
|
||||
if (std::filesystem::is_directory(p)) {
|
||||
success = true;
|
||||
} else {
|
||||
success = std::filesystem::create_directories(p);
|
||||
}
|
||||
} else {
|
||||
success = std::filesystem::create_directory(p);
|
||||
}
|
||||
|
13
deps/ox/src/ox/mc/intops.hpp
vendored
13
deps/ox/src/ox/mc/intops.hpp
vendored
@ -28,7 +28,7 @@ template<typename I>
|
||||
// find most significant non-sign indicator bit
|
||||
std::size_t highestBit = 0;
|
||||
// start at one bit lower if signed
|
||||
if constexpr(ox::is_signed<I>) {
|
||||
if constexpr(ox::is_signed_v<I>) {
|
||||
--shiftStart;
|
||||
}
|
||||
for (int i = shiftStart; i > -1; --i) {
|
||||
@ -65,7 +65,7 @@ template<typename I>
|
||||
if (val) {
|
||||
// bits needed to represent number factoring in space possibly
|
||||
// needed for signed bit
|
||||
const auto bits = highestBit(val) + 1 + (ox::is_signed<I> ? 1 : 0);
|
||||
const auto bits = highestBit(val) + 1 + (ox::is_signed_v<I> ? 1 : 0);
|
||||
// bytes needed to store value
|
||||
std::size_t bytes = bits / 8 + (bits % 8 != 0);
|
||||
const auto bitsAvailable = bytes * 8; // bits available to integer value
|
||||
@ -77,13 +77,6 @@ template<typename I>
|
||||
}
|
||||
const auto bytesIndicator = onMask<uint8_t>(bytes - 1);
|
||||
|
||||
// move sign bit
|
||||
if constexpr(ox::is_signed<I>) {
|
||||
if (val < 0) {
|
||||
val ^= uint64_t(1) << (sizeof(I) * 8 - 1);
|
||||
val |= uint64_t(1) << (bitsAvailable - 1);
|
||||
}
|
||||
}
|
||||
// ensure we are copying from little endian represenstation
|
||||
LittleEndian<I> leVal = val;
|
||||
if (bytes == 9) {
|
||||
@ -135,7 +128,7 @@ template<typename I>
|
||||
decoded >>= bytes;
|
||||
auto out = static_cast<I>(decoded);
|
||||
// move sign bit
|
||||
if constexpr(ox::is_signed<I>) {
|
||||
if constexpr(ox::is_signed_v<I>) {
|
||||
const auto valBits = bytes << 3;
|
||||
// get sign
|
||||
uint64_t sign = decoded >> (valBits - 1);
|
||||
|
1
deps/ox/src/ox/mc/mc.hpp
vendored
1
deps/ox/src/ox/mc/mc.hpp
vendored
@ -11,5 +11,4 @@
|
||||
#include "intops.hpp"
|
||||
#include "read.hpp"
|
||||
#include "types.hpp"
|
||||
#include "walk.hpp"
|
||||
#include "write.hpp"
|
||||
|
2
deps/ox/src/ox/mc/presenceindicator.cpp
vendored
2
deps/ox/src/ox/mc/presenceindicator.cpp
vendored
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
#include "err.hpp"
|
||||
#include "presenceindicator.hpp"
|
||||
|
||||
@ -40,6 +41,7 @@ Error FieldPresenceIndicator::set(std::size_t i, bool on) {
|
||||
|
||||
void FieldPresenceIndicator::setFields(int fields) noexcept {
|
||||
m_fields = fields;
|
||||
m_maskLen = (fields / 8 + 1) - (fields % 8 == 0);
|
||||
}
|
||||
|
||||
int FieldPresenceIndicator::getFields() const noexcept {
|
||||
|
4
deps/ox/src/ox/mc/presenceindicator.hpp
vendored
4
deps/ox/src/ox/mc/presenceindicator.hpp
vendored
@ -22,9 +22,9 @@ class FieldPresenceIndicator {
|
||||
public:
|
||||
FieldPresenceIndicator(uint8_t *mask, std::size_t maxLen);
|
||||
|
||||
ValErr<bool> get(std::size_t i) const;
|
||||
[[nodiscard]] ValErr<bool> get(std::size_t i) const;
|
||||
|
||||
Error set(std::size_t i, bool on);
|
||||
[[nodiscard]] Error set(std::size_t i, bool on);
|
||||
|
||||
void setFields(int) noexcept;
|
||||
|
||||
|
106
deps/ox/src/ox/mc/read.cpp
vendored
106
deps/ox/src/ox/mc/read.cpp
vendored
@ -14,17 +14,21 @@
|
||||
|
||||
namespace ox {
|
||||
|
||||
MetalClawReader::MetalClawReader(uint8_t *buff, std::size_t buffLen, MetalClawReader *parent): m_fieldPresence(buff, buffLen) {
|
||||
m_buff = buff;
|
||||
m_buffLen = buffLen;
|
||||
m_parent = parent;
|
||||
MetalClawReader::MetalClawReader(uint8_t *buff, std::size_t buffLen, int unionIdx, MetalClawReader *parent) noexcept:
|
||||
m_fieldPresence(buff, buffLen),
|
||||
m_unionIdx(unionIdx),
|
||||
m_buffLen(buffLen),
|
||||
m_buff(buff),
|
||||
m_parent(parent) {
|
||||
}
|
||||
|
||||
MetalClawReader::~MetalClawReader() {
|
||||
MetalClawReader::~MetalClawReader() noexcept {
|
||||
if (m_parent) {
|
||||
m_parent->m_buffIt += m_buffIt;
|
||||
}
|
||||
//oxAssert(m_field == m_fields, "MetalClawReader: incorrect fields number given");
|
||||
if (m_field != m_fields) {
|
||||
oxTrace("ox::mc::MetalClawReader::error") << "MetalClawReader: incorrect fields number given";
|
||||
}
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, int8_t *val) {
|
||||
@ -61,41 +65,52 @@ Error MetalClawReader::field(const char*, uint64_t *val) {
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, bool *val) {
|
||||
auto valErr = m_fieldPresence.get(m_field++);
|
||||
*val = valErr.value;
|
||||
return valErr.error;
|
||||
}
|
||||
|
||||
Error MetalClawReader::field(const char*, SerStr val) {
|
||||
if (m_fieldPresence.get(m_field++)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(err);
|
||||
|
||||
// read the string
|
||||
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
|
||||
if (m_buffIt + size <= m_buffLen) {
|
||||
ox_memcpy(val.data(), &m_buff[m_buffIt], size);
|
||||
m_buffIt += size;
|
||||
} else {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
} else {
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
}
|
||||
} else {
|
||||
val.data()[0] = 0;
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
auto valErr = m_fieldPresence.get(m_field);
|
||||
*val = valErr.value;
|
||||
oxReturnError(valErr.error);
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
[[nodiscard]] ValErr<ArrayLength> MetalClawReader::arrayLength(bool pass) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
Error MetalClawReader::field(const char*, SerStr val) {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(err);
|
||||
auto data = val.data(size + 1);
|
||||
// read the string
|
||||
if (val.cap() > -1 && static_cast<StringLength>(val.cap()) >= size) {
|
||||
if (m_buffIt + size <= m_buffLen) {
|
||||
ox_memcpy(data, &m_buff[m_buffIt], size);
|
||||
data[size] = 0;
|
||||
m_buffIt += size;
|
||||
} else {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
} else {
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
}
|
||||
} else {
|
||||
auto data = val.data();
|
||||
if (data) {
|
||||
data[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
[[nodiscard]] ValErr<ArrayLength> MetalClawReader::arrayLength(const char*, bool pass) {
|
||||
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
@ -110,8 +125,8 @@ Error MetalClawReader::field(const char*, SerStr val) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
[[nodiscard]] StringLength MetalClawReader::stringLength() {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
[[nodiscard]] StringLength MetalClawReader::stringLength(const char*) {
|
||||
if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
@ -120,18 +135,11 @@ Error MetalClawReader::field(const char*, SerStr val) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MetalClawReader::setTypeInfo(const char*, int fields) {
|
||||
m_fields = fields;
|
||||
m_buffIt = (fields / 8 + 1) - (fields % 8 == 0);
|
||||
m_fieldPresence.setFields(fields);
|
||||
m_fieldPresence.setMaxLen(m_buffIt);
|
||||
MetalClawReader MetalClawReader::child(const char*, int unionIdx) {
|
||||
return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this);
|
||||
}
|
||||
|
||||
MetalClawReader MetalClawReader::child() {
|
||||
return MetalClawReader(m_buff + m_buffIt, m_buffLen - m_buffIt, this);
|
||||
}
|
||||
|
||||
bool MetalClawReader::fieldPresent() const {
|
||||
bool MetalClawReader::fieldPresent(const char*) const {
|
||||
return m_fieldPresence.get(m_field).value;
|
||||
}
|
||||
|
||||
|
224
deps/ox/src/ox/mc/read.hpp
vendored
224
deps/ox/src/ox/mc/read.hpp
vendored
@ -28,73 +28,78 @@ class MetalClawReader {
|
||||
FieldPresenceIndicator m_fieldPresence;
|
||||
int m_fields = 0;
|
||||
int m_field = 0;
|
||||
int m_unionIdx = -1;
|
||||
std::size_t m_buffIt = 0;
|
||||
std::size_t m_buffLen = 0;
|
||||
uint8_t *m_buff = nullptr;
|
||||
MetalClawReader *m_parent = nullptr;
|
||||
|
||||
public:
|
||||
MetalClawReader(uint8_t *buff, std::size_t buffLen, MetalClawReader *parent = nullptr);
|
||||
MetalClawReader(uint8_t *buff, std::size_t buffLen, int unionIdx = -1, MetalClawReader *parent = nullptr) noexcept;
|
||||
|
||||
~MetalClawReader();
|
||||
~MetalClawReader() noexcept;
|
||||
|
||||
Error field(const char*, int8_t *val);
|
||||
Error field(const char*, int16_t *val);
|
||||
Error field(const char*, int32_t *val);
|
||||
Error field(const char*, int64_t *val);
|
||||
[[nodiscard]] Error field(const char*, int8_t *val);
|
||||
[[nodiscard]] Error field(const char*, int16_t *val);
|
||||
[[nodiscard]] Error field(const char*, int32_t *val);
|
||||
[[nodiscard]] Error field(const char*, int64_t *val);
|
||||
|
||||
Error field(const char*, uint8_t *val);
|
||||
Error field(const char*, uint16_t *val);
|
||||
Error field(const char*, uint32_t *val);
|
||||
Error field(const char*, uint64_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint8_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint16_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint32_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint64_t *val);
|
||||
|
||||
Error field(const char*, bool *val);
|
||||
[[nodiscard]] Error field(const char*, bool *val);
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
Error field(const char*, T *val, std::size_t len);
|
||||
[[nodiscard]] Error field(const char*, T *val, std::size_t len);
|
||||
|
||||
// map handler
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, HashMap<String, T> *val);
|
||||
|
||||
// array handler, with callback to allow handling individual elements
|
||||
template<typename T, typename Handler>
|
||||
Error field(const char*, Handler handler);
|
||||
|
||||
// array handler, with callback to allow handling individual elements
|
||||
template<typename T, typename Handler>
|
||||
Error field(const char*, Handler handler, ArrayLength len);
|
||||
[[nodiscard]] Error field(const char*, Handler handler);
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, ox::Vector<T> *val);
|
||||
[[nodiscard]] Error field(const char*, ox::Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, T *val);
|
||||
[[nodiscard]] Error field(const char*, T *val);
|
||||
|
||||
template<typename U>
|
||||
[[nodiscard]] Error field(const char*, UnionView<U> val);
|
||||
|
||||
template<std::size_t L>
|
||||
Error field(const char*, ox::BString<L> *val);
|
||||
[[nodiscard]] Error field(const char*, ox::BString<L> *val);
|
||||
|
||||
Error field(const char*, SerStr val);
|
||||
[[nodiscard]] Error field(const char*, SerStr val);
|
||||
|
||||
/**
|
||||
* Reads an array length from the current location in the buffer.
|
||||
* @param pass indicates that the parsing should iterate past the array length
|
||||
*/
|
||||
[[nodiscard]] ValErr<ArrayLength> arrayLength(bool pass = true);
|
||||
[[nodiscard]] ValErr<ArrayLength> arrayLength(const char *name, bool pass = true);
|
||||
|
||||
/**
|
||||
* Reads an string length from the current location in the buffer.
|
||||
*/
|
||||
[[nodiscard]] StringLength stringLength();
|
||||
[[nodiscard]] StringLength stringLength(const char *name);
|
||||
|
||||
void setTypeInfo(const char *name, int fields);
|
||||
template<typename T = std::nullptr_t>
|
||||
void setTypeInfo(const char *name = T::TypeName, int fields = T::Fields);
|
||||
|
||||
/**
|
||||
* Returns a MetalClawReader to parse a child object.
|
||||
*/
|
||||
[[nodiscard]] MetalClawReader child();
|
||||
[[nodiscard]] MetalClawReader child(const char *name, int unionIdx = -1);
|
||||
|
||||
/**
|
||||
* Indicates whether or not the next field to be read is present.
|
||||
*/
|
||||
bool fieldPresent() const;
|
||||
bool fieldPresent(const char *name) const;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the given field is present.
|
||||
@ -103,22 +108,33 @@ class MetalClawReader {
|
||||
|
||||
void nextField() noexcept;
|
||||
|
||||
static constexpr OpType opType() {
|
||||
static constexpr auto opType() {
|
||||
return OpType::Read;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename I>
|
||||
Error readInteger(I *val);
|
||||
[[nodiscard]] Error readInteger(I *val);
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char*, T *val) {
|
||||
if (val && m_fieldPresence.get(m_field++)) {
|
||||
auto reader = child();
|
||||
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val && m_fieldPresence.get(m_field)) {
|
||||
auto reader = child("");
|
||||
oxReturnError(model(&reader, val));
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Error MetalClawReader::field(const char*, UnionView<U> val) {
|
||||
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get() && m_fieldPresence.get(m_field)) {
|
||||
auto reader = child("", val.idx());
|
||||
oxReturnError(model(&reader, val.get()));
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
@ -129,85 +145,133 @@ Error MetalClawReader::field(const char *name, ox::BString<L> *val) {
|
||||
|
||||
template<typename I>
|
||||
Error MetalClawReader::readInteger(I *val) {
|
||||
if (m_fieldPresence.get(m_field++)) {
|
||||
std::size_t bytesRead = 0;
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
oxTrace("ox::MetalClaw::readInteger") << "Buffer ended";
|
||||
return OxError(MC_BUFFENDED);
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
std::size_t bytesRead = 0;
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
oxTrace("ox::MetalClaw::readInteger") << "Buffer ended";
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
auto valErr = mc::decodeInteger<I>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(valErr.error);
|
||||
*val = valErr.value;
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
auto valErr = mc::decodeInteger<I>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(valErr.error);
|
||||
*val = valErr.value;
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) {
|
||||
if (m_fieldPresence.get(m_field++)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
|
||||
// read the list
|
||||
if (valLen >= len.value) {
|
||||
auto reader = child();
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
oxReturnError(reader.field("", &val[i]));
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
|
||||
// read the list
|
||||
if (valLen >= len.value) {
|
||||
auto reader = child("");
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
oxReturnError(reader.field("", &val[i]));
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
}
|
||||
} else {
|
||||
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
|
||||
return OxError(MC_OUTBUFFENDED);
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char*, HashMap<String, T> *val) {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
|
||||
// read the list
|
||||
auto reader = child("");
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
auto keyLen = reader.stringLength(nullptr);
|
||||
auto wkey = ox_malloca(keyLen + 1, char, 0);
|
||||
oxReturnError(reader.field("", SerStr(wkey.get(), keyLen)));
|
||||
oxReturnError(reader.field("", &val->at(wkey.get())));
|
||||
}
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T, typename Handler>
|
||||
Error MetalClawReader::field(const char*, Handler handler) {
|
||||
if (m_fieldPresence.get(m_field++)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
// read the length
|
||||
if (m_buffIt >= m_buffLen) {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
std::size_t bytesRead = 0;
|
||||
auto len = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
|
||||
m_buffIt += bytesRead;
|
||||
oxReturnError(len.error);
|
||||
|
||||
// read the list
|
||||
auto reader = child();
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
T val;
|
||||
oxReturnError(reader.field("", &val));
|
||||
oxReturnError(handler(i, &val));
|
||||
// read the list
|
||||
auto reader = child("");
|
||||
reader.setTypeInfo("List", len.value);
|
||||
for (std::size_t i = 0; i < len.value; i++) {
|
||||
T val;
|
||||
oxReturnError(reader.field("", &val));
|
||||
oxReturnError(handler(i, &val));
|
||||
}
|
||||
}
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawReader::field(const char* name, ox::Vector<T> *val) {
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
const auto [len, err] = arrayLength(false);
|
||||
oxReturnError(err);
|
||||
val->resize(len);
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
// set size of val if the field is present, don't worry about it if not
|
||||
if (m_fieldPresence.get(m_field)) {
|
||||
const auto [len, err] = arrayLength(name, false);
|
||||
oxReturnError(err);
|
||||
val->resize(len);
|
||||
}
|
||||
return field(name, val->data(), val->size());
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MetalClawReader::setTypeInfo(const char*, int fields) {
|
||||
m_fields = fields;
|
||||
m_buffIt = (fields / 8 + 1) - (fields % 8 == 0);
|
||||
m_fieldPresence.setFields(fields);
|
||||
m_fieldPresence.setMaxLen(m_buffIt);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error readMC(uint8_t *buff, std::size_t buffLen, T *val) {
|
||||
MetalClawReader reader(buff, buffLen);
|
||||
|
117
deps/ox/src/ox/mc/test/tests.cpp
vendored
117
deps/ox/src/ox/mc/test/tests.cpp
vendored
@ -6,6 +6,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "ox/std/hashmap.hpp"
|
||||
#undef NDEBUG
|
||||
|
||||
#include <assert.h>
|
||||
@ -18,13 +19,25 @@
|
||||
#include <ox/model/model.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
union TestUnion {
|
||||
static constexpr auto TypeName = "TestUnion";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool;
|
||||
uint32_t Int = 5;
|
||||
char String[32];
|
||||
};
|
||||
|
||||
struct TestStructNest {
|
||||
static constexpr auto TypeName = "TestStructNest";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool = false;
|
||||
uint32_t Int = 0;
|
||||
ox::BString<32> String = "";
|
||||
};
|
||||
|
||||
struct TestStruct {
|
||||
static constexpr auto TypeName = "TestStruct";
|
||||
static constexpr auto Fields = 17;
|
||||
bool Bool = false;
|
||||
int32_t Int = 0;
|
||||
int32_t Int1 = 0;
|
||||
@ -35,41 +48,59 @@ struct TestStruct {
|
||||
int32_t Int6 = 0;
|
||||
int32_t Int7 = 0;
|
||||
int32_t Int8 = 0;
|
||||
TestUnion Union;
|
||||
char *CString = nullptr;
|
||||
ox::BString<32> String = "";
|
||||
uint32_t List[4] = {0, 0, 0 , 0};
|
||||
uint32_t List[4] = {0, 0, 0, 0};
|
||||
ox::HashMap<ox::String, int> Map;
|
||||
TestStructNest EmptyStruct;
|
||||
TestStructNest Struct;
|
||||
|
||||
~TestStruct() {
|
||||
delete[] CString;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestUnion *obj) {
|
||||
io->template setTypeInfo<TestUnion>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", ox::SerStr(obj->String)));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStructNest *obj) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("TestStructNest", 3);
|
||||
err |= io->field("Bool", &obj->Bool);
|
||||
err |= io->field("Int", &obj->Int);
|
||||
err |= io->field("String", &obj->String);
|
||||
return err;
|
||||
io->template setTypeInfo<TestStructNest>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStruct *obj) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("TestStruct", 14);
|
||||
err |= io->field("Bool", &obj->Bool);
|
||||
err |= io->field("Int", &obj->Int);
|
||||
err |= io->field("Int1", &obj->Int1);
|
||||
err |= io->field("Int2", &obj->Int2);
|
||||
err |= io->field("Int3", &obj->Int3);
|
||||
err |= io->field("Int4", &obj->Int4);
|
||||
err |= io->field("Int5", &obj->Int5);
|
||||
err |= io->field("Int6", &obj->Int6);
|
||||
err |= io->field("Int7", &obj->Int7);
|
||||
err |= io->field("Int8", &obj->Int8);
|
||||
err |= io->field("String", &obj->String);
|
||||
err |= io->field("List", obj->List, 4);
|
||||
err |= io->field("EmptyStruct", &obj->EmptyStruct);
|
||||
err |= io->field("Struct", &obj->Struct);
|
||||
return err;
|
||||
io->template setTypeInfo<TestStruct>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("Int1", &obj->Int1));
|
||||
oxReturnError(io->field("Int2", &obj->Int2));
|
||||
oxReturnError(io->field("Int3", &obj->Int3));
|
||||
oxReturnError(io->field("Int4", &obj->Int4));
|
||||
oxReturnError(io->field("Int5", &obj->Int5));
|
||||
oxReturnError(io->field("Int6", &obj->Int6));
|
||||
oxReturnError(io->field("Int7", &obj->Int7));
|
||||
oxReturnError(io->field("Int8", &obj->Int8));
|
||||
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
|
||||
oxReturnError(io->field("CString", ox::SerStr(&obj->CString)));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
oxReturnError(io->field("List", obj->List, 4));
|
||||
oxReturnError(io->field("Map", &obj->Map));
|
||||
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
|
||||
oxReturnError(io->field("Struct", &obj->Struct));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
std::map<std::string, ox::Error(*)()> tests = {
|
||||
@ -81,12 +112,11 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
// doesn't segfault
|
||||
constexpr size_t buffLen = 1024;
|
||||
uint8_t buff[buffLen];
|
||||
auto err = ox::Error(0);
|
||||
TestStruct ts;
|
||||
|
||||
err |= ox::writeMC(buff, buffLen, &ts);
|
||||
oxReturnError(ox::writeMC(buff, buffLen, &ts));
|
||||
|
||||
return err;
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -98,18 +128,23 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.Union.Int = 42;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.CString = new char[ox_strlen("c-string") + 1];
|
||||
ox_strcpy(testIn.CString, "c-string");
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Map["asdf"] = 93;
|
||||
testIn.Map["aoeu"] = 94;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed");
|
||||
oxAssert(ox::readMC(buff, buffLen, &testOut), "writeMC failed");
|
||||
std::cout << testIn.Int << " " << testOut.Int << '\n';
|
||||
oxAssert(ox::readMC(buff, buffLen, &testOut), "readMC failed");
|
||||
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
|
||||
|
||||
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
|
||||
oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
|
||||
@ -121,11 +156,15 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch");
|
||||
oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch");
|
||||
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
|
||||
oxAssert(ox_strcmp(testIn.CString, testOut.CString) == 0, "CString value mismatch");
|
||||
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
|
||||
oxAssert(testIn.String == testOut.String, "String value mismatch");
|
||||
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
|
||||
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
|
||||
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
|
||||
oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch");
|
||||
oxAssert(testIn.Map["asdf"] == testOut.Map["asdf"], "Map[\"asdf\"] value mismatch");
|
||||
oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.String == testOut.EmptyStruct.String, "EmptyStruct.String value mismatch");
|
||||
@ -217,10 +256,12 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
oxReturnError(result.error);
|
||||
if (result.value != val) {
|
||||
std::cout << "Bad value: " << result.value << ", expected: " << val << '\n';
|
||||
return OxError(1);
|
||||
}
|
||||
return OxError(result.value != val);
|
||||
return OxError(0);
|
||||
};
|
||||
oxAssert(check(uint32_t(14)), "Decode of 14 failed.");
|
||||
oxAssert(check(int64_t(-1)), "Decode of -1 failed.");
|
||||
oxAssert(check(int64_t(1)), "Decode of 1 failed.");
|
||||
oxAssert(check(int64_t(2)), "Decode of 2 failed.");
|
||||
oxAssert(check(int64_t(42)), "Decode of 42 failed.");
|
||||
@ -241,7 +282,6 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
{
|
||||
"MetalClawDef",
|
||||
[] {
|
||||
auto err = OxError(0);
|
||||
//constexpr size_t descBuffLen = 1024;
|
||||
//uint8_t descBuff[descBuffLen];
|
||||
constexpr size_t dataBuffLen = 1024;
|
||||
@ -260,9 +300,9 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed");
|
||||
auto type = ox::buildMCDef(&testIn);
|
||||
auto type = ox::buildTypeDef(&testIn);
|
||||
oxAssert(type.error, "Descriptor write failed");
|
||||
ox::walkMC<ox::MetalClawReader>(type.value, dataBuff, dataBuffLen,
|
||||
ox::walkModel<ox::MetalClawReader>(type.value, dataBuff, dataBuffLen,
|
||||
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
|
||||
//std::cout << f.fieldName.c_str() << '\n';
|
||||
auto fieldName = f.fieldName.c_str();
|
||||
@ -330,25 +370,26 @@ std::map<std::string, ox::Error(*)()> tests = {
|
||||
case ox::PrimitiveType::Bool: {
|
||||
bool i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "bool:\t" << (i ? "true" : "false") << '\n';
|
||||
std::cout << fieldName << ":\t" << "bool:\t\t" << (i ? "true" : "false") << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::String: {
|
||||
ox::Vector<char> v(rdr->stringLength());
|
||||
ox::Vector<char> v(rdr->stringLength(fieldName) + 1);
|
||||
//std::cout << rdr->stringLength() << '\n';
|
||||
oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "string: " << v.data() << '\n';
|
||||
std::cout << fieldName << ":\t" << "string:\t\t" << v.data() << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::Struct:
|
||||
break;
|
||||
case ox::PrimitiveType::Union:
|
||||
break;
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
);
|
||||
delete type.value;
|
||||
|
||||
return err;
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
22
deps/ox/src/ox/mc/walk.hpp
vendored
22
deps/ox/src/ox/mc/walk.hpp
vendored
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/model/walk.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
template<typename Reader, typename Handler>
|
||||
ox::Error walkMC(DescriptorType *type, uint8_t *data, std::size_t dataLen, Handler handler) {
|
||||
DataWalker<Reader, Handler> walker(type, handler);
|
||||
Reader rdr(data, dataLen);
|
||||
return model(&rdr, &walker);
|
||||
}
|
||||
|
||||
}
|
68
deps/ox/src/ox/mc/write.cpp
vendored
68
deps/ox/src/ox/mc/write.cpp
vendored
@ -9,88 +9,88 @@
|
||||
#include <ox/std/assert.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
|
||||
#include "write.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen): m_fieldPresence(buff, buffLen) {
|
||||
m_buff = buff;
|
||||
m_buffLen = buffLen;
|
||||
MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
|
||||
m_fieldPresence(buff, buffLen),
|
||||
m_unionIdx(unionIdx),
|
||||
m_buffLen(buffLen),
|
||||
m_buff(buff) {
|
||||
}
|
||||
|
||||
MetalClawWriter::~MetalClawWriter() noexcept {
|
||||
oxAssert(m_field == m_fields, "MetalClawWriter: incorrect fields number given");
|
||||
if (m_field != m_fields) {
|
||||
oxTrace("ox::mc::MetalClawWriter::error") << "MetalClawReader: incorrect fields number given";
|
||||
}
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int8_t *val) {
|
||||
Error MetalClawWriter::field(const char*, int8_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int16_t *val) {
|
||||
Error MetalClawWriter::field(const char*, int16_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int32_t *val) {
|
||||
Error MetalClawWriter::field(const char*, int32_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, int64_t *val) {
|
||||
Error MetalClawWriter::field(const char*, int64_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint8_t *val) {
|
||||
Error MetalClawWriter::field(const char*, uint8_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint16_t *val) {
|
||||
Error MetalClawWriter::field(const char*, uint16_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint32_t *val) {
|
||||
Error MetalClawWriter::field(const char*, uint32_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, uint64_t *val) {
|
||||
Error MetalClawWriter::field(const char*, uint64_t *val) noexcept {
|
||||
return appendInteger(*val);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, bool *val) {
|
||||
return m_fieldPresence.set(m_field++, *val);
|
||||
Error MetalClawWriter::field(const char*, bool *val) noexcept {
|
||||
if (m_unionIdx == -1 || m_unionIdx == m_field) {
|
||||
oxReturnError(m_fieldPresence.set(m_field, *val));
|
||||
}
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error MetalClawWriter::field(const char*, SerStr val) {
|
||||
auto err = OxError(0);
|
||||
Error MetalClawWriter::field(const char*, SerStr val) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (val.cap()) {
|
||||
if (val.len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
const auto strLen = mc::encodeInteger(val.bytes());
|
||||
if (m_buffIt + strLen.length + val.bytes() < m_buffLen) {
|
||||
const auto strLen = mc::encodeInteger(val.len());
|
||||
if (m_buffIt + strLen.length + val.len() < m_buffLen) {
|
||||
ox_memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
|
||||
m_buffIt += strLen.length;
|
||||
|
||||
// write the string
|
||||
ox_memcpy(&m_buff[m_buffIt], val.c_str(), val.bytes());
|
||||
m_buffIt += val.bytes();
|
||||
ox_memcpy(&m_buff[m_buffIt], val.c_str(), val.len());
|
||||
m_buffIt += val.len();
|
||||
fieldSet = true;
|
||||
} else {
|
||||
err = OxError(MC_BUFFENDED);
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
}
|
||||
err |= m_fieldPresence.set(m_field, fieldSet);
|
||||
m_field++;
|
||||
return err;
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
++m_field;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
void MetalClawWriter::setTypeInfo(const char*, int fields) {
|
||||
m_fields = fields;
|
||||
m_buffIt = (fields / 8 + 1) - (fields % 8 == 0);
|
||||
m_fieldPresence.setFields(fields);
|
||||
m_fieldPresence.setMaxLen(m_buffIt);
|
||||
}
|
||||
|
||||
std::size_t MetalClawWriter::size() {
|
||||
std::size_t MetalClawWriter::size() noexcept {
|
||||
return m_buffIt;
|
||||
}
|
||||
|
||||
|
154
deps/ox/src/ox/mc/write.hpp
vendored
154
deps/ox/src/ox/mc/write.hpp
vendored
@ -14,10 +14,12 @@
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/units.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "intops.hpp"
|
||||
#include "err.hpp"
|
||||
#include "ox/std/hashmap.hpp"
|
||||
#include "presenceindicator.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
@ -29,64 +31,73 @@ class MetalClawWriter {
|
||||
FieldPresenceIndicator m_fieldPresence;
|
||||
int m_fields = 0;
|
||||
int m_field = 0;
|
||||
int m_unionIdx = -1;
|
||||
std::size_t m_buffIt = 0;
|
||||
std::size_t m_buffLen = 0;
|
||||
uint8_t *m_buff = nullptr;
|
||||
|
||||
public:
|
||||
MetalClawWriter(uint8_t *buff, std::size_t buffLen);
|
||||
MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept;
|
||||
|
||||
~MetalClawWriter() noexcept;
|
||||
|
||||
Error field(const char*, int8_t *val);
|
||||
Error field(const char*, int16_t *val);
|
||||
Error field(const char*, int32_t *val);
|
||||
Error field(const char*, int64_t *val);
|
||||
[[nodiscard]] Error field(const char*, int8_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, int16_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, int32_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, int64_t *val) noexcept;
|
||||
|
||||
Error field(const char*, uint8_t *val);
|
||||
Error field(const char*, uint16_t *val);
|
||||
Error field(const char*, uint32_t *val);
|
||||
Error field(const char*, uint64_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint8_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, uint16_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, uint32_t *val) noexcept;
|
||||
[[nodiscard]] Error field(const char*, uint64_t *val) noexcept;
|
||||
|
||||
Error field(const char*, bool *val);
|
||||
[[nodiscard]] Error field(const char*, bool *val) noexcept;
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, T *val, std::size_t len);
|
||||
[[nodiscard]] Error field(const char*, T *val, std::size_t len);
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, ox::Vector<T> *val);
|
||||
[[nodiscard]] Error field(const char*, Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, HashMap<String, T> *val);
|
||||
|
||||
template<std::size_t L>
|
||||
Error field(const char*, ox::BString<L> *val);
|
||||
[[nodiscard]] Error field(const char*, ox::BString<L> *val) noexcept;
|
||||
|
||||
Error field(const char*, SerStr val);
|
||||
[[nodiscard]] Error field(const char*, SerStr val) noexcept;
|
||||
|
||||
template<typename T>
|
||||
Error field(const char*, T *val);
|
||||
[[nodiscard]] Error field(const char*, T *val);
|
||||
|
||||
void setTypeInfo(const char *name, int fields);
|
||||
template<typename U>
|
||||
[[nodiscard]] Error field(const char*, UnionView<U> val);
|
||||
|
||||
std::size_t size();
|
||||
template<typename T = std::nullptr_t>
|
||||
void setTypeInfo(const char *name = T::TypeName, int fields = T::Fields);
|
||||
|
||||
static constexpr OpType opType() {
|
||||
std::size_t size() noexcept;
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::Write;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename I>
|
||||
Error appendInteger(I val);
|
||||
[[nodiscard]] Error appendInteger(I val) noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<std::size_t L>
|
||||
Error MetalClawWriter::field(const char *name, ox::BString<L> *val) {
|
||||
Error MetalClawWriter::field(const char *name, ox::BString<L> *val) noexcept {
|
||||
return field(name, SerStr(val->data(), val->cap()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawWriter::field(const char*, T *val) {
|
||||
bool fieldSet = false;
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
|
||||
if (val) {
|
||||
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
|
||||
oxReturnError(model(&writer, val));
|
||||
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
|
||||
m_buffIt += writer.m_buffIt;
|
||||
@ -98,27 +109,42 @@ Error MetalClawWriter::field(const char*, T *val) {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Error MetalClawWriter::field(const char*, UnionView<U> val) {
|
||||
bool fieldSet = false;
|
||||
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt, val.idx());
|
||||
oxReturnError(model(&writer, val.get()));
|
||||
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
|
||||
m_buffIt += writer.m_buffIt;
|
||||
fieldSet = true;
|
||||
}
|
||||
}
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawWriter::field(const char*, T *val, std::size_t len) {
|
||||
auto err = OxError(0);
|
||||
bool fieldSet = false;
|
||||
|
||||
if (len) {
|
||||
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
const auto arrLen = mc::encodeInteger(len);
|
||||
if (m_buffIt + arrLen.length < m_buffLen) {
|
||||
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length);
|
||||
m_buffIt += arrLen.length;
|
||||
} else {
|
||||
err = OxError(MC_BUFFENDED);
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
|
||||
writer.setTypeInfo("List", len);
|
||||
writer.setTypeInfo<T>("List", len);
|
||||
|
||||
// write the array
|
||||
for (std::size_t i = 0; i < len; i++) {
|
||||
err |= writer.field("", &val[i]);
|
||||
oxReturnError(writer.field("", &val[i]));
|
||||
}
|
||||
|
||||
m_buffIt += writer.m_buffIt;
|
||||
@ -127,31 +153,87 @@ Error MetalClawWriter::field(const char*, T *val, std::size_t len) {
|
||||
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return err;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error MetalClawWriter::field(const char*, ox::Vector<T> *val) {
|
||||
Error MetalClawWriter::field(const char*, Vector<T> *val) {
|
||||
return field(nullptr, val->data(), val->size());
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
Error MetalClawWriter::appendInteger(I val) {
|
||||
auto err = OxError(0);
|
||||
template<typename T>
|
||||
[[nodiscard]] Error MetalClawWriter::field(const char*, HashMap<String, T> *val) {
|
||||
auto &keys = val->keys();
|
||||
auto len = keys.size();
|
||||
bool fieldSet = false;
|
||||
if (val) {
|
||||
|
||||
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
// write the length
|
||||
const auto arrLen = mc::encodeInteger(len);
|
||||
if (m_buffIt + arrLen.length < m_buffLen) {
|
||||
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length);
|
||||
m_buffIt += arrLen.length;
|
||||
} else {
|
||||
return OxError(MC_BUFFENDED);
|
||||
}
|
||||
|
||||
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
|
||||
// double len for both key and value
|
||||
writer.setTypeInfo("Map", len * 2);
|
||||
|
||||
// write the array
|
||||
for (std::size_t i = 0; i < len; i++) {
|
||||
auto &key = keys[i];
|
||||
const auto keyLen = ox_strlen(key);
|
||||
auto wkey = static_cast<char*>(ox_alloca(keyLen + 1));
|
||||
memcpy(wkey, key.c_str(), keyLen + 1);
|
||||
oxReturnError(writer.field("", SerStr(&wkey, keyLen)));
|
||||
oxReturnError(writer.field("", &(*val)[key]));
|
||||
}
|
||||
|
||||
m_buffIt += writer.m_buffIt;
|
||||
fieldSet = true;
|
||||
}
|
||||
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
Error MetalClawWriter::appendInteger(I val) noexcept {
|
||||
bool fieldSet = false;
|
||||
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
|
||||
auto mi = mc::encodeInteger(val);
|
||||
if (mi.length < m_buffLen) {
|
||||
fieldSet = true;
|
||||
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
|
||||
m_buffIt += mi.length;
|
||||
} else {
|
||||
err |= OxError(MC_BUFFENDED);
|
||||
oxReturnError(OxError(MC_BUFFENDED));
|
||||
}
|
||||
}
|
||||
err |= m_fieldPresence.set(m_field, fieldSet);
|
||||
oxReturnError(m_fieldPresence.set(m_field, fieldSet));
|
||||
m_field++;
|
||||
return err;
|
||||
return OxError(0);
|
||||
;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MetalClawWriter::setTypeInfo(const char*, int fields) {
|
||||
m_fields = fields;
|
||||
m_fieldPresence.setFields(fields);
|
||||
m_buffIt = m_fieldPresence.getMaxLen();
|
||||
ox_memset(m_buff, 0, m_buffIt);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<Vector<char>> writeMC(T *val) {
|
||||
Vector<char> buff(10 * units::MB);
|
||||
MetalClawWriter writer(bit_cast<uint8_t*>(buff.data()), buff.size());
|
||||
oxReturnError(model(&writer, val));
|
||||
buff.resize(writer.size());
|
||||
return buff;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
41
deps/ox/src/ox/model/desctypes.hpp
vendored
41
deps/ox/src/ox/model/desctypes.hpp
vendored
@ -8,11 +8,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/bit.hpp>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/bstring.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
using ModelString = BString<100>;
|
||||
@ -26,13 +29,16 @@ enum class PrimitiveType: uint8_t {
|
||||
// Float = 3, reserved, but not implemented
|
||||
String = 4,
|
||||
Struct = 5,
|
||||
Union = 6,
|
||||
};
|
||||
|
||||
struct DescriptorField {
|
||||
// order of fields matters
|
||||
|
||||
static constexpr auto TypeVersion = 1;
|
||||
|
||||
// only serialize type name if type has already been serialized
|
||||
const struct DescriptorType *type = nullptr;
|
||||
struct DescriptorType *type = nullptr;
|
||||
FieldName fieldName;
|
||||
int subscriptLevels = 0;
|
||||
|
||||
@ -53,7 +59,7 @@ struct DescriptorField {
|
||||
ownsType = false; // is copy, only owns type if move
|
||||
}
|
||||
|
||||
constexpr DescriptorField(const DescriptorType *type, const FieldName &fieldName, int subscriptLevels, const TypeName &typeName, bool ownsType) noexcept {
|
||||
constexpr DescriptorField(DescriptorType *type, const FieldName &fieldName, int subscriptLevels, const TypeName &typeName, bool ownsType) noexcept {
|
||||
this->type = type;
|
||||
this->fieldName = fieldName;
|
||||
this->subscriptLevels = subscriptLevels;
|
||||
@ -98,6 +104,7 @@ struct DescriptorField {
|
||||
using FieldList = Vector<DescriptorField>;
|
||||
|
||||
struct DescriptorType {
|
||||
static constexpr auto TypeVersion = 1;
|
||||
TypeName typeName;
|
||||
PrimitiveType primitiveType;
|
||||
// fieldList only applies to structs
|
||||
@ -105,6 +112,7 @@ struct DescriptorType {
|
||||
// - number of bytes for integer and float types
|
||||
// - number of fields for structs and lists
|
||||
int64_t length = 0;
|
||||
bool preloadable = false;
|
||||
|
||||
DescriptorType() = default;
|
||||
|
||||
@ -118,13 +126,13 @@ struct DescriptorType {
|
||||
|
||||
template<typename T>
|
||||
Error model(T *io, DescriptorType *type) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("ox::DescriptorType", 4);
|
||||
err |= io->field("typeName", &type->typeName);
|
||||
err |= io->field("primitiveType", &type->primitiveType);
|
||||
err |= io->field("fieldList", &type->fieldList);
|
||||
err |= io->field("length", &type->length);
|
||||
return err;
|
||||
io->template setTypeInfo<T>("net.drinkingtea.ox.DescriptorType", 5);
|
||||
oxReturnError(io->field("typeName", &type->typeName));
|
||||
oxReturnError(io->field("primitiveType", bit_cast<uint8_t*>(&type->primitiveType)));
|
||||
oxReturnError(io->field("fieldList", &type->fieldList));
|
||||
oxReturnError(io->field("length", &type->length));
|
||||
oxReturnError(io->field("preloadable", &type->preloadable));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@ -132,16 +140,17 @@ Error modelWrite(T *io, DescriptorField *field) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("ox::DescriptorField", 4);
|
||||
if (field->ownsType) {
|
||||
err |= io->field("typeName", "");
|
||||
err |= io->field("type", field->type);
|
||||
BString<2> empty = "";
|
||||
oxReturnError(io->field("typeName", SerStr(&empty)));
|
||||
oxReturnError(io->field("type", field->type));
|
||||
} else {
|
||||
err |= io->field("typeName", &field->type->typeName);
|
||||
err |= io->field("type", static_cast<decltype(field->type)>(nullptr));
|
||||
oxReturnError(io->field("typeName", SerStr(&field->type->typeName)));
|
||||
oxReturnError(io->field("type", static_cast<decltype(field->type)>(nullptr)));
|
||||
}
|
||||
err |= io->field("fieldName", &field->fieldName);
|
||||
oxReturnError(io->field("fieldName", &field->fieldName));
|
||||
// defaultValue is unused now, but leave placeholder for backwards compatibility
|
||||
const int DefaultValue = 0;
|
||||
err |= io->field("defaultValue", &DefaultValue);
|
||||
int DefaultValue = 0;
|
||||
oxReturnError(io->field("defaultValue", &DefaultValue));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
38
deps/ox/src/ox/model/descwrite.cpp
vendored
38
deps/ox/src/ox/model/descwrite.cpp
vendored
@ -12,6 +12,26 @@
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct preloadable_type {
|
||||
static constexpr auto Preloadable = true;
|
||||
};
|
||||
|
||||
struct non_preloadable_type {
|
||||
static constexpr auto Preloadable = false;
|
||||
};
|
||||
|
||||
struct non_preloadable_type2 {
|
||||
};
|
||||
|
||||
static_assert(preloadable<preloadable_type>::value);
|
||||
static_assert(!preloadable<non_preloadable_type>::value);
|
||||
static_assert(!preloadable<non_preloadable_type2>::value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static_assert([] {
|
||||
int i = 0;
|
||||
return indirectionLevels(i) == 0;
|
||||
@ -96,7 +116,7 @@ DescriptorType *TypeDescWriter::type(uint64_t*, bool *alreadyExisted) {
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(const char*, bool *alreadyExisted) {
|
||||
DescriptorType *TypeDescWriter::type(char*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:string";
|
||||
constexpr auto PT = PrimitiveType::String;
|
||||
return getType(TypeName, PT, 0, alreadyExisted);
|
||||
@ -108,6 +128,12 @@ DescriptorType *TypeDescWriter::type(SerStr, bool *alreadyExisted) {
|
||||
return getType(TypeName, PT, 0, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(String*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:string";
|
||||
constexpr auto PT = PrimitiveType::String;
|
||||
return getType(TypeName, PT, 0, alreadyExisted);
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::type(bool*, bool *alreadyExisted) {
|
||||
constexpr auto TypeName = "B:bool";
|
||||
constexpr auto PT = PrimitiveType::Bool;
|
||||
@ -115,16 +141,6 @@ DescriptorType *TypeDescWriter::type(bool*, bool *alreadyExisted) {
|
||||
return getType(TypeName, PT, Bytes, alreadyExisted);
|
||||
}
|
||||
|
||||
void TypeDescWriter::setTypeInfo(const char *name, int) {
|
||||
auto &t = m_typeStore->at(name);
|
||||
if (!t) {
|
||||
t = new DescriptorType;
|
||||
}
|
||||
m_type = t;
|
||||
m_type->typeName = name;
|
||||
m_type->primitiveType = PrimitiveType::Struct;
|
||||
}
|
||||
|
||||
DescriptorType *TypeDescWriter::getType(TypeName tn, PrimitiveType pt, int b, bool *alreadyExisted) {
|
||||
if (m_typeStore->contains(tn)) {
|
||||
*alreadyExisted = true;
|
||||
|
105
deps/ox/src/ox/model/descwrite.hpp
vendored
105
deps/ox/src/ox/model/descwrite.hpp
vendored
@ -9,8 +9,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/bstring.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
@ -21,6 +21,22 @@
|
||||
|
||||
namespace ox {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<bool>
|
||||
struct BoolWrapper {
|
||||
};
|
||||
|
||||
template<typename T, typename = BoolWrapper<true>>
|
||||
struct preloadable: false_type {};
|
||||
|
||||
template<typename T>
|
||||
struct preloadable<T, BoolWrapper<T::Preloadable>> {
|
||||
static constexpr bool value = T::Preloadable;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static constexpr int indirectionLevels(T) {
|
||||
return 0;
|
||||
@ -38,20 +54,25 @@ class TypeDescWriter {
|
||||
|
||||
TypeName name;
|
||||
|
||||
constexpr void setTypeInfo(const char *n, int) noexcept {
|
||||
template<typename T = std::nullptr_t>
|
||||
constexpr void setTypeInfo(const char *n = T::TypeName, int = T::Fields) noexcept {
|
||||
this->name = n;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr ox::Error field(const char*, T*, std::size_t) noexcept {
|
||||
[[nodiscard]] constexpr ox::Error field(const char*, T*, std::size_t) noexcept {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr ox::Error field(const char*, T*) noexcept {
|
||||
[[nodiscard]] constexpr ox::Error field(const char*, T) noexcept {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::WriteDefinition;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TypeStore *m_typeStoreOwnerRef = nullptr;
|
||||
@ -64,21 +85,22 @@ class TypeDescWriter {
|
||||
~TypeDescWriter();
|
||||
|
||||
template<typename T>
|
||||
ox::Error field(const char *name, T *val, std::size_t valLen);
|
||||
[[nodiscard]] ox::Error field(const char *name, T *val, std::size_t valLen);
|
||||
|
||||
template<typename T>
|
||||
ox::Error field(const char *name, ox::Vector<T> *val);
|
||||
[[nodiscard]] ox::Error field(const char *name, T val);
|
||||
|
||||
template<typename T>
|
||||
ox::Error field(const char *name, T *val);
|
||||
[[nodiscard]] ox::Error field(const char *name, T *val);
|
||||
|
||||
void setTypeInfo(const char *name, int fields);
|
||||
template<typename T = std::nullptr_t>
|
||||
void setTypeInfo(const char *name = T::TypeName, int fields = T::Fields);
|
||||
|
||||
[[nodiscard]] DescriptorType *definition() noexcept {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
static constexpr OpType opType() {
|
||||
static constexpr auto opType() {
|
||||
return OpType::WriteDefinition;
|
||||
}
|
||||
|
||||
@ -95,16 +117,27 @@ class TypeDescWriter {
|
||||
|
||||
DescriptorType *type(bool *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(const char *val, bool *alreadyExisted);
|
||||
DescriptorType *type(char *val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(SerStr val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *type(String *val, bool *alreadyExisted);
|
||||
|
||||
template<std::size_t sz>
|
||||
DescriptorType *type(BString<sz> *val, bool *alreadyExisted);
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *type(T *val, bool *alreadyExisted);
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *type(Vector<T> *val, bool *alreadyExisted);
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *type(HashMap<String, T> *val, bool *alreadyExisted);
|
||||
|
||||
template<typename U>
|
||||
DescriptorType *type(UnionView<U> val, bool *alreadyExisted);
|
||||
|
||||
DescriptorType *getType(TypeName tn, PrimitiveType t, int b, bool *alreadyExisted);
|
||||
};
|
||||
|
||||
@ -126,8 +159,15 @@ ox::Error TypeDescWriter::field(const char *name, T *val, std::size_t) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error TypeDescWriter::field(const char *name, ox::Vector<T> *val) {
|
||||
return field(name, val->data(), val->size());
|
||||
ox::Error TypeDescWriter::field(const char *name, T val) {
|
||||
if (m_type) {
|
||||
bool alreadyExisted = false;
|
||||
const auto t = type(val, &alreadyExisted);
|
||||
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
|
||||
m_type->fieldList.emplace_back(t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted);
|
||||
return OxError(0);
|
||||
}
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@ -150,7 +190,7 @@ DescriptorType *TypeDescWriter::type(BString<sz> *val, bool *alreadyExisted) {
|
||||
template<typename T>
|
||||
DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) {
|
||||
NameCatcher nc;
|
||||
model(&nc, val);
|
||||
oxLogError(model(&nc, val));
|
||||
if (m_typeStore->contains(nc.name)) {
|
||||
*alreadyExisted = true;
|
||||
return m_typeStore->at(nc.name);
|
||||
@ -163,18 +203,49 @@ DescriptorType *TypeDescWriter::type(T *val, bool *alreadyExisted) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] ValErr<DescriptorType*> buildMCDef(T *val) {
|
||||
DescriptorType *TypeDescWriter::type(Vector<T> *val, bool *alreadyExisted) {
|
||||
return type(val->data(), alreadyExisted);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DescriptorType *TypeDescWriter::type(HashMap<String, T>*, bool *alreadyExisted) {
|
||||
return type(static_cast<T*>(nullptr), alreadyExisted);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
DescriptorType *TypeDescWriter::type(UnionView<U> val, bool *alreadyExisted) {
|
||||
return type(val.get(), alreadyExisted);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void TypeDescWriter::setTypeInfo(const char *name, int) {
|
||||
auto &t = m_typeStore->at(name);
|
||||
if (!t) {
|
||||
t = new DescriptorType;
|
||||
}
|
||||
m_type = t;
|
||||
m_type->typeName = name;
|
||||
if (is_union_v<T>) {
|
||||
m_type->primitiveType = PrimitiveType::Union;
|
||||
} else {
|
||||
m_type->primitiveType = PrimitiveType::Struct;
|
||||
}
|
||||
m_type->preloadable = detail::preloadable<T>::value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] ValErr<DescriptorType*> buildTypeDef(T *val) {
|
||||
TypeDescWriter writer;
|
||||
Error err = model(&writer, val);
|
||||
return {writer.definition(), err};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error writeMCDef(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) {
|
||||
auto def = buildMCDef(val);
|
||||
Error writeTypeDef(uint8_t *buff, std::size_t buffLen, T *val, std::size_t *sizeOut = nullptr) {
|
||||
auto def = buildTypeDef(val);
|
||||
auto err = def.error;
|
||||
if (!err) {
|
||||
err |= writeMC(buff, buffLen, def.value, sizeOut);
|
||||
oxReturnError(writeType(buff, buffLen, def.value, sizeOut));
|
||||
}
|
||||
delete def.value;
|
||||
return err;
|
||||
|
42
deps/ox/src/ox/model/optype.hpp
vendored
42
deps/ox/src/ox/model/optype.hpp
vendored
@ -8,43 +8,47 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/assert.hpp>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/strops.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
enum class OpType {
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
WriteDefinition = 3,
|
||||
};
|
||||
namespace OpType {
|
||||
constexpr auto Read = "Read";
|
||||
constexpr auto Write = "Write";
|
||||
constexpr auto WriteDefinition = "WriteDefinition";
|
||||
}
|
||||
|
||||
// empty default implementations of model functions
|
||||
|
||||
template<typename T, typename O>
|
||||
ox::Error modelRead(T*, O*) {
|
||||
return OxError(1);
|
||||
[[nodiscard]] ox::Error modelRead(T*, O*) {
|
||||
return OxError(1, "Model: modelRead not implemented");
|
||||
}
|
||||
|
||||
template<typename T, typename O>
|
||||
ox::Error modelWrite(T*, O*) {
|
||||
return OxError(1);
|
||||
[[nodiscard]] ox::Error modelWrite(T*, O*) {
|
||||
return OxError(1, "Model: modelWrite not implemented");
|
||||
}
|
||||
|
||||
template<typename T, typename O>
|
||||
ox::Error modelWriteDefinition(T*, O*) {
|
||||
return OxError(1);
|
||||
[[nodiscard]] ox::Error modelWriteDefinition(T*, O*) {
|
||||
return OxError(1, "Model: modelWriteDefinition not implemented");
|
||||
}
|
||||
|
||||
template<typename T, typename O>
|
||||
ox::Error model(T *io, O *obj) {
|
||||
if constexpr(T::opType() == ox::OpType::Read) {
|
||||
return modelRead(io, obj);
|
||||
} else if constexpr(T::opType() == ox::OpType::Write) {
|
||||
return modelWrite(io, obj);
|
||||
} else if constexpr(T::opType() == ox::OpType::WriteDefinition) {
|
||||
return modelWriteDefinition(io, obj);
|
||||
[[nodiscard]] ox::Error model(T *io, O *obj) {
|
||||
ox::Error err;
|
||||
if constexpr(ox_strcmp(T::opType(), ox::OpType::Read) == 0) {
|
||||
err = modelRead(io, obj);
|
||||
} else if constexpr(ox_strcmp(T::opType(), ox::OpType::Write) == 0) {
|
||||
err = modelWrite(io, obj);
|
||||
} else if constexpr(ox_strcmp(T::opType(), ox::OpType::WriteDefinition) == 0) {
|
||||
err = modelWriteDefinition(io, obj);
|
||||
}
|
||||
return OxError(1);
|
||||
oxAssert(err, "Missing model function");
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
||||
|
49
deps/ox/src/ox/model/types.hpp
vendored
49
deps/ox/src/ox/model/types.hpp
vendored
@ -11,6 +11,7 @@
|
||||
#include <ox/std/bstring.hpp>
|
||||
#include <ox/std/strops.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/typetraits.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
@ -19,6 +20,7 @@ class SerStr {
|
||||
protected:
|
||||
int m_cap = 0;
|
||||
char *m_str = nullptr;
|
||||
char **m_tgt = nullptr;
|
||||
|
||||
public:
|
||||
template<std::size_t sz>
|
||||
@ -32,21 +34,33 @@ class SerStr {
|
||||
m_cap = cap;
|
||||
}
|
||||
|
||||
constexpr SerStr(char **tgt, int cap = -1) noexcept {
|
||||
m_tgt = tgt;
|
||||
m_str = const_cast<char*>(*tgt);
|
||||
m_cap = cap;
|
||||
}
|
||||
|
||||
template<std::size_t cap>
|
||||
constexpr SerStr(char (&str)[cap]) noexcept {
|
||||
m_str = str;
|
||||
m_cap = cap;
|
||||
}
|
||||
|
||||
constexpr const char *c_str() noexcept {
|
||||
return m_str;
|
||||
}
|
||||
|
||||
constexpr char *data() noexcept {
|
||||
// do not return a non-const pointer to the const_casted m_str
|
||||
constexpr char *data(std::size_t sz = 0) noexcept {
|
||||
if (m_tgt && sz) {
|
||||
*m_tgt = new char[sz];
|
||||
m_str = *m_tgt;
|
||||
m_cap = sz;
|
||||
}
|
||||
return m_str;
|
||||
}
|
||||
|
||||
constexpr int len() noexcept {
|
||||
return ox_strlen(m_str);
|
||||
}
|
||||
|
||||
constexpr int bytes() noexcept {
|
||||
return ox_strlen(m_str) + 1; // adds 1 for \0
|
||||
return m_str ? ox_strlen(m_str) : 0;
|
||||
}
|
||||
|
||||
constexpr int cap() noexcept {
|
||||
@ -55,4 +69,25 @@ class SerStr {
|
||||
|
||||
};
|
||||
|
||||
template<typename Union>
|
||||
class UnionView {
|
||||
|
||||
protected:
|
||||
int m_idx = -1;
|
||||
typename enable_if<is_union_v<Union>, Union>::type *m_union = nullptr;
|
||||
|
||||
public:
|
||||
constexpr explicit UnionView(Union *u, int idx) noexcept: m_idx(idx), m_union(u) {
|
||||
}
|
||||
|
||||
constexpr auto idx() noexcept {
|
||||
return m_idx;
|
||||
}
|
||||
|
||||
constexpr Union *get() noexcept {
|
||||
return m_union;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
22
deps/ox/src/ox/model/walk.hpp
vendored
22
deps/ox/src/ox/model/walk.hpp
vendored
@ -30,7 +30,7 @@ class DataWalker {
|
||||
|
||||
[[nodiscard]] const DescriptorType *type() const noexcept;
|
||||
|
||||
ox::Error read(const DescriptorField&, Reader *rdr);
|
||||
[[nodiscard]] ox::Error read(const DescriptorField&, Reader *rdr);
|
||||
|
||||
protected:
|
||||
void pushNamePath(FieldName fn);
|
||||
@ -86,14 +86,14 @@ static ox::Error parseField(const DescriptorField &field, Reader *rdr, DataWalke
|
||||
walker->pushNamePath(field.fieldName);
|
||||
if (field.subscriptLevels) {
|
||||
// add array handling
|
||||
const auto [arrayLen, err] = rdr->arrayLength(true);
|
||||
const auto [arrayLen, err] = rdr->arrayLength(field.fieldName.c_str(), true);
|
||||
oxReturnError(err);
|
||||
auto child = rdr->child();
|
||||
auto child = rdr->child(field.fieldName.c_str());
|
||||
child.setTypeInfo(field.fieldName.c_str(), arrayLen);
|
||||
DescriptorField f(field); // create mutable copy
|
||||
--f.subscriptLevels;
|
||||
BString<100> subscript;
|
||||
for (ArrayLength i = 0; i < arrayLen; i++) {
|
||||
for (std::size_t i = 0; i < arrayLen; i++) {
|
||||
subscript = "[";
|
||||
subscript += i;
|
||||
subscript += "]";
|
||||
@ -111,8 +111,9 @@ static ox::Error parseField(const DescriptorField &field, Reader *rdr, DataWalke
|
||||
oxReturnError(walker->read(field, rdr));
|
||||
break;
|
||||
case PrimitiveType::Struct:
|
||||
if (rdr->fieldPresent()) {
|
||||
auto child = rdr->child();
|
||||
case PrimitiveType::Union:
|
||||
if (rdr->fieldPresent(field.fieldName.c_str())) {
|
||||
auto child = rdr->child(field.fieldName.c_str());
|
||||
walker->pushType(field.type);
|
||||
oxReturnError(model(&child, walker));
|
||||
walker->popType();
|
||||
@ -120,7 +121,7 @@ static ox::Error parseField(const DescriptorField &field, Reader *rdr, DataWalke
|
||||
} else {
|
||||
// skip and discard absent field
|
||||
int discard;
|
||||
oxReturnError(rdr->field("", &discard));
|
||||
oxReturnError(rdr->field(field.fieldName.c_str(), &discard));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -144,4 +145,11 @@ ox::Error model(Reader *rdr, DataWalker<Reader, FH> *walker) {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename Reader, typename Handler>
|
||||
ox::Error walkModel(DescriptorType *type, uint8_t *data, std::size_t dataLen, Handler handler) {
|
||||
DataWalker<Reader, Handler> walker(type, handler);
|
||||
Reader rdr(data, dataLen);
|
||||
return model(&rdr, &walker);
|
||||
}
|
||||
|
||||
}
|
||||
|
40
deps/ox/src/ox/oc/CMakeLists.txt
vendored
Normal file
40
deps/ox/src/ox/oc/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
add_library(
|
||||
OxOrganicClaw
|
||||
read.cpp
|
||||
write.cpp
|
||||
)
|
||||
|
||||
find_package(JsonCpp REQUIRED)
|
||||
|
||||
target_compile_options(OxOrganicClaw PRIVATE -Wsign-conversion)
|
||||
|
||||
target_link_libraries(
|
||||
OxOrganicClaw PUBLIC
|
||||
OxModel
|
||||
JsonCpp::JsonCpp
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
OxOrganicClaw
|
||||
PROPERTY
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
oc.hpp
|
||||
read.hpp
|
||||
write.hpp
|
||||
DESTINATION
|
||||
include/ox/oc
|
||||
)
|
||||
|
||||
install(TARGETS OxOrganicClaw
|
||||
LIBRARY DESTINATION lib/ox
|
||||
ARCHIVE DESTINATION lib/ox
|
||||
)
|
||||
|
||||
if(OX_RUN_TESTS STREQUAL "ON")
|
||||
add_subdirectory(test)
|
||||
endif()
|
12
deps/ox/src/ox/oc/oc.hpp
vendored
Normal file
12
deps/ox/src/ox/oc/oc.hpp
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "read.hpp"
|
||||
#include "write.hpp"
|
255
deps/ox/src/ox/oc/read.cpp
vendored
Normal file
255
deps/ox/src/ox/oc/read.cpp
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2015 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/std/bit.hpp>
|
||||
|
||||
#include "read.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
OrganicClawReader::OrganicClawReader(const uint8_t *buff, std::size_t buffSize) {
|
||||
auto json = bit_cast<const char*>(buff);
|
||||
auto jsonLen = ox_strnlen(json, buffSize);
|
||||
Json::CharReaderBuilder parserBuilder;
|
||||
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
|
||||
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
|
||||
throw OxError(1, "Could not parse JSON");
|
||||
}
|
||||
}
|
||||
|
||||
OrganicClawReader::OrganicClawReader(const char *json, std::size_t jsonLen) {
|
||||
Json::CharReaderBuilder parserBuilder;
|
||||
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
|
||||
if (!parser->parse(json, json + jsonLen, &m_json, nullptr)) {
|
||||
throw OxError(1, "Could not parse JSON");
|
||||
}
|
||||
}
|
||||
|
||||
OrganicClawReader::OrganicClawReader(const Json::Value &json, int unionIdx):
|
||||
m_json(json),
|
||||
m_unionIdx(unionIdx) {
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, int8_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isInt()) {
|
||||
*val = static_cast<int8_t>(jv.asInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, int16_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isInt()) {
|
||||
*val = static_cast<int16_t>(jv.asInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, int32_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isInt()) {
|
||||
*val = static_cast<int32_t>(jv.asInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, int64_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isInt() || jv.isInt64()) {
|
||||
*val = static_cast<int64_t>(jv.asInt64());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
Error OrganicClawReader::field(const char *key, uint8_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isUInt()) {
|
||||
*val = static_cast<uint8_t>(jv.asUInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, uint16_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isUInt()) {
|
||||
*val = static_cast<uint16_t>(jv.asUInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, uint32_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isUInt()) {
|
||||
*val = static_cast<uint32_t>(jv.asUInt());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, uint64_t *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = 0;
|
||||
} else if (jv.isUInt() || jv.isUInt64()) {
|
||||
*val = static_cast<uint64_t>(jv.asUInt64());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, bool *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
*val = false;
|
||||
} else if (jv.isBool()) {
|
||||
*val = jv.asBool();
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
Error OrganicClawReader::field(const char *key, SerStr val) {
|
||||
auto err = OxError(0);
|
||||
const char *begin = nullptr, *end = nullptr;
|
||||
const auto &jv = value(key);
|
||||
if (targetValid()) {
|
||||
if (jv.empty()) {
|
||||
auto data = val.data();
|
||||
if (data) {
|
||||
data[0] = 0;
|
||||
}
|
||||
} else if (jv.isString()) {
|
||||
jv.getString(&begin, &end);
|
||||
auto strSize = end - begin;
|
||||
auto data = val.data(static_cast<std::size_t>(strSize) + 1);
|
||||
if (strSize >= val.cap()) {
|
||||
err = OxError(1, "String size exceeds capacity of destination");
|
||||
} else {
|
||||
ox_memcpy(data, begin, static_cast<std::size_t>(strSize));
|
||||
data[strSize] = 0;
|
||||
}
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
[[nodiscard]] ValErr<std::size_t> OrganicClawReader::arrayLength(const char *key, bool) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
return 0;
|
||||
}
|
||||
if (jv.isArray()) {
|
||||
return jv.size();
|
||||
}
|
||||
return OxError(1, "Type mismatch");
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t OrganicClawReader::stringLength(const char *key) {
|
||||
const char *begin = nullptr, *end = nullptr;
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty()) {
|
||||
return 0;
|
||||
}
|
||||
if (jv.isString()) {
|
||||
jv.getString(&begin, &end);
|
||||
return static_cast<std::size_t>(end - begin);
|
||||
}
|
||||
return OxError(1, "Type mismatch");
|
||||
}
|
||||
|
||||
OrganicClawReader OrganicClawReader::child(const char *key, int unionIdx) {
|
||||
return OrganicClawReader(m_json[key], unionIdx);
|
||||
}
|
||||
|
||||
bool OrganicClawReader::fieldPresent(const char *key) {
|
||||
return !m_json[key].empty();
|
||||
}
|
||||
|
||||
Json::Value &OrganicClawReader::value(const char *key) {
|
||||
if (m_json.isArray()) {
|
||||
return m_json[m_fieldIt];
|
||||
} else {
|
||||
return m_json[key];
|
||||
}
|
||||
}
|
||||
|
||||
bool OrganicClawReader::targetValid() noexcept {
|
||||
return static_cast<int>(m_fieldIt) == m_unionIdx || m_unionIdx == -1;
|
||||
}
|
||||
|
||||
}
|
204
deps/ox/src/ox/oc/read.hpp
vendored
Normal file
204
deps/ox/src/ox/oc/read.hpp
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2015 - 2020 gtalent2@gmail.com
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <ox/model/optype.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/memops.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class OrganicClawReader {
|
||||
|
||||
private:
|
||||
Json::Value m_json;
|
||||
Json::ArrayIndex m_fieldIt = 0;
|
||||
int m_unionIdx = -1;
|
||||
|
||||
public:
|
||||
OrganicClawReader() = default;
|
||||
|
||||
OrganicClawReader(const uint8_t *buff, std::size_t buffSize);
|
||||
|
||||
OrganicClawReader(const char *json, std::size_t buffSize);
|
||||
|
||||
OrganicClawReader(const Json::Value &json, int unionIdx = -1);
|
||||
|
||||
[[nodiscard]] Error field(const char *key, int8_t *val);
|
||||
[[nodiscard]] Error field(const char *key, int16_t *val);
|
||||
[[nodiscard]] Error field(const char *key, int32_t *val);
|
||||
[[nodiscard]] Error field(const char *key, int64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char *key, uint8_t *val);
|
||||
[[nodiscard]] Error field(const char *key, uint16_t *val);
|
||||
[[nodiscard]] Error field(const char *key, uint32_t *val);
|
||||
[[nodiscard]] Error field(const char *key, uint64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char *key, bool *val);
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char *key, T *val, std::size_t len);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char *key, Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, HashMap<String, T> *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char *key, T *val);
|
||||
|
||||
template<typename U>
|
||||
[[nodiscard]] Error field(const char *key, UnionView<U> val);
|
||||
|
||||
template<std::size_t L>
|
||||
[[nodiscard]] Error field(const char *key, ox::BString<L> *val);
|
||||
|
||||
[[nodiscard]] Error field(const char *key, SerStr val);
|
||||
|
||||
/**
|
||||
* Reads an array length from the current location in the buffer.
|
||||
* @param pass indicates that the parsing should iterate past the array length
|
||||
*/
|
||||
[[nodiscard]] ValErr<std::size_t> arrayLength(const char *key, bool pass = true);
|
||||
|
||||
/**
|
||||
* Reads an string length from the current location in the buffer.
|
||||
*/
|
||||
[[nodiscard]] std::size_t stringLength(const char *name);
|
||||
|
||||
template<typename T = void>
|
||||
constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a OrganicClawReader to parse a child object.
|
||||
*/
|
||||
[[nodiscard]] OrganicClawReader child(const char *key, int unionIdx = -1);
|
||||
|
||||
// compatibility stub
|
||||
constexpr void nextField() noexcept {}
|
||||
|
||||
bool fieldPresent(const char *key);
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::Read;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Json::Value &value(const char *key);
|
||||
|
||||
bool targetValid() noexcept;
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawReader::field(const char *key, T *val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty() || jv.isObject()) {
|
||||
auto reader = child(key);
|
||||
return model(&reader, val);
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Error OrganicClawReader::field(const char *key, UnionView<U> val) {
|
||||
auto err = OxError(0);
|
||||
if (targetValid()) {
|
||||
const auto &jv = value(key);
|
||||
if (jv.empty() || jv.isObject()) {
|
||||
auto reader = child(key, val.idx());
|
||||
err = model(&reader, val.get());
|
||||
} else {
|
||||
err = OxError(1, "Type mismatch");
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return err;
|
||||
}
|
||||
|
||||
template<std::size_t L>
|
||||
Error OrganicClawReader::field(const char *name, ox::BString<L> *val) {
|
||||
return field(name, SerStr(val->data(), val->cap()));
|
||||
}
|
||||
|
||||
// array handler
|
||||
template<typename T>
|
||||
Error OrganicClawReader::field(const char *key, T *val, std::size_t valLen) {
|
||||
const auto &srcVal = value(key);
|
||||
auto srcSize = srcVal.size();
|
||||
if (srcSize > valLen) {
|
||||
return OxError(1);
|
||||
}
|
||||
OrganicClawReader r(srcVal);
|
||||
for (decltype(srcSize) i = 0; i < srcSize; ++i) {
|
||||
oxReturnError(r.field("", &val[i]));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawReader::field(const char *key, ox::Vector<T> *val) {
|
||||
return field(key, val->data(), val->size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error OrganicClawReader::field(const char *key, HashMap<String, T> *val) {
|
||||
const auto &srcVal = value(key);
|
||||
auto keys = srcVal.getMemberNames();
|
||||
auto srcSize = srcVal.size();
|
||||
OrganicClawReader r(srcVal);
|
||||
for (decltype(srcSize) i = 0; i < srcSize; ++i) {
|
||||
auto k = keys[i].c_str();
|
||||
oxReturnError(r.field(k, &val->at(k)));
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error readOC(const char *json, std::size_t jsonSize, T *val) noexcept {
|
||||
// OrganicClawReader constructor can throw, but readOC should return its errors.
|
||||
try {
|
||||
Json::Value doc;
|
||||
Json::CharReaderBuilder parserBuilder;
|
||||
auto parser = std::unique_ptr<Json::CharReader>(parserBuilder.newCharReader());
|
||||
if (!parser->parse(json, json + jsonSize, &doc, nullptr)) {
|
||||
return OxError(1, "Could not parse JSON");
|
||||
}
|
||||
OrganicClawReader reader(json, jsonSize);
|
||||
return model(&reader, val);
|
||||
} catch (Error err) {
|
||||
return err;
|
||||
} catch (...) {
|
||||
return OxError(1, "Unkown Error");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<std::unique_ptr<T>> readOC(const char *json) {
|
||||
auto val = std::make_unique<T>();
|
||||
oxReturnError(readOC(json, ox_strlen(json), val.get()));
|
||||
return {std::move(val), OxError(0)};
|
||||
}
|
||||
|
||||
}
|
13
deps/ox/src/ox/oc/test/CMakeLists.txt
vendored
Normal file
13
deps/ox/src/ox/oc/test/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
add_executable(
|
||||
OcTest
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
OcTest
|
||||
OxOrganicClaw
|
||||
)
|
||||
|
||||
add_test("Test\\ OcTest\\ Writer" OcTest OrganicClawWriter)
|
||||
add_test("Test\\ OcTest\\ Reader" OcTest OrganicClawReader)
|
||||
add_test("Test\\ OcTest\\ OrganicClawDef" OcTest OrganicClawDef)
|
288
deps/ox/src/ox/oc/test/tests.cpp
vendored
Normal file
288
deps/ox/src/ox/oc/test/tests.cpp
vendored
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright 2015 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#undef NDEBUG
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <ox/model/model.hpp>
|
||||
#include <ox/oc/oc.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
union TestUnion {
|
||||
static constexpr auto TypeName = "TestUnion";
|
||||
static constexpr auto Fields = 3;
|
||||
bool Bool;
|
||||
uint32_t Int = 5;
|
||||
char String[32];
|
||||
};
|
||||
|
||||
struct TestStructNest {
|
||||
bool Bool = false;
|
||||
uint32_t Int = 0;
|
||||
ox::BString<32> String = "";
|
||||
};
|
||||
|
||||
struct TestStruct {
|
||||
bool Bool = false;
|
||||
int32_t Int = 0;
|
||||
int32_t Int1 = 0;
|
||||
int32_t Int2 = 0;
|
||||
int32_t Int3 = 0;
|
||||
int32_t Int4 = 0;
|
||||
int32_t Int5 = 0;
|
||||
int32_t Int6 = 0;
|
||||
int32_t Int7 = 0;
|
||||
int32_t Int8 = 0;
|
||||
TestUnion Union;
|
||||
char *CString = nullptr;
|
||||
ox::BString<32> String = "";
|
||||
uint32_t List[4] = {0, 0, 0, 0};
|
||||
ox::HashMap<ox::String, int> Map;
|
||||
TestStructNest EmptyStruct;
|
||||
TestStructNest Struct;
|
||||
|
||||
~TestStruct() {
|
||||
delete[] CString;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestUnion *obj) {
|
||||
io->template setTypeInfo<TestUnion>();
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", ox::SerStr(obj->String)));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStructNest *obj) {
|
||||
io->setTypeInfo("TestStructNest", 3);
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, TestStruct *obj) {
|
||||
io->setTypeInfo("TestStruct", 17);
|
||||
oxReturnError(io->field("Bool", &obj->Bool));
|
||||
oxReturnError(io->field("Int", &obj->Int));
|
||||
oxReturnError(io->field("Int1", &obj->Int1));
|
||||
oxReturnError(io->field("Int2", &obj->Int2));
|
||||
oxReturnError(io->field("Int3", &obj->Int3));
|
||||
oxReturnError(io->field("Int4", &obj->Int4));
|
||||
oxReturnError(io->field("Int5", &obj->Int5));
|
||||
oxReturnError(io->field("Int6", &obj->Int6));
|
||||
oxReturnError(io->field("Int7", &obj->Int7));
|
||||
oxReturnError(io->field("Int8", &obj->Int8));
|
||||
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1}));
|
||||
oxReturnError(io->field("CString", ox::SerStr(&obj->CString)));
|
||||
oxReturnError(io->field("String", &obj->String));
|
||||
oxReturnError(io->field("List", obj->List, 4));
|
||||
oxReturnError(io->field("Map", &obj->Map));
|
||||
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
|
||||
oxReturnError(io->field("Struct", &obj->Struct));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
std::map<std::string, ox::Error(*)()> tests = {
|
||||
{
|
||||
{
|
||||
"OrganicClawWriter",
|
||||
[] {
|
||||
// This test doesn't confirm much, but it does show that the writer
|
||||
// doesn't segfault
|
||||
TestStruct ts;
|
||||
return ox::writeOC(&ts).error;
|
||||
}
|
||||
},
|
||||
{
|
||||
"OrganicClawReader",
|
||||
[] {
|
||||
TestStruct testIn;
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.Union.Int = 52;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.CString = new char[ox_strlen("c-string") + 1];
|
||||
ox_strcpy(testIn.CString, "c-string");
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Map["asdf"] = 93;
|
||||
testIn.Map["aoeu"] = 94;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
auto [oc, writeErr] = ox::writeOC(&testIn);
|
||||
oxAssert(writeErr, "writeOC failed");
|
||||
std::cout << oc.data() << '\n';
|
||||
auto [testOut, readErr] = ox::readOC<TestStruct>(oc.data());
|
||||
oxAssert(readErr, "readOC failed");
|
||||
|
||||
oxAssert(testIn.Bool == testOut->Bool, "Bool value mismatch");
|
||||
oxAssert(testIn.Int == testOut->Int, "Int value mismatch");
|
||||
oxAssert(testIn.Int1 == testOut->Int1, "Int1 value mismatch");
|
||||
oxAssert(testIn.Int2 == testOut->Int2, "Int2 value mismatch");
|
||||
oxAssert(testIn.Int3 == testOut->Int3, "Int3 value mismatch");
|
||||
oxAssert(testIn.Int4 == testOut->Int4, "Int4 value mismatch");
|
||||
oxAssert(testIn.Int5 == testOut->Int5, "Int5 value mismatch");
|
||||
oxAssert(testIn.Int6 == testOut->Int6, "Int6 value mismatch");
|
||||
oxAssert(testIn.Int7 == testOut->Int7, "Int7 value mismatch");
|
||||
oxAssert(testIn.Int8 == testOut->Int8, "Int8 value mismatch");
|
||||
oxAssert(ox_strcmp(testIn.CString, testOut->CString) == 0, "CString value mismatch");
|
||||
oxAssert(testIn.Union.Int == testOut->Union.Int, "Union.Int value mismatch");
|
||||
oxAssert(testIn.String == testOut->String, "String value mismatch");
|
||||
oxAssert(testIn.List[0] == testOut->List[0], "List[0] value mismatch");
|
||||
oxAssert(testIn.List[1] == testOut->List[1], "List[1] value mismatch");
|
||||
oxAssert(testIn.List[2] == testOut->List[2], "List[2] value mismatch");
|
||||
oxAssert(testIn.List[3] == testOut->List[3], "List[3] value mismatch");
|
||||
oxAssert(testIn.Map["asdf"] == testOut->Map["asdf"], "Map[\"asdf\"] value mismatch");
|
||||
oxAssert(testIn.Map["aoeu"] == testOut->Map["aoeu"], "Map[\"aoeu\"] value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Bool == testOut->EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.Int == testOut->EmptyStruct.Int, "EmptyStruct.Int value mismatch");
|
||||
oxAssert(testIn.EmptyStruct.String == testOut->EmptyStruct.String, "EmptyStruct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Int == testOut->Struct.Int, "Struct.Int value mismatch");
|
||||
oxAssert(testIn.Struct.String == testOut->Struct.String, "Struct.String value mismatch");
|
||||
oxAssert(testIn.Struct.Bool == testOut->Struct.Bool, "Struct.Bool value mismatch");
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
{
|
||||
"OrganicClawDef",
|
||||
[] {
|
||||
TestStruct testIn, testOut;
|
||||
|
||||
testIn.Bool = true;
|
||||
testIn.Int = 42;
|
||||
testIn.String = "Test String 1";
|
||||
testIn.List[0] = 1;
|
||||
testIn.List[1] = 2;
|
||||
testIn.List[2] = 3;
|
||||
testIn.List[3] = 4;
|
||||
testIn.Struct.Bool = false;
|
||||
testIn.Struct.Int = 300;
|
||||
testIn.Struct.String = "Test String 2";
|
||||
|
||||
auto [oc, ocErr] = ox::writeOC(&testIn);
|
||||
oxAssert(ocErr, "Data generation failed");
|
||||
auto type = ox::buildTypeDef(&testIn);
|
||||
oxAssert(type.error, "Descriptor write failed");
|
||||
ox::walkModel<ox::OrganicClawReader>(type.value, ox::bit_cast<uint8_t*>(oc.data()), oc.size(),
|
||||
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::TypeName>&, const ox::DescriptorField &f, ox::OrganicClawReader *rdr) -> ox::Error {
|
||||
//std::cout << f.fieldName.c_str() << '\n';
|
||||
auto fieldName = f.fieldName.c_str();
|
||||
switch (f.type->primitiveType) {
|
||||
case ox::PrimitiveType::UnsignedInteger:
|
||||
std::cout << fieldName << ":\tuint" << f.type->length * 8 << "_t:\t";
|
||||
switch (f.type->length) {
|
||||
case 1: {
|
||||
uint8_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
uint16_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
uint32_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
uint64_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cout << '\n';
|
||||
break;
|
||||
case ox::PrimitiveType::SignedInteger:
|
||||
std::cout << fieldName << ":\tint" << f.type->length * 8 << "_t:\t";
|
||||
switch (f.type->length) {
|
||||
case 1: {
|
||||
int8_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
int16_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int32_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
int64_t i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::cout << '\n';
|
||||
break;
|
||||
case ox::PrimitiveType::Bool: {
|
||||
bool i = {};
|
||||
oxAssert(rdr->field(fieldName, &i), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "bool:\t" << (i ? "true" : "false") << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::String: {
|
||||
ox::Vector<char> v(rdr->stringLength(fieldName) + 1);
|
||||
//std::cout << rdr->stringLength() << '\n';
|
||||
oxAssert(rdr->field(fieldName, ox::SerStr(v.data(), v.size())), "Walking model failed.");
|
||||
std::cout << fieldName << ":\t" << "string: " << v.data() << '\n';
|
||||
break;
|
||||
}
|
||||
case ox::PrimitiveType::Struct:
|
||||
break;
|
||||
case ox::PrimitiveType::Union:
|
||||
break;
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
);
|
||||
delete type.value;
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 0) {
|
||||
auto testName = args[1];
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName]();
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
118
deps/ox/src/ox/oc/write.cpp
vendored
Normal file
118
deps/ox/src/ox/oc/write.cpp
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "write.hpp"
|
||||
|
||||
namespace ox {
|
||||
|
||||
OrganicClawWriter::OrganicClawWriter(int unionIdx): m_unionIdx(unionIdx) {
|
||||
}
|
||||
|
||||
OrganicClawWriter::OrganicClawWriter(Json::Value json, int unionIdx):
|
||||
m_json(json),
|
||||
m_unionIdx(unionIdx) {
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, int8_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, int16_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, int32_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, int64_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, uint8_t *val) {
|
||||
if (*val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, uint16_t *val) {
|
||||
if (targetValid() && *val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, uint32_t *val) {
|
||||
if (targetValid() && *val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, uint64_t *val) {
|
||||
if (targetValid() && *val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, bool *val) {
|
||||
if (targetValid() && *val) {
|
||||
value(key) = *val;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, ox::String val) {
|
||||
if (targetValid() && val.len()) {
|
||||
value(key) = val.c_str();
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Error OrganicClawWriter::field(const char *key, SerStr val) {
|
||||
if (targetValid() && val.len()) {
|
||||
value(key) = val.c_str();
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
Json::Value &OrganicClawWriter::value(const char *key) {
|
||||
if (m_json.isArray()) {
|
||||
return m_json[m_fieldIt];
|
||||
} else {
|
||||
return m_json[key];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
162
deps/ox/src/ox/oc/write.hpp
vendored
Normal file
162
deps/ox/src/ox/oc/write.hpp
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
#include <ox/model/optype.hpp>
|
||||
#include <ox/model/types.hpp>
|
||||
#include <ox/std/hashmap.hpp>
|
||||
#include <ox/std/string.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
class OrganicClawWriter {
|
||||
|
||||
template<typename T>
|
||||
friend ValErr<Vector<char>> writeOC(T *val);
|
||||
|
||||
protected:
|
||||
Json::Value m_json;
|
||||
Json::ArrayIndex m_fieldIt = 0;
|
||||
int m_unionIdx = -1;
|
||||
|
||||
public:
|
||||
OrganicClawWriter(int unionIdx = -1);
|
||||
|
||||
OrganicClawWriter(Json::Value json, int unionIdx = -1);
|
||||
|
||||
[[nodiscard]] Error field(const char*, int8_t *val);
|
||||
[[nodiscard]] Error field(const char*, int16_t *val);
|
||||
[[nodiscard]] Error field(const char*, int32_t *val);
|
||||
[[nodiscard]] Error field(const char*, int64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, uint8_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint16_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint32_t *val);
|
||||
[[nodiscard]] Error field(const char*, uint64_t *val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, bool *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, T *val, std::size_t len);
|
||||
|
||||
template<typename U>
|
||||
[[nodiscard]] Error field(const char*, UnionView<U> val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, ox::Vector<T> *val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, HashMap<String, T> *val);
|
||||
|
||||
template<std::size_t L>
|
||||
[[nodiscard]] Error field(const char*, ox::BString<L> *val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, ox::String val);
|
||||
|
||||
[[nodiscard]] Error field(const char*, SerStr val);
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error field(const char*, T *val);
|
||||
|
||||
template<typename T = void>
|
||||
constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) {
|
||||
}
|
||||
|
||||
static constexpr auto opType() {
|
||||
return OpType::Write;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr bool targetValid() noexcept {
|
||||
return static_cast<int>(m_fieldIt) == m_unionIdx || m_unionIdx == -1;
|
||||
}
|
||||
|
||||
Json::Value &value(const char *key);
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawWriter::field(const char *key, T *val, std::size_t len) {
|
||||
if (targetValid()) {
|
||||
OrganicClawWriter w((Json::Value(Json::arrayValue)));
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
oxReturnError(w.field("", &val[i]));
|
||||
}
|
||||
value(key) = w.m_json;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<std::size_t L>
|
||||
Error OrganicClawWriter::field(const char *key, ox::BString<L> *val) {
|
||||
return field(key, SerStr(val->data(), val->cap()));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawWriter::field(const char *key, T *val) {
|
||||
if (val && targetValid()) {
|
||||
OrganicClawWriter w;
|
||||
oxReturnError(model(&w, val));
|
||||
if (!w.m_json.isNull()) {
|
||||
value(key) = w.m_json;
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
Error OrganicClawWriter::field(const char *key, UnionView<U> val) {
|
||||
if (targetValid()) {
|
||||
OrganicClawWriter w(val.idx());
|
||||
oxReturnError(model(&w, val.get()));
|
||||
if (!w.m_json.isNull()) {
|
||||
value(key) = w.m_json;
|
||||
}
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Error OrganicClawWriter::field(const char *key, ox::Vector<T> *val) {
|
||||
return field(key, val->data(), val->size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] Error OrganicClawWriter::field(const char *key, ox::HashMap<String, T> *val) {
|
||||
if (targetValid()) {
|
||||
auto &keys = val->keys();
|
||||
OrganicClawWriter w;
|
||||
for (std::size_t i = 0; i < keys.size(); ++i) {
|
||||
auto k = keys[i].c_str();
|
||||
oxReturnError(w.field(k, &val->at(k)));
|
||||
}
|
||||
value(key) = w.m_json;
|
||||
}
|
||||
++m_fieldIt;
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ValErr<Vector<char>> writeOC(T *val) {
|
||||
OrganicClawWriter writer;
|
||||
oxReturnError(model(&writer, val));
|
||||
Json::StreamWriterBuilder jsonBuilder;
|
||||
auto str = Json::writeString(jsonBuilder, writer.m_json);
|
||||
Vector<char> buff(str.size() + 1);
|
||||
memcpy(buff.data(), str.c_str(), str.size() + 1);
|
||||
return buff;
|
||||
}
|
||||
|
||||
}
|
9
deps/ox/src/ox/std/CMakeLists.txt
vendored
9
deps/ox/src/ox/std/CMakeLists.txt
vendored
@ -3,6 +3,7 @@ add_library(
|
||||
assert.cpp
|
||||
buildinfo.cpp
|
||||
byteswap.cpp
|
||||
heapmgr.cpp
|
||||
memops.cpp
|
||||
new.cpp
|
||||
random.cpp
|
||||
@ -13,6 +14,8 @@ add_library(
|
||||
trace.cpp
|
||||
)
|
||||
|
||||
target_compile_options(OxStd PRIVATE -Wsign-conversion)
|
||||
|
||||
if(NOT OX_BARE_METAL)
|
||||
set_property(
|
||||
TARGET
|
||||
@ -45,17 +48,19 @@ install(
|
||||
error.hpp
|
||||
hardware.hpp
|
||||
hashmap.hpp
|
||||
heapmgr.hpp
|
||||
math.hpp
|
||||
memops.hpp
|
||||
new.hpp
|
||||
random.hpp
|
||||
std.hpp
|
||||
stddef.hpp
|
||||
stacktrace.hpp
|
||||
string.hpp
|
||||
strongint.hpp
|
||||
strops.hpp
|
||||
std.hpp
|
||||
stddef.hpp
|
||||
trace.hpp
|
||||
typeinfo.hpp
|
||||
types.hpp
|
||||
typetraits.hpp
|
||||
units.hpp
|
||||
|
27
deps/ox/src/ox/std/assert.cpp
vendored
27
deps/ox/src/ox/std/assert.cpp
vendored
@ -32,21 +32,38 @@ void assertFunc<bool>([[maybe_unused]]const char *file, [[maybe_unused]]int line
|
||||
}
|
||||
|
||||
template<>
|
||||
void assertFunc<Error>(const char *file, int line, Error err, const char *msg) {
|
||||
void assertFunc<Error>(const char *file, int line, Error err, const char *assertMsg) {
|
||||
if (err) {
|
||||
panic(file, line, msg, err);
|
||||
#if defined(OX_USE_STDLIB)
|
||||
std::cerr << "\033[31;1;1mASSERT FAILURE:\033[0m (" << file << ':' << line << "): " << assertMsg << '\n';
|
||||
if (err.msg) {
|
||||
std::cerr << "\tError Message:\t" << err.msg << '\n';
|
||||
}
|
||||
std::cerr << "\tError Code:\t" << err << '\n';
|
||||
if (err.file != nullptr) {
|
||||
std::cerr << "\tError Location:\t" << reinterpret_cast<const char*>(err.file) << ':' << err.line << '\n';
|
||||
}
|
||||
printStackTrace(2);
|
||||
oxTrace("panic").del("") << "Panic: " << assertMsg << " (" << file << ":" << line << ")";
|
||||
std::abort();
|
||||
#else
|
||||
panic(file, line, assertMsg);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(OX_USE_STDLIB)
|
||||
void panic(const char *file, int line, const char *msg, Error err) {
|
||||
std::cerr << "\033[31;1;1mPANIC:\033[0m (" << file << ':' << line << "): " << msg << '\n';
|
||||
void panic(const char *file, int line, const char *panicMsg, Error err) {
|
||||
std::cerr << "\033[31;1;1mPANIC:\033[0m (" << file << ':' << line << "): " << panicMsg << '\n';
|
||||
if (err.msg) {
|
||||
std::cerr << "\tError Message:\t" << err.msg << '\n';
|
||||
}
|
||||
std::cerr << "\tError Code:\t" << err << '\n';
|
||||
if (err.file != nullptr) {
|
||||
std::cerr << "\tError Location:\t" << reinterpret_cast<const char*>(err.file) << ':' << err.line << '\n';
|
||||
}
|
||||
printStackTrace(2);
|
||||
oxTrace("assert").del("") << "Failed assert: " << msg << " (" << file << ":" << line << ")";
|
||||
oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")";
|
||||
std::abort();
|
||||
}
|
||||
#endif
|
||||
|
2
deps/ox/src/ox/std/bit.hpp
vendored
2
deps/ox/src/ox/std/bit.hpp
vendored
@ -24,7 +24,7 @@ typename enable_if<sizeof(To) == sizeof(From), To>::type bit_cast(From src) noex
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr T rotl(T i, int shift) noexcept {
|
||||
constexpr auto bits = sizeof(i) * 8;
|
||||
return (i << shift) | (i >> (bits - shift));
|
||||
return (i << static_cast<T>(shift)) | (i >> (bits - static_cast<T>(shift)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
27
deps/ox/src/ox/std/error.hpp
vendored
27
deps/ox/src/ox/std/error.hpp
vendored
@ -8,37 +8,44 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "defines.hpp"
|
||||
#include "strongint.hpp"
|
||||
#include "typetraits.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define OxError(x) ox::_error(__FILE__, __LINE__, static_cast<ox::Error>(x))
|
||||
#else
|
||||
#define OxError(x) static_cast<ox::Error>(x)
|
||||
#endif
|
||||
#define OxError(...) ox::_error(__FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
namespace ox {
|
||||
|
||||
struct BaseError {
|
||||
const char *msg = nullptr;
|
||||
const char *file = "";
|
||||
uint16_t line = 0;
|
||||
|
||||
BaseError() = default;
|
||||
|
||||
constexpr BaseError(const BaseError &o) noexcept {
|
||||
msg = o.msg;
|
||||
file = o.file;
|
||||
line = o.line;
|
||||
}
|
||||
|
||||
constexpr BaseError operator=(const BaseError &o) noexcept {
|
||||
msg = o.msg;
|
||||
file = o.file;
|
||||
line = o.line;
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
using Error = Integer<uint64_t, BaseError>;
|
||||
|
||||
static constexpr Error _error(const char *file, uint32_t line, Error errCode) {
|
||||
Error err = errCode;
|
||||
err.file = file;
|
||||
err.line = line;
|
||||
static constexpr Error _error(const char *file, uint32_t line, uint64_t errCode, const char *msg = nullptr) {
|
||||
Error err = static_cast<ox::Error>(errCode);
|
||||
err.file = file;
|
||||
err.line = line;
|
||||
err.msg = msg;
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -83,7 +90,7 @@ namespace error {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr ox::Error toError(ox::ValErr<T> ve) noexcept {
|
||||
[[nodiscard]] constexpr ox::Error toError(const ox::ValErr<T> &ve) noexcept {
|
||||
return ve.error;
|
||||
}
|
||||
|
||||
|
26
deps/ox/src/ox/std/hashmap.hpp
vendored
26
deps/ox/src/ox/std/hashmap.hpp
vendored
@ -16,6 +16,9 @@ namespace ox {
|
||||
template<typename K, typename T>
|
||||
class HashMap {
|
||||
|
||||
using key_t = K;
|
||||
using value_t = T;
|
||||
|
||||
private:
|
||||
struct Pair {
|
||||
K key = {};
|
||||
@ -31,6 +34,8 @@ class HashMap {
|
||||
|
||||
~HashMap();
|
||||
|
||||
bool operator==(const HashMap &other) const;
|
||||
|
||||
HashMap &operator=(HashMap &other);
|
||||
|
||||
/**
|
||||
@ -47,6 +52,8 @@ class HashMap {
|
||||
|
||||
std::size_t size() const noexcept;
|
||||
|
||||
const Vector<K> &keys() const noexcept;
|
||||
|
||||
private:
|
||||
void expand();
|
||||
|
||||
@ -78,6 +85,20 @@ HashMap<K, T>::~HashMap() {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
bool HashMap<K, T>::operator==(const HashMap &other) const {
|
||||
if (m_keys != other.m_keys) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < m_keys.size(); i++) {
|
||||
auto &k = m_keys[i];
|
||||
if (at(k) != other.at(k)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &other) {
|
||||
this->~HashMap<K, T>();
|
||||
@ -115,6 +136,11 @@ std::size_t HashMap<K, T>::size() const noexcept {
|
||||
return m_keys.size();
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
const Vector<K> &HashMap<K, T>::keys() const noexcept {
|
||||
return m_keys;
|
||||
}
|
||||
|
||||
template<typename K, typename T>
|
||||
void HashMap<K, T>::expand() {
|
||||
Vector<Pair*> r;
|
||||
|
@ -1,27 +1,16 @@
|
||||
/*
|
||||
* Copyright 2016 - 2019 gtalent2@gmail.com
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "addresses.hpp"
|
||||
#include "assert.hpp"
|
||||
#include "bit.hpp"
|
||||
#include "heapmgr.hpp"
|
||||
|
||||
#include <ox/std/assert.hpp>
|
||||
#include <ox/std/bit.hpp>
|
||||
|
||||
// this warning is too dumb to realize that it can actually confirm the hard
|
||||
// coded address aligns with the requirement of HeapSegment, so it must be
|
||||
// suppressed
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
|
||||
#define HEAP_BEGIN reinterpret_cast<HeapSegment*>(MEM_WRAM_BEGIN)
|
||||
// set size to half of WRAM
|
||||
#define HEAP_SIZE ((MEM_WRAM_END - MEM_WRAM_BEGIN) / 2)
|
||||
#define HEAP_END reinterpret_cast<HeapSegment*>(MEM_WRAM_BEGIN + HEAP_SIZE)
|
||||
|
||||
namespace nostalgia::core {
|
||||
namespace ox::heapmgr {
|
||||
|
||||
static struct HeapSegment *volatile g_heapBegin = nullptr;
|
||||
static struct HeapSegment *volatile g_heapEnd = nullptr;
|
||||
@ -36,28 +25,23 @@ static constexpr std::size_t alignedSize(T = {}) {
|
||||
return alignedSize(sizeof(T));
|
||||
}
|
||||
|
||||
struct HeapSegment {
|
||||
std::size_t size;
|
||||
uint8_t inUse;
|
||||
void HeapSegment::init(std::size_t maxSize = ox::bit_cast<std::size_t>(g_heapEnd)) {
|
||||
this->size = maxSize - ox::bit_cast<std::size_t>(this);
|
||||
this->inUse = false;
|
||||
}
|
||||
|
||||
void init(std::size_t maxSize = ox::bit_cast<std::size_t>(g_heapEnd)) {
|
||||
this->size = maxSize - ox::bit_cast<std::size_t>(this);
|
||||
this->inUse = false;
|
||||
}
|
||||
template<typename T>
|
||||
T *HeapSegment::data() {
|
||||
return ox::bit_cast<T*>(ox::bit_cast<uint8_t*>(this) + alignedSize(this));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *data() {
|
||||
return ox::bit_cast<T*>(ox::bit_cast<uint8_t*>(this) + alignedSize(this));
|
||||
}
|
||||
template<typename T>
|
||||
T *HeapSegment::end() {
|
||||
const auto size = alignedSize(this) + alignedSize(this->size);
|
||||
auto e = ox::bit_cast<uintptr_t>(ox::bit_cast<uint8_t*>(this) + size);
|
||||
return ox::bit_cast<T*>(e);
|
||||
}
|
||||
|
||||
template<typename T = uint8_t>
|
||||
T *end() {
|
||||
const auto size = alignedSize(this) + alignedSize(this->size);
|
||||
auto e = ox::bit_cast<uintptr_t>(ox::bit_cast<uint8_t*>(this) + size);
|
||||
return ox::bit_cast<T*>(e);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void initHeap(char *heapBegin, char *heapEnd) {
|
||||
g_heapBegin = ox::bit_cast<HeapSegment*>(heapBegin);
|
||||
@ -67,10 +51,6 @@ void initHeap(char *heapBegin, char *heapEnd) {
|
||||
heapIdx->inUse = false;
|
||||
}
|
||||
|
||||
void initHeap() {
|
||||
initHeap(ox::bit_cast<char*>(HEAP_BEGIN), ox::bit_cast<char*>(HEAP_END));
|
||||
}
|
||||
|
||||
struct SegmentPair {
|
||||
HeapSegment *anteSegment = nullptr;
|
||||
HeapSegment *segment = nullptr;
|
||||
@ -78,7 +58,7 @@ struct SegmentPair {
|
||||
|
||||
static SegmentPair findSegmentOf(void *ptr) {
|
||||
HeapSegment *prev = nullptr;
|
||||
for (auto seg = HEAP_BEGIN; seg < HEAP_END;) {
|
||||
for (auto seg = g_heapBegin; seg < g_heapEnd;) {
|
||||
if (seg->data<void>() == ptr) {
|
||||
return {prev, seg};
|
||||
}
|
||||
@ -126,38 +106,38 @@ void free(void *ptr) {
|
||||
|
||||
#ifndef OX_USE_STDLIB
|
||||
|
||||
using namespace nostalgia;
|
||||
using namespace ox;
|
||||
|
||||
void *operator new(std::size_t allocSize) {
|
||||
return core::malloc(allocSize);
|
||||
return heapmgr::malloc(allocSize);
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t allocSize) {
|
||||
return core::malloc(allocSize);
|
||||
return heapmgr::malloc(allocSize);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr) {
|
||||
core::free(ptr);
|
||||
heapmgr::free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr) {
|
||||
core::free(ptr);
|
||||
heapmgr::free(ptr);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr, unsigned) {
|
||||
core::free(ptr);
|
||||
heapmgr::free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr, unsigned) {
|
||||
core::free(ptr);
|
||||
heapmgr::free(ptr);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr, unsigned long int) {
|
||||
core::free(ptr);
|
||||
heapmgr::free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr, unsigned long int) {
|
||||
core::free(ptr);
|
||||
heapmgr::free(ptr);
|
||||
}
|
||||
|
||||
#endif
|
33
deps/ox/src/ox/std/heapmgr.hpp
vendored
Normal file
33
deps/ox/src/ox/std/heapmgr.hpp
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace ox::heapmgr {
|
||||
|
||||
struct HeapSegment {
|
||||
std::size_t size;
|
||||
uint8_t inUse;
|
||||
|
||||
void init(std::size_t maxSize);
|
||||
|
||||
template<typename T>
|
||||
T *data();
|
||||
|
||||
template<typename T = uint8_t>
|
||||
T *end();
|
||||
|
||||
};
|
||||
|
||||
void initHeap(char *heapBegin, char *heapEnd);
|
||||
|
||||
[[nodiscard]] void *malloc(std::size_t allocSize);
|
||||
|
||||
void free(void *ptr);
|
||||
|
||||
}
|
5
deps/ox/src/ox/std/std.hpp
vendored
5
deps/ox/src/ox/std/std.hpp
vendored
@ -12,18 +12,21 @@
|
||||
#include "bit.hpp"
|
||||
#include "bstring.hpp"
|
||||
#include "byteswap.hpp"
|
||||
#include "defines.hpp"
|
||||
#include "error.hpp"
|
||||
#include "hardware.hpp"
|
||||
#include "hashmap.hpp"
|
||||
#include "heapmgr.hpp"
|
||||
#include "math.hpp"
|
||||
#include "memops.hpp"
|
||||
#include "new.hpp"
|
||||
#include "random.hpp"
|
||||
#include "stacktrace.hpp"
|
||||
#include "stddef.hpp"
|
||||
#include "string.hpp"
|
||||
#include "strongint.hpp"
|
||||
#include "strops.hpp"
|
||||
#include "string.hpp"
|
||||
#include "trace.hpp"
|
||||
#include "typeinfo.hpp"
|
||||
#include "types.hpp"
|
||||
#include "typetraits.hpp"
|
||||
|
30
deps/ox/src/ox/std/string.cpp
vendored
30
deps/ox/src/ox/std/string.cpp
vendored
@ -12,22 +12,41 @@
|
||||
namespace ox {
|
||||
|
||||
String::String() noexcept {
|
||||
m_buff.push_back(0);
|
||||
if (m_buff.size()) {
|
||||
m_buff[0] = 0;
|
||||
} else {
|
||||
m_buff.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
String::String(std::size_t cap) noexcept {
|
||||
m_buff.resize(cap + 1);
|
||||
m_buff[0] = 0;
|
||||
}
|
||||
|
||||
String::String(const char *str) noexcept {
|
||||
m_buff.push_back(0);
|
||||
if (m_buff.size()) {
|
||||
m_buff[0] = 0;
|
||||
} else {
|
||||
m_buff.push_back(0);
|
||||
}
|
||||
*this = str;
|
||||
}
|
||||
|
||||
String::String(String &other) noexcept {
|
||||
String::String(const char *str, std::size_t size) noexcept {
|
||||
m_buff.resize(size + 1);
|
||||
memcpy(m_buff.data(), str, size);
|
||||
m_buff[size] = 0;
|
||||
}
|
||||
|
||||
String::String(const String &other) noexcept {
|
||||
m_buff = other.m_buff;
|
||||
}
|
||||
|
||||
String::String(String &&other) noexcept {
|
||||
m_buff = ox::move(other.m_buff);
|
||||
}
|
||||
|
||||
const String &String::operator=(const char *str) noexcept {
|
||||
std::size_t strLen = ox_strlen(str) + 1;
|
||||
m_buff.resize(strLen + 1);
|
||||
@ -51,6 +70,11 @@ const String &String::operator=(const String &src) noexcept {
|
||||
return *this = src.c_str();
|
||||
}
|
||||
|
||||
const String &String::operator=(const String &&src) noexcept {
|
||||
m_buff = ox::move(src.m_buff);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const String &String::operator+=(const char *str) noexcept {
|
||||
std::size_t strLen = ox_strlen(str);
|
||||
auto currentLen = len();
|
||||
|
8
deps/ox/src/ox/std/string.hpp
vendored
8
deps/ox/src/ox/std/string.hpp
vendored
@ -27,7 +27,11 @@ class String {
|
||||
|
||||
String(const char *str) noexcept;
|
||||
|
||||
String(String&) noexcept;
|
||||
String(const char *str, std::size_t size) noexcept;
|
||||
|
||||
String(const String&) noexcept;
|
||||
|
||||
String(String&&) noexcept;
|
||||
|
||||
const String &operator=(const char *str) noexcept;
|
||||
|
||||
@ -37,6 +41,8 @@ class String {
|
||||
|
||||
const String &operator=(const String &src) noexcept;
|
||||
|
||||
const String &operator=(const String &&src) noexcept;
|
||||
|
||||
const String &operator+=(const char *str) noexcept;
|
||||
|
||||
const String &operator+=(char *str) noexcept;
|
||||
|
19
deps/ox/src/ox/std/strongint.hpp
vendored
19
deps/ox/src/ox/std/strongint.hpp
vendored
@ -12,13 +12,24 @@
|
||||
|
||||
namespace ox {
|
||||
|
||||
class BaseInteger {};
|
||||
struct BaseInteger {
|
||||
|
||||
constexpr BaseInteger() = default;
|
||||
|
||||
constexpr BaseInteger(const BaseInteger&) {
|
||||
}
|
||||
|
||||
constexpr BaseInteger operator=(const BaseInteger&) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Integer is a strongly typed integer wrapper used to create strongly typed
|
||||
* integers.
|
||||
*/
|
||||
template<typename T, class Base = BaseInteger>
|
||||
template<typename T, typename Base = BaseInteger>
|
||||
class Integer: public Base {
|
||||
private:
|
||||
T m_i;
|
||||
@ -115,7 +126,9 @@ constexpr Integer<T, Base>::Integer(const Integer<T, Base> &i) noexcept: Base(i)
|
||||
|
||||
template<typename T, class Base>
|
||||
constexpr Integer<T, Base> Integer<T, Base>::operator=(Integer<T, Base> i) noexcept {
|
||||
return Integer<T, Base>(m_i = i.m_i);
|
||||
Base::operator=(i);
|
||||
m_i = i.m_i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, class Base>
|
||||
|
15
deps/ox/src/ox/std/strops.hpp
vendored
15
deps/ox/src/ox/std/strops.hpp
vendored
@ -12,6 +12,18 @@
|
||||
#include "types.hpp"
|
||||
#include "typetraits.hpp"
|
||||
|
||||
template<typename T1, typename T2>
|
||||
constexpr char *ox_strcpy(T1 dest, T2 src) noexcept {
|
||||
std::size_t i = 0;
|
||||
while (src[i]) {
|
||||
dest[i] = src[i];
|
||||
++i;
|
||||
}
|
||||
// set null terminator
|
||||
dest[i] = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
constexpr char *ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept {
|
||||
std::size_t i = 0;
|
||||
@ -54,7 +66,8 @@ template<typename T1, typename T2>
|
||||
return retval;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr int ox_strncmp(const char *str1, const char *str2, const std::size_t maxLen) noexcept {
|
||||
template<typename T1, typename T2>
|
||||
[[nodiscard]] constexpr int ox_strncmp(T1 str1, T2 str2, const std::size_t maxLen) noexcept {
|
||||
auto retval = 0;
|
||||
std::size_t i = 0;
|
||||
while (i < maxLen && (str1[i] || str2[i])) {
|
||||
|
1
deps/ox/src/ox/std/test/CMakeLists.txt
vendored
1
deps/ox/src/ox/std/test/CMakeLists.txt
vendored
@ -15,3 +15,4 @@ add_test("Test\\ BString" StdTest "BString")
|
||||
add_test("Test\\ String" StdTest "String")
|
||||
add_test("Test\\ Vector" StdTest "Vector")
|
||||
add_test("Test\\ HashMap" StdTest "HashMap")
|
||||
add_test("Test\\ HeapMgr" StdTest malloc)
|
||||
|
17
deps/ox/src/ox/std/test/tests.cpp
vendored
17
deps/ox/src/ox/std/test/tests.cpp
vendored
@ -1,18 +1,27 @@
|
||||
/*
|
||||
* Copyright 2015 - 2018 gtalent2@gmail.com
|
||||
* Copyright 2015 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
map<string, function<int()>> tests = {
|
||||
std::map<std::string, std::function<int()>> tests = {
|
||||
{
|
||||
"malloc",
|
||||
[] {
|
||||
ox::Vector<char> buff(ox::units::MB);
|
||||
ox::heapmgr::initHeap(&buff.front(), &buff.back());
|
||||
oxAssert(ox::heapmgr::malloc(5) != nullptr, "malloc is broken");
|
||||
oxAssert(ox::heapmgr::malloc(5) != nullptr, "malloc is broken");
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
{
|
||||
"ABCDEFG != HIJKLMN",
|
||||
[]() {
|
||||
|
2
deps/ox/src/ox/std/typetraits.hpp
vendored
2
deps/ox/src/ox/std/typetraits.hpp
vendored
@ -89,7 +89,7 @@ template<typename T>
|
||||
constexpr bool is_class_v = ox::is_class<T>();
|
||||
|
||||
template<typename T>
|
||||
constexpr bool is_signed = ox::integral_constant<bool, T(-1) < T(0)>::value;
|
||||
constexpr bool is_signed_v = ox::integral_constant<bool, T(-1) < T(0)>::value;
|
||||
|
||||
// enable_if ///////////////////////////////////////////////////////////////////
|
||||
|
||||
|
10
deps/ox/src/ox/std/vector.hpp
vendored
10
deps/ox/src/ox/std/vector.hpp
vendored
@ -27,13 +27,13 @@ class Vector {
|
||||
|
||||
explicit Vector(std::size_t size) noexcept;
|
||||
|
||||
Vector(Vector &other) noexcept;
|
||||
Vector(const Vector &other) noexcept;
|
||||
|
||||
Vector(Vector &&other) noexcept;
|
||||
|
||||
~Vector() noexcept;
|
||||
|
||||
Vector &operator=(Vector &other) noexcept;
|
||||
Vector &operator=(const Vector &other) noexcept;
|
||||
|
||||
Vector &operator=(Vector &&other) noexcept;
|
||||
|
||||
@ -97,7 +97,7 @@ Vector<T>::Vector(std::size_t size) noexcept {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector<T>::Vector(Vector<T> &other) noexcept {
|
||||
Vector<T>::Vector(const Vector<T> &other) noexcept {
|
||||
m_size = other.m_size;
|
||||
m_cap = other.m_cap;
|
||||
m_items = reinterpret_cast<T*>(new AllocAlias<T>[m_cap]);
|
||||
@ -128,7 +128,7 @@ Vector<T>::~Vector() noexcept {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vector<T> &Vector<T>::operator=(Vector<T> &other) noexcept {
|
||||
Vector<T> &Vector<T>::operator=(const Vector<T> &other) noexcept {
|
||||
this->~Vector<T>();
|
||||
m_size = other.m_size;
|
||||
m_cap = other.m_cap;
|
||||
@ -245,7 +245,7 @@ void Vector<T>::push_back(const T &item) noexcept {
|
||||
if (m_size == m_cap) {
|
||||
expandCap(m_cap ? m_cap * 2 : 100);
|
||||
}
|
||||
m_items[m_size] = item;
|
||||
new (&m_items[m_size]) T(item);
|
||||
++m_size;
|
||||
}
|
||||
|
||||
|
49
jenkins/gba/Jenkinsfile
vendored
Normal file
49
jenkins/gba/Jenkinsfile
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
pipeline {
|
||||
agent {
|
||||
label 'gba'
|
||||
}
|
||||
environment {
|
||||
DEVKITPRO = '/opt/devkitpro'
|
||||
DEVKITARM = '/opt/devkitpro/devkitARM'
|
||||
}
|
||||
stages {
|
||||
stage('Environment') {
|
||||
steps {
|
||||
sh 'conan profile update settings.compiler.libcxx=libstdc++11 default'
|
||||
sh 'conan remote add -f bincrafters https://api.bintray.com/conan/bincrafters/public-conan'
|
||||
sh 'make conan'
|
||||
}
|
||||
}
|
||||
stage('Build Tools Debug') {
|
||||
steps {
|
||||
sh 'make purge configure-debug'
|
||||
sh 'make install'
|
||||
}
|
||||
}
|
||||
stage('Build GBA Debug') {
|
||||
steps {
|
||||
sh 'make configure-gba-debug'
|
||||
sh 'make'
|
||||
sh 'make pkg-gba'
|
||||
}
|
||||
}
|
||||
stage('Build Tools Release') {
|
||||
steps {
|
||||
sh 'make purge configure-release'
|
||||
sh 'make install'
|
||||
}
|
||||
}
|
||||
stage('Build GBA Release') {
|
||||
steps {
|
||||
sh 'make configure-gba'
|
||||
sh 'make'
|
||||
sh 'make pkg-gba'
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
archiveArtifacts artifacts: 'nostalgia.gba', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
47
jenkins/linux/Jenkinsfile
vendored
Normal file
47
jenkins/linux/Jenkinsfile
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
pipeline {
|
||||
agent {
|
||||
label 'linux-x86_64'
|
||||
}
|
||||
stages {
|
||||
stage('Environment') {
|
||||
steps {
|
||||
sh 'conan profile update settings.compiler.libcxx=libstdc++11 default'
|
||||
sh 'conan remote add -f bincrafters https://api.bintray.com/conan/bincrafters/public-conan'
|
||||
sh 'make conan'
|
||||
}
|
||||
}
|
||||
stage('Build Asan') {
|
||||
steps {
|
||||
sh 'make purge configure-asan'
|
||||
sh 'make'
|
||||
}
|
||||
}
|
||||
stage('Test Asan') {
|
||||
steps {
|
||||
sh 'make test'
|
||||
}
|
||||
}
|
||||
stage('Build Debug') {
|
||||
steps {
|
||||
sh 'make purge configure-debug'
|
||||
sh 'make'
|
||||
}
|
||||
}
|
||||
stage('Test Debug') {
|
||||
steps {
|
||||
sh 'make test'
|
||||
}
|
||||
}
|
||||
stage('Build Release') {
|
||||
steps {
|
||||
sh 'make purge configure-release'
|
||||
sh 'make'
|
||||
}
|
||||
}
|
||||
stage('Test Release') {
|
||||
steps {
|
||||
sh 'make test'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
O1;net.drinkingtea.ox.DescriptorType;1;{
|
||||
"fieldList" :
|
||||
[
|
||||
{
|
||||
"fieldName" : "bpp",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" : [],
|
||||
"length" : 1,
|
||||
"primitiveType" : 1,
|
||||
"typeName" : "B:int8_t"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldName" : "rows",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" : [],
|
||||
"length" : 4,
|
||||
"primitiveType" : 1,
|
||||
"typeName" : "B:int32_t"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldName" : "columns",
|
||||
"typeName" : "B:int32_t"
|
||||
},
|
||||
{
|
||||
"fieldName" : "defaultPalette",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" :
|
||||
[
|
||||
{
|
||||
"fieldName" : "type",
|
||||
"typeName" : "B:int8_t"
|
||||
},
|
||||
{
|
||||
"fieldName" : "data",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" :
|
||||
[
|
||||
{
|
||||
"fieldName" : "path",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" : [],
|
||||
"primitiveType" : 4,
|
||||
"typeName" : "B:string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldName" : "constPath",
|
||||
"typeName" : "B:string"
|
||||
},
|
||||
{
|
||||
"fieldName" : "inode",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" : [],
|
||||
"length" : 8,
|
||||
"typeName" : "B:uint64_t"
|
||||
}
|
||||
}
|
||||
],
|
||||
"primitiveType" : 6,
|
||||
"typeName" : "net.drinkingtea.ox.FileAddress.Data"
|
||||
}
|
||||
}
|
||||
],
|
||||
"primitiveType" : 5,
|
||||
"typeName" : "net.drinkingtea.ox.FileAddress"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldName" : "pal",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" :
|
||||
[
|
||||
{
|
||||
"fieldName" : "colors",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" : [],
|
||||
"length" : 2,
|
||||
"typeName" : "B:uint16_t"
|
||||
}
|
||||
}
|
||||
],
|
||||
"primitiveType" : 5,
|
||||
"typeName" : "net.drinkingtea.nostalgia.core.NostalgiaPalette"
|
||||
}
|
||||
},
|
||||
{
|
||||
"fieldName" : "tiles",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" : [],
|
||||
"length" : 1,
|
||||
"typeName" : "B:uint8_t"
|
||||
}
|
||||
}
|
||||
],
|
||||
"primitiveType" : 5,
|
||||
"typeName" : "net.drinkingtea.nostalgia.core.NostalgiaGraphic"
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
O1;net.drinkingtea.ox.DescriptorType;1;{
|
||||
"fieldList" :
|
||||
[
|
||||
{
|
||||
"fieldName" : "colors",
|
||||
"type" :
|
||||
{
|
||||
"fieldList" : [],
|
||||
"length" : 2,
|
||||
"typeName" : "B:uint16_t"
|
||||
}
|
||||
}
|
||||
],
|
||||
"primitiveType" : 5,
|
||||
"typeName" : "net.drinkingtea.nostalgia.core.NostalgiaPalette"
|
||||
}
|
Binary file not shown.
@ -1 +1 @@
|
||||
<03><><EFBFBD><EFBFBD>
|
||||
M1;net.drinkingtea.nostalgia.core.NostalgiaPalette;1;<03><><EFBFBD><EFBFBD>
|
Binary file not shown.
Binary file not shown.
@ -3,10 +3,10 @@
|
||||
set -e
|
||||
|
||||
BIN=./dist/$(cat .current_build)/bin/
|
||||
PATH=$BIN:${DEVKITARM}/bin/:$PATH
|
||||
PATH=$BIN:${DEVKITPRO}/tools/bin/:${DEVKITARM}/bin/:$PATH
|
||||
NOSTALGIA_BIN=build/gba-*/src/nostalgia/player/nostalgia.bin
|
||||
NOSTALGIA_MEDIA=nostalgia_media.oxfs
|
||||
NOSTALGIA_PROJECT=sample_project
|
||||
NOSTALGIA_PROJECT=$1
|
||||
NOSTALGIA_GBA=nostalgia.gba
|
||||
MEDIA_HEADER=media_header.txt
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
target=$1
|
||||
buildType=$2
|
||||
|
||||
@ -42,6 +44,8 @@ cmake -S $project -B $buildDir -GNinja \
|
||||
$toolchain
|
||||
|
||||
mkdir -p dist
|
||||
echo ${buildConfig} > .current_build
|
||||
if [[ $target != gba ]] && [[ $target != gba-debug ]]; then
|
||||
echo ${buildConfig} > .current_build
|
||||
fi
|
||||
rm -f compile_commands.json
|
||||
ln -s build/${buildConfig}/compile_commands.json
|
||||
|
@ -15,9 +15,12 @@ endif()
|
||||
|
||||
add_subdirectory(core)
|
||||
add_subdirectory(common)
|
||||
add_subdirectory(player)
|
||||
add_subdirectory(world)
|
||||
|
||||
if(NOSTALGIA_BUILD_PLAYER)
|
||||
add_subdirectory(player)
|
||||
endif()
|
||||
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "Native")
|
||||
add_subdirectory(tools)
|
||||
if(NOSTALGIA_BUILD_STUDIO)
|
||||
|
@ -5,6 +5,8 @@ add_library(
|
||||
media.cpp
|
||||
)
|
||||
|
||||
target_compile_options(NostalgiaCore PUBLIC -Wsign-conversion)
|
||||
|
||||
target_link_libraries(
|
||||
NostalgiaCore PUBLIC
|
||||
OxFS
|
||||
|
@ -4,7 +4,6 @@ if(NOSTALGIA_BUILD_TYPE STREQUAL "GBA")
|
||||
core.cpp
|
||||
gfx.cpp
|
||||
media.cpp
|
||||
mem.cpp
|
||||
panic.cpp
|
||||
)
|
||||
|
||||
@ -28,8 +27,6 @@ endif()
|
||||
if(NOSTALGIA_BUILD_TYPE STREQUAL "Native")
|
||||
add_executable(NostalgiaCore-GBA_Test
|
||||
tests.cpp
|
||||
mem.cpp
|
||||
)
|
||||
target_link_libraries(NostalgiaCore-GBA_Test NostalgiaCore)
|
||||
add_test("NostalgiaCore-GBA\\ Test\\ malloc" NostalgiaCore-GBA_Test malloc)
|
||||
endif()
|
||||
|
@ -25,11 +25,16 @@ constexpr auto GBA_TILE_COLUMNS = 32;
|
||||
constexpr auto GBA_TILE_ROWS = 32;
|
||||
|
||||
struct GbaPaletteTarget {
|
||||
static constexpr auto TypeName = NostalgiaPalette::TypeName;
|
||||
static constexpr auto Fields = NostalgiaPalette::Fields;
|
||||
static constexpr auto TypeVersion = NostalgiaPalette::TypeVersion;
|
||||
volatile uint16_t *palette = nullptr;
|
||||
};
|
||||
|
||||
struct GbaTileMapTarget {
|
||||
static constexpr auto Fields = 4;
|
||||
static constexpr auto TypeName = NostalgiaGraphic::TypeName;
|
||||
static constexpr auto Fields = NostalgiaGraphic::Fields;
|
||||
static constexpr auto TypeVersion = NostalgiaGraphic::TypeVersion;
|
||||
volatile uint32_t *bgCtl = nullptr;
|
||||
ox::FileAddress defaultPalette;
|
||||
GbaPaletteTarget pal;
|
||||
@ -38,17 +43,17 @@ struct GbaTileMapTarget {
|
||||
|
||||
template<typename T>
|
||||
ox::Error modelRead(T *io, GbaPaletteTarget *t) {
|
||||
io->setTypeInfo("nostalgia::core::NostalgiaPalette", NostalgiaPalette::Fields);
|
||||
oxReturnError(io->template field<Color16>("colors", [t](auto i, Color16 *c) {
|
||||
io->template setTypeInfo<GbaPaletteTarget>();
|
||||
auto colorHandler = [t](std::size_t i, Color16 *c) {
|
||||
t->palette[i] = *c;
|
||||
return OxError(0);
|
||||
}));
|
||||
return OxError(0);
|
||||
};
|
||||
return io->template field<Color16, decltype(colorHandler)>("colors", colorHandler);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error modelRead(T *io, GbaTileMapTarget *t) {
|
||||
io->setTypeInfo("nostalgia::core::NostalgiaGraphic", NostalgiaGraphic::Fields);
|
||||
io->template setTypeInfo<GbaTileMapTarget>();
|
||||
|
||||
uint8_t bpp;
|
||||
int dummy;
|
||||
@ -66,7 +71,7 @@ ox::Error modelRead(T *io, GbaTileMapTarget *t) {
|
||||
oxReturnError(io->field("defaultPalette", &t->defaultPalette));
|
||||
oxReturnError(io->field("pal", &t->pal));
|
||||
uint16_t intermediate = 0;
|
||||
auto err = io->template field<uint8_t>("tileMap", [t, &intermediate](auto i, uint8_t *tile) {
|
||||
auto handleTileMap = [t, &intermediate](std::size_t i, uint8_t *tile) {
|
||||
if (i & 1) { // i is odd
|
||||
intermediate |= static_cast<uint16_t>(*tile) << 8;
|
||||
t->tileMap[i / 2] = intermediate;
|
||||
@ -74,8 +79,8 @@ ox::Error modelRead(T *io, GbaTileMapTarget *t) {
|
||||
intermediate = *tile & 0x00ff;
|
||||
}
|
||||
return OxError(0);
|
||||
});
|
||||
return OxError(err);
|
||||
};
|
||||
return io->template field<uint8_t, decltype(handleTileMap)>("tileMap", handleTileMap);
|
||||
}
|
||||
|
||||
ox::Error initGfx(Context*) {
|
||||
|
@ -1,3 +1,10 @@
|
||||
/*
|
||||
* Copyright 2016 - 2020 gtalent2@gmail.com
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@ -5,9 +12,7 @@
|
||||
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
#include <nostalgia/core/mem.hpp>
|
||||
|
||||
namespace nostalgia::core {
|
||||
namespace ox::heapmgr {
|
||||
|
||||
[[nodiscard]] void *malloc(std::size_t allocSize);
|
||||
|
||||
@ -17,20 +22,7 @@ void initHeap(char *heapBegin, char *heapEnd);
|
||||
|
||||
}
|
||||
|
||||
using namespace nostalgia;
|
||||
|
||||
int testMalloc(std::string) {
|
||||
std::vector<char> buff(ox::units::MB);
|
||||
core::initHeap(&buff.front(), &buff.back());
|
||||
oxAssert(core::malloc(5) != nullptr, "malloc is broken");
|
||||
oxAssert(core::malloc(5) != nullptr, "malloc is broken");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::map<std::string, int(*)(std::string)> tests = {
|
||||
{
|
||||
{ "malloc", testMalloc },
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
|
@ -142,9 +142,9 @@ static char charMap[128] = {
|
||||
};
|
||||
|
||||
Color32 toColor32(Color16 nc) noexcept {
|
||||
Color32 r = ((nc & 0b0000000000011111) >> 0) * 8;
|
||||
Color32 g = ((nc & 0b0000001111100000) >> 5) * 8;
|
||||
Color32 b = ((nc & 0b0111110000000000) >> 10) * 8;
|
||||
Color32 r = static_cast<Color32>(((nc & 0b0000000000011111) >> 0) * 8);
|
||||
Color32 g = static_cast<Color32>(((nc & 0b0000001111100000) >> 5) * 8);
|
||||
Color32 b = static_cast<Color32>(((nc & 0b0111110000000000) >> 10) * 8);
|
||||
Color32 a = 255;
|
||||
return a | (b << 8) | (g << 16) | (r << 24);
|
||||
}
|
||||
@ -177,7 +177,7 @@ uint8_t blue32(Color16 c) noexcept {
|
||||
|
||||
void puts(Context *ctx, int column, int row, const char *str) {
|
||||
for (int i = 0; str[i]; i++) {
|
||||
setTile(ctx, 0, column + i, row, charMap[static_cast<int>(str[i])]);
|
||||
setTile(ctx, 0, column + i, row, static_cast<uint8_t>(charMap[static_cast<int>(str[i])]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,16 @@ using Color16 = uint16_t;
|
||||
using Color32 = uint32_t;
|
||||
|
||||
struct NostalgiaPalette {
|
||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaPalette";
|
||||
static constexpr auto Fields = 1;
|
||||
static constexpr auto TypeVersion = 1;
|
||||
ox::Vector<Color16> colors;
|
||||
};
|
||||
|
||||
struct NostalgiaGraphic {
|
||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic";
|
||||
static constexpr auto Fields = 6;
|
||||
static constexpr auto TypeVersion = 1;
|
||||
int8_t bpp = 0;
|
||||
// rows and columns are really only used by TileSheetEditor
|
||||
int rows = 1;
|
||||
@ -45,14 +49,14 @@ struct NostalgiaGraphic {
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, NostalgiaPalette *pal) {
|
||||
io->setTypeInfo("nostalgia::core::NostalgiaPalette", NostalgiaPalette::Fields);
|
||||
io->template setTypeInfo<NostalgiaPalette>();
|
||||
oxReturnError(io->field("colors", &pal->colors));
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error model(T *io, NostalgiaGraphic *ng) {
|
||||
io->setTypeInfo("nostalgia::core::NostalgiaGraphic", NostalgiaGraphic::Fields);
|
||||
io->template setTypeInfo<NostalgiaGraphic>();
|
||||
oxReturnError(io->field("bpp", &ng->bpp));
|
||||
oxReturnError(io->field("rows", &ng->rows));
|
||||
oxReturnError(io->field("columns", &ng->columns));
|
||||
|
@ -9,6 +9,7 @@ find_package(sdl2 REQUIRED)
|
||||
target_link_libraries(
|
||||
NostalgiaCore-SDL PUBLIC
|
||||
sdl2::sdl2
|
||||
OxClaw
|
||||
OxFS
|
||||
OxStd
|
||||
NostalgiaCore-Userspace
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <ox/mc/read.hpp>
|
||||
#include <ox/claw/read.hpp>
|
||||
|
||||
#include <nostalgia/core/gfx.hpp>
|
||||
|
||||
@ -25,26 +25,26 @@ using TileMap = std::array<std::array<int, 128>, 128>;
|
||||
struct SdlImplData {
|
||||
SDL_Window *window = nullptr;
|
||||
SDL_Renderer *renderer = nullptr;
|
||||
std::array<SDL_Texture*, 4> bgTextures;
|
||||
std::array<TileMap, 4> bgTileMaps;
|
||||
uint64_t prevFpsCheckTime = 0;
|
||||
std::array<SDL_Texture*, 4> bgTextures{};
|
||||
std::array<TileMap, 4> bgTileMaps{};
|
||||
int64_t prevFpsCheckTime = 0;
|
||||
uint64_t draws = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] static ox::ValErr<ox::Vector<uint8_t>> readFile(Context *ctx, const ox::FileAddress &file) {
|
||||
[[nodiscard]] static ox::ValErr<ox::Vector<char>> readFile(Context *ctx, const ox::FileAddress &file) {
|
||||
auto [stat, err] = ctx->rom->stat(file);
|
||||
oxReturnError(err);
|
||||
ox::Vector<uint8_t> buff(stat.size);
|
||||
ox::Vector<char> buff(stat.size);
|
||||
oxReturnError(ctx->rom->read(file, buff.data(), buff.size()));
|
||||
return buff;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] ox::ValErr<T> readMC(Context *ctx, const ox::FileAddress &file) {
|
||||
[[nodiscard]] ox::ValErr<T> readObj(Context *ctx, const ox::FileAddress &file) {
|
||||
auto [buff, err] = readFile(ctx, file);
|
||||
oxReturnError(err);
|
||||
T t;
|
||||
oxReturnError(ox::readMC(buff.data(), buff.size(), &t));
|
||||
oxReturnError(ox::readClaw(buff.data(), buff.size(), &t));
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -97,15 +97,15 @@ ox::Error loadTileSheet(Context *ctx,
|
||||
ox::FileAddress tilesheetPath,
|
||||
ox::FileAddress palettePath) {
|
||||
auto id = ctx->implData<SdlImplData>();
|
||||
auto [tilesheet, tserr] = readMC<NostalgiaGraphic>(ctx, tilesheetPath);
|
||||
auto [tilesheet, tserr] = readObj<NostalgiaGraphic>(ctx, tilesheetPath);
|
||||
oxReturnError(tserr);
|
||||
NostalgiaPalette palette;
|
||||
if (!palettePath) {
|
||||
palettePath = tilesheet.defaultPalette;
|
||||
}
|
||||
oxReturnError(readMC<NostalgiaPalette>(ctx, palettePath).get(&palette));
|
||||
oxReturnError(readObj<NostalgiaPalette>(ctx, palettePath).get(&palette));
|
||||
|
||||
const auto bytesPerTile = tilesheet.bpp == 8 ? 64 : 32;
|
||||
const unsigned bytesPerTile = tilesheet.bpp == 8 ? 64 : 32;
|
||||
const auto tiles = tilesheet.tiles.size() / bytesPerTile;
|
||||
const int width = 8;
|
||||
const int height = 8 * tiles;
|
||||
@ -126,11 +126,12 @@ ox::Error loadTileSheet(Context *ctx,
|
||||
SDL_FreeSurface(surface);
|
||||
SDL_FreePalette(sdlPalette);
|
||||
|
||||
auto sectionIdx = static_cast<unsigned>(section);
|
||||
if (tss == TileSheetSpace::Background) {
|
||||
if (id->bgTextures[section]) {
|
||||
SDL_DestroyTexture(id->bgTextures[section]);
|
||||
if (id->bgTextures[sectionIdx]) {
|
||||
SDL_DestroyTexture(id->bgTextures[sectionIdx]);
|
||||
}
|
||||
id->bgTextures[section] = texture;
|
||||
id->bgTextures[sectionIdx] = texture;
|
||||
}
|
||||
|
||||
return OxError(0);
|
||||
@ -187,7 +188,10 @@ void draw(Context *ctx) {
|
||||
|
||||
void setTile(Context *ctx, int layer, int column, int row, uint8_t tile) {
|
||||
auto id = ctx->implData<SdlImplData>();
|
||||
id->bgTileMaps[layer][row][column] = tile;
|
||||
auto z = static_cast<unsigned>(layer);
|
||||
auto y = static_cast<unsigned>(row);
|
||||
auto x = static_cast<unsigned>(column);
|
||||
id->bgTileMaps[z][y][x] = tile;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ add_library(
|
||||
rsrc.qrc
|
||||
)
|
||||
|
||||
target_compile_options(NostalgiaCore-Studio PRIVATE -Wsign-conversion)
|
||||
|
||||
target_link_libraries(
|
||||
NostalgiaCore-Studio
|
||||
Qt5::Core
|
||||
|
@ -23,7 +23,10 @@ Rectangle {
|
||||
|
||||
onClicked: {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
contextMenu.popup();
|
||||
var tile = mouseArea.tileAt(mouseX, mouseY);
|
||||
if (tile) {
|
||||
contextMenu.popup();
|
||||
}
|
||||
} else {
|
||||
contextMenu.dismiss();
|
||||
}
|
||||
@ -92,7 +95,9 @@ Rectangle {
|
||||
text: "Insert Tile"
|
||||
onTriggered: {
|
||||
var tile = mouseArea.tileAt(contextMenu.x, contextMenu.y);
|
||||
sheetData.insertTileCmd(tile.tileNumber);
|
||||
if (tile) {
|
||||
sheetData.insertTileCmd(tile.tileNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace {
|
||||
const auto r = static_cast<uint32_t>(c.red()) >> 3;
|
||||
const auto g = static_cast<uint32_t>(c.green()) >> 3;
|
||||
const auto b = static_cast<uint32_t>(c.blue()) >> 3;
|
||||
const auto a = static_cast<uint32_t>(c.alpha()) > 128 ? 1 : 0;
|
||||
const auto a = static_cast<uint32_t>(c.alpha() > 128 ? 1 : 0);
|
||||
return (a << 15) | (r << 10) | (g << 5) | (b << 0);
|
||||
}
|
||||
|
||||
@ -72,11 +72,11 @@ namespace {
|
||||
|
||||
QMap<QRgb, int> colors;
|
||||
auto ng = std::make_unique<core::NostalgiaGraphic>();
|
||||
ng->pal.colors.resize(countColors(src, Tiles));
|
||||
ng->pal.colors.resize(static_cast<std::size_t>(countColors(src, Tiles)));
|
||||
if (argBpp == 4) {
|
||||
ng->tiles.resize(Pixels / 2);
|
||||
ng->tiles.resize(static_cast<std::size_t>(Pixels / 2));
|
||||
} else {
|
||||
ng->tiles.resize(Pixels);
|
||||
ng->tiles.resize(static_cast<std::size_t>(Pixels));
|
||||
}
|
||||
ng->bpp = argBpp;
|
||||
ng->columns = src.width() / TileWidth;
|
||||
@ -97,12 +97,12 @@ namespace {
|
||||
// set pixel color
|
||||
if (argBpp == 4) {
|
||||
if (destI % 2) { // is odd number pixel
|
||||
ng->tiles[destI / 2] |= colors[c] << 4;
|
||||
ng->tiles[static_cast<std::size_t>(destI / 2)] |= colors[c] << 4;
|
||||
} else {
|
||||
ng->tiles[destI / 2] |= colors[c];
|
||||
ng->tiles[static_cast<std::size_t>(destI / 2)] |= colors[c];
|
||||
}
|
||||
} else {
|
||||
ng->tiles[destI] = colors[c];
|
||||
ng->tiles[static_cast<std::size_t>(destI)] = static_cast<std::size_t>(colors[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,7 +110,7 @@ namespace {
|
||||
|
||||
// store colors in palette with the corresponding color id
|
||||
for (auto key : colors.keys()) {
|
||||
auto colorId = colors[key];
|
||||
auto colorId = static_cast<std::size_t>(colors[key]);
|
||||
ng->pal.colors[colorId] = toGbaColor(key);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace nostalgia::core {
|
||||
|
||||
NewTilesheetWizardPage::NewTilesheetWizardPage(const studio::Context *ctx) {
|
||||
m_ctx = ctx;
|
||||
addLineEdit(tr("&Tile Sheet Name:"), QString(TileSheetName) + "*", "", [this](QString name) {
|
||||
addLineEdit(tr("&Tile Sheet Name:"), QString(TileSheetName) + "*", "", [](QString) {
|
||||
return 0;
|
||||
});
|
||||
m_palettePicker = addComboBox(tr("&Palette:"), QString(Palette) + "*", {""});
|
||||
@ -33,8 +33,7 @@ NewTilesheetWizardPage::NewTilesheetWizardPage(const studio::Context *ctx) {
|
||||
int NewTilesheetWizardPage::accept() {
|
||||
const auto tilesheetName = field(TileSheetName).toString();
|
||||
const auto palette = m_palettePicker->itemData(field(Palette).toInt()).toString();
|
||||
const auto outPath = TileSheetDir + tilesheetName + FileExt_ng;
|
||||
auto outPath = QString(TileSheetDir) + name + FileExt_ng;
|
||||
const auto outPath = QString(TileSheetDir) + tilesheetName + FileExt_ng;
|
||||
auto err = m_ctx->project->exists(outPath);
|
||||
if (err) {
|
||||
showValidationError(tr("A tile sheet with this name already exists."));
|
||||
|
@ -20,7 +20,7 @@ namespace nostalgia::core {
|
||||
|
||||
NewPaletteWizardPage::NewPaletteWizardPage(const studio::Context *ctx) {
|
||||
m_ctx = ctx;
|
||||
addLineEdit(tr("&Palette Name:"), QString(PaletteName) + "*", "", [this](QString) {
|
||||
addLineEdit(tr("&Palette Name:"), QString(PaletteName) + "*", "", [](QString) {
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
@ -191,14 +191,14 @@ QString PaletteEditor::itemName() const {
|
||||
}
|
||||
|
||||
void PaletteEditor::addColor(int idx, Color16 c) {
|
||||
m_pal->colors.insert(idx, c);
|
||||
m_pal->colors.insert(static_cast<std::size_t>(idx), c);
|
||||
addTableRow(idx, c);
|
||||
setUnsavedChanges(true);
|
||||
}
|
||||
|
||||
void PaletteEditor::rmColor(int idx) {
|
||||
rmTableRow(idx);
|
||||
m_pal->colors.erase(idx);
|
||||
m_pal->colors.erase(static_cast<std::size_t>(idx));
|
||||
setUnsavedChanges(true);
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ void PaletteEditor::addTableRow(int i, Color16 c) {
|
||||
m_table->setItem(i, 1, mkCell(green16(c)));
|
||||
m_table->setItem(i, 2, mkCell(blue16(c)));
|
||||
m_table->setItem(i, 3, mkCell(alpha16(c)));
|
||||
m_table->setItem(i, 4, mkCell(toQColor(m_pal->colors[i]).name(QColor::HexArgb), false));
|
||||
m_table->setItem(i, 4, mkCell(toQColor(m_pal->colors[static_cast<std::size_t>(i)]).name(QColor::HexArgb), false));
|
||||
connect(m_table, &QTableWidget::cellChanged, this, &PaletteEditor::cellChanged);
|
||||
}
|
||||
|
||||
@ -225,12 +225,12 @@ void PaletteEditor::setTableRow(int idx, Color16 c) {
|
||||
m_table->item(idx, 1)->setText(QString::number(green16(c)));
|
||||
m_table->item(idx, 2)->setText(QString::number(blue16(c)));
|
||||
m_table->item(idx, 3)->setText(QString::number(alpha16(c)));
|
||||
m_table->item(idx, 4)->setText(toQColor(m_pal->colors[idx]).name(QColor::HexArgb));
|
||||
m_table->item(idx, 4)->setText(toQColor(m_pal->colors[static_cast<std::size_t>(idx)]).name(QColor::HexArgb));
|
||||
connect(m_table, &QTableWidget::cellChanged, this, &PaletteEditor::cellChanged);
|
||||
}
|
||||
|
||||
void PaletteEditor::updateColor(int idx, Color16 c) {
|
||||
m_pal->colors[idx] = c;
|
||||
m_pal->colors[static_cast<std::size_t>(idx)] = c;
|
||||
setTableRow(idx, c);
|
||||
setUnsavedChanges(true);
|
||||
}
|
||||
@ -266,7 +266,7 @@ void PaletteEditor::colorSelected() {
|
||||
}
|
||||
|
||||
void PaletteEditor::cellChanged(int row, int) {
|
||||
auto oldColor = m_pal->colors[row];
|
||||
auto oldColor = m_pal->colors[static_cast<std::size_t>(row)];
|
||||
auto newColor = rowColor(row);
|
||||
undoStack()->push(new UpdateColorCommand(this, row, oldColor, newColor));
|
||||
}
|
||||
@ -278,7 +278,7 @@ void PaletteEditor::addColorClicked() {
|
||||
|
||||
void PaletteEditor::rmColorClicked() {
|
||||
auto row = m_table->currentRow();
|
||||
undoStack()->push(new RemoveColorCommand(this, m_pal->colors[row], row));
|
||||
undoStack()->push(new RemoveColorCommand(this, m_pal->colors[static_cast<std::size_t>(row)], row));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -366,10 +366,10 @@ std::unique_ptr<NostalgiaGraphic> SheetData::toNostalgiaGraphic() const {
|
||||
ng->bpp = highestColorIdx > 15 ? 8 : 4;
|
||||
ng->columns = m_columns;
|
||||
ng->rows = m_rows;
|
||||
auto pixelCount = ng->rows * ng->columns * PixelsPerTile;
|
||||
auto pixelCount = static_cast<std::size_t>(ng->rows * ng->columns * PixelsPerTile);
|
||||
if (ng->bpp == 4) {
|
||||
ng->tiles.resize(pixelCount / 2);
|
||||
for (int i = 0; i < pixelCount; ++i) {
|
||||
for (std::size_t i = 0; i < pixelCount && i < static_cast<std::size_t>(m_pixels.size()); ++i) {
|
||||
if (i & 1) {
|
||||
ng->tiles[i / 2] |= static_cast<uint8_t>(m_pixels[i]) << 4;
|
||||
} else {
|
||||
|
@ -3,6 +3,8 @@ add_library(
|
||||
media.cpp
|
||||
)
|
||||
|
||||
target_compile_options(NostalgiaCore-Userspace PRIVATE -Wsign-conversion)
|
||||
|
||||
target_link_libraries(
|
||||
NostalgiaCore-Userspace PUBLIC
|
||||
OxFS
|
||||
|
@ -21,9 +21,9 @@ char *loadRom(const char *path) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::size_t size = file.tellg();
|
||||
const auto size = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
auto buff = new char[size];
|
||||
auto buff = new char[static_cast<std::size_t>(size)];
|
||||
file.read(buff, size);
|
||||
return buff;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ target_link_libraries(
|
||||
NostalgiaStudio PUBLIC
|
||||
Qt5::Widgets
|
||||
OxFS
|
||||
OxMetalClaw
|
||||
OxClaw
|
||||
)
|
||||
|
||||
install(
|
||||
|
@ -56,8 +56,8 @@ void Project::writeBuff(QString path, uint8_t *buff, size_t buffLen) const {
|
||||
emit fileUpdated(path);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Project::loadBuff(QString path) const {
|
||||
std::vector<uint8_t> buff(stat(path).size);
|
||||
std::vector<char> Project::loadBuff(QString path) const {
|
||||
std::vector<char> buff(stat(path).size);
|
||||
const auto csPath = path.toUtf8();
|
||||
oxThrowError(m_fs.read(csPath.data(), buff.data(), buff.size()));
|
||||
return buff;
|
||||
|
@ -16,8 +16,11 @@
|
||||
#include <ox/mc/mc.hpp>
|
||||
#include <qnamespace.h>
|
||||
|
||||
#include <ox/claw/claw.hpp>
|
||||
#include <ox/fs/filesystem/passthroughfs.hpp>
|
||||
#include <ox/model/descwrite.hpp>
|
||||
|
||||
#include "nostalgiastudio_export.h"
|
||||
#include "ox/fs/filesystem/passthroughfs.hpp"
|
||||
|
||||
namespace nostalgia::studio {
|
||||
|
||||
@ -71,7 +74,7 @@ class NOSTALGIASTUDIO_EXPORT Project: public QObject {
|
||||
private:
|
||||
void writeBuff(QString path, uint8_t *buff, size_t buffLen) const;
|
||||
|
||||
std::vector<uint8_t> loadBuff(QString path) const;
|
||||
std::vector<char> loadBuff(QString path) const;
|
||||
|
||||
void procDir(QStringList &paths, QString path) const;
|
||||
|
||||
@ -91,12 +94,23 @@ class NOSTALGIASTUDIO_EXPORT Project: public QObject {
|
||||
|
||||
template<typename T>
|
||||
void Project::writeObj(QString path, T *obj) const {
|
||||
std::vector<uint8_t> buff(10 * ox::units::MB, 0);
|
||||
// write MetalClaw
|
||||
size_t mcSize = 0;
|
||||
oxThrowError(ox::writeMC(buff.data(), buff.size(), obj, &mcSize));
|
||||
auto [buff, err] = ox::writeClaw(obj, ox::ClawFormat::Metal);
|
||||
oxThrowError(err);
|
||||
// write to FS
|
||||
writeBuff(path, buff.data(), mcSize);
|
||||
writeBuff(path, ox::bit_cast<uint8_t*>(buff.data()), buff.size());
|
||||
|
||||
// write type descriptor
|
||||
const auto type = ox::buildTypeDef(obj);
|
||||
auto typeOut = ox::writeClaw(type.value, ox::ClawFormat::Organic);
|
||||
oxThrowError(typeOut);
|
||||
// replace garbage last character with new line
|
||||
typeOut.value.back() = '\n';
|
||||
// write to FS
|
||||
QString descPath = "/.nostalgia/type_descriptors/";
|
||||
const auto typePath = descPath + type.value->typeName.c_str();
|
||||
mkdir(descPath);
|
||||
writeBuff(typePath, ox::bit_cast<uint8_t*>(typeOut.value.data()), typeOut.value.size());
|
||||
emit fileUpdated(path);
|
||||
}
|
||||
|
||||
@ -104,7 +118,7 @@ template<typename T>
|
||||
std::unique_ptr<T> Project::loadObj(QString path) const {
|
||||
auto obj = std::make_unique<T>();
|
||||
auto buff = loadBuff(path);
|
||||
oxThrowError(ox::readMC<T>(buff.data(), buff.size(), obj.get()));
|
||||
oxThrowError(ox::readClaw<T>(buff.data(), buff.size(), obj.get()));
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -15,12 +15,26 @@
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "context.hpp"
|
||||
#include "project.hpp"
|
||||
#include "plugin.hpp"
|
||||
#include "wizard.hpp"
|
||||
|
||||
namespace nostalgia::studio {
|
||||
|
||||
using std::function;
|
||||
PathExistsValidator::PathExistsValidator(const Context *ctx, QString pathTemplate, bool shouldExist) {
|
||||
m_ctx = ctx;
|
||||
m_pathTemplate = pathTemplate;
|
||||
m_shouldExist = shouldExist;
|
||||
}
|
||||
|
||||
QValidator::State PathExistsValidator::validate(QString &input, int&) const {
|
||||
auto path = m_pathTemplate.arg(input);
|
||||
if (m_ctx->project->exists(path) == m_shouldExist) {
|
||||
return QValidator::Acceptable;
|
||||
}
|
||||
return QValidator::Invalid;
|
||||
}
|
||||
|
||||
WizardSelect::WizardSelect() {
|
||||
m_listWidget = new QListWidget(this);
|
||||
@ -203,7 +217,7 @@ QComboBox *WizardFormPage::addComboBox(QString displayName, QString fieldName, Q
|
||||
return cb;
|
||||
}
|
||||
|
||||
QLineEdit *WizardFormPage::addLineEdit(QString displayName, QString fieldName, QString defaultVal, function<int(QString)> validator) {
|
||||
QLineEdit *WizardFormPage::addLineEdit(QString displayName, QString fieldName, QString defaultVal, std::function<int(QString)> validator) {
|
||||
auto lbl = new QLabel(displayName, this);
|
||||
auto le = new QLineEdit(this);
|
||||
lbl->setBuddy(le);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QMap>
|
||||
#include <QValidator>
|
||||
#include <QVector>
|
||||
#include <QWizard>
|
||||
|
||||
@ -25,6 +26,19 @@
|
||||
|
||||
namespace nostalgia::studio {
|
||||
|
||||
class PathExistsValidator: public QValidator {
|
||||
private:
|
||||
const class Context *m_ctx = nullptr;
|
||||
QString m_pathTemplate;
|
||||
bool m_shouldExist = true;
|
||||
|
||||
public:
|
||||
PathExistsValidator(const class Context *ctx, QString pathTemplate, bool shouldExist);
|
||||
|
||||
QValidator::State validate(QString &input, int &pos) const override;
|
||||
|
||||
};
|
||||
|
||||
struct NOSTALGIASTUDIO_EXPORT WizardMaker {
|
||||
QString name;
|
||||
std::function<QVector<QWizardPage*>()> make;
|
||||
|
@ -29,7 +29,9 @@ OxFSFile::OxFSFile(PassThroughFS *fs, QString path, OxFSFile *parentItem) {
|
||||
if (!stat.error) {
|
||||
if (stat.value.fileType == FileType_Directory) {
|
||||
fs->ls(m_path.toUtf8(), [&ls](const char *name, ox::InodeId_t) {
|
||||
ls.push_back(name);
|
||||
if (name[0] != '.') {
|
||||
ls.push_back(name);
|
||||
}
|
||||
return OxError(0);
|
||||
});
|
||||
std::sort(ls.begin(), ls.end());
|
||||
@ -143,7 +145,7 @@ QVariant OxFSModel::data(const QModelIndex &index, int role) const {
|
||||
|
||||
Qt::ItemFlags OxFSModel::flags(const QModelIndex &index) const {
|
||||
if (!index.isValid()) {
|
||||
return 0;
|
||||
return {};
|
||||
} else {
|
||||
return QAbstractItemModel::flags(index);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
static void writeFileBuff(const std::string &path, std::vector<char> &buff) {
|
||||
try {
|
||||
std::ofstream f(path, std::ios::binary);
|
||||
f.write(buff.data(), buff.size());
|
||||
f.write(buff.data(), static_cast<intptr_t>(buff.size()));
|
||||
} catch (const std::fstream::failure&) {
|
||||
throw OxError(2);
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ add_library(
|
||||
target_link_libraries(
|
||||
NostalgiaPack PUBLIC
|
||||
OxClArgs
|
||||
OxClaw
|
||||
OxFS
|
||||
OxStd
|
||||
OxMetalClaw
|
||||
NostalgiaCommon
|
||||
NostalgiaCore
|
||||
)
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <ox/claw/read.hpp>
|
||||
|
||||
#include "pack.hpp"
|
||||
|
||||
namespace nostalgia {
|
||||
@ -20,6 +22,10 @@ namespace {
|
||||
return str.size() >= ending.size() && str.substr(str.size() - ending.size()) == ending;
|
||||
}
|
||||
|
||||
static_assert(endsWith("asdf", "df"));
|
||||
static_assert(!endsWith("asdf", "awefawe"));
|
||||
static_assert(!endsWith("asdf", "eu"));
|
||||
|
||||
/**
|
||||
* Convert path references to inodes to save space
|
||||
* @param buff buffer holding file
|
||||
@ -31,7 +37,11 @@ namespace {
|
||||
}
|
||||
|
||||
// stub for now
|
||||
[[nodiscard]] ox::Error toMetalClaw(std::vector<uint8_t>*) {
|
||||
[[nodiscard]] ox::Error toMetalClaw(std::vector<uint8_t> *buff) {
|
||||
auto [mc, err] = ox::stripClawHeader(ox::bit_cast<char*>(buff->data()), buff->size());
|
||||
oxReturnError(err);
|
||||
buff->resize(mc.size());
|
||||
ox_memcpy(buff->data(), mc.data(), mc.size());
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
@ -41,22 +51,23 @@ namespace {
|
||||
// copy
|
||||
oxTrace("pack::transformClaw") << "path:" << path.c_str();
|
||||
return dest->ls(path.c_str(), [dest, path](const char *name, ox::InodeId_t) {
|
||||
auto [stat, err] = dest->stat(path.c_str());
|
||||
auto filePath = path + name;
|
||||
auto [stat, err] = dest->stat(filePath.c_str());
|
||||
oxReturnError(err);
|
||||
if (stat.fileType == ox::FileType_Directory) {
|
||||
const auto dir = path + name + '/';
|
||||
oxReturnError(transformClaw(dest, dir));
|
||||
} else {
|
||||
// do transforms
|
||||
if (endsWith(path, ".claw")) {
|
||||
if (endsWith(name, ".ng") || endsWith(name, ".npal")) {
|
||||
// load file
|
||||
std::vector<uint8_t> buff(stat.size);
|
||||
oxReturnError(dest->read(path.c_str(), buff.data(), buff.size()));
|
||||
oxReturnError(dest->read(filePath.c_str(), buff.data(), buff.size()));
|
||||
// do transformations
|
||||
oxReturnError(pathToInode(&buff));
|
||||
oxReturnError(toMetalClaw(&buff));
|
||||
// write file to dest
|
||||
oxReturnError(dest->write(path.c_str(), buff.data(), buff.size()));
|
||||
oxReturnError(dest->write(filePath.c_str(), buff.data(), buff.size()));
|
||||
}
|
||||
}
|
||||
return OxError(0);
|
||||
@ -79,8 +90,11 @@ struct VerificationPair {
|
||||
std::vector<VerificationPair> verficationPairs;
|
||||
// copy
|
||||
oxReturnError(src->ls(path.c_str(), [&verficationPairs, src, dest, path](std::string name, ox::InodeId_t) {
|
||||
std::cout << "reading " << name << '\n';
|
||||
auto currentFile = path + name;
|
||||
if (currentFile == "/.nostalgia") {
|
||||
return OxError(0);
|
||||
}
|
||||
std::cout << "reading " << name << '\n';
|
||||
auto [stat, err] = src->stat((currentFile).c_str());
|
||||
oxReturnError(err);
|
||||
if (stat.fileType == ox::FileType_Directory) {
|
||||
|
@ -14,7 +14,7 @@ using namespace common;
|
||||
using namespace core;
|
||||
|
||||
ox::Error Zone::init(Context *ctx, Bounds bnds, ox::FileAddress tileSheet, ox::FileAddress palette) {
|
||||
const auto size = bnds.width * bnds.height;
|
||||
const auto size = static_cast<std::size_t>(bnds.width * bnds.height);
|
||||
m_tiles = new Tile[size];
|
||||
m_bounds = bnds;
|
||||
return core::loadTileSheet(ctx, core::TileSheetSpace::Background, 0, tileSheet, palette);
|
||||
@ -37,7 +37,7 @@ void Zone::draw(Context *ctx) {
|
||||
}
|
||||
|
||||
std::size_t Zone::size() {
|
||||
return sizeof(Zone) + m_bounds.width * m_bounds.height * sizeof(Tile);
|
||||
return sizeof(Zone) + static_cast<std::size_t>(m_bounds.width * m_bounds.height) * sizeof(Tile);
|
||||
}
|
||||
|
||||
Tile *Zone::tile(int x, int y) {
|
||||
|
@ -66,7 +66,7 @@ struct Zone {
|
||||
template<typename T>
|
||||
ox::Error modelRead(T *io, Zone *obj) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("nostalgia::world::Zone", Zone::Fields);
|
||||
io->setTypeInfo("net.drinkingtea.nostalgia.world.Zone", Zone::Fields);
|
||||
err |= io->field("bounds", &obj->m_bounds);
|
||||
return err;
|
||||
}
|
||||
@ -74,7 +74,7 @@ ox::Error modelRead(T *io, Zone *obj) {
|
||||
template<typename T>
|
||||
ox::Error modelWrite(T *io, Zone *obj) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("nostalgia::world::Zone", Zone::Fields);
|
||||
io->setTypeInfo("net.drinkingtea.nostalgia.world.Zone", Zone::Fields);
|
||||
err |= io->field("bounds", &obj->m_bounds);
|
||||
return err;
|
||||
}
|
||||
@ -99,14 +99,14 @@ struct Region {
|
||||
template<typename T>
|
||||
ox::Error modelRead(T *io, Region*) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("nostalgia::World::Region", Region::Fields);
|
||||
io->setTypeInfo("net.drinkingtea.nostalgia.world.Region", Region::Fields);
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ox::Error modelWrite(T *io, Region*) {
|
||||
auto err = OxError(0);
|
||||
io->setTypeInfo("nostalgia::World::Region", Region::Fields);
|
||||
io->setTypeInfo("net.drinkingtea.nostalgia.world.Region", Region::Fields);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user