diff --git a/deps/ox/.gitignore b/deps/ox/.gitignore new file mode 100644 index 00000000..41c3c78f --- /dev/null +++ b/deps/ox/.gitignore @@ -0,0 +1,5 @@ +build/current +build/gba +build/*-debug +build/*-release +tags diff --git a/deps/ox/.liccor.yml b/deps/ox/.liccor.yml new file mode 100644 index 00000000..55025146 --- /dev/null +++ b/deps/ox/.liccor.yml @@ -0,0 +1,9 @@ +--- +source: +- src +copyright_notice: |- + Copyright 2015 - 2017 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/. diff --git a/deps/ox/.travis.yml b/deps/ox/.travis.yml new file mode 100644 index 00000000..3c7d22c4 --- /dev/null +++ b/deps/ox/.travis.yml @@ -0,0 +1,11 @@ +language: cpp +sudo: false +dist: trusty +compiler: + - clang + - gcc +addons: + apt: + packages: + - cmake +script: ./scripts/cibuild diff --git a/deps/ox/CMakeLists.txt b/deps/ox/CMakeLists.txt new file mode 100644 index 00000000..dc872d29 --- /dev/null +++ b/deps/ox/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 2.8) + +project(Ox) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) +include(address_sanitizer) + +set(OX_BUILD_EXEC "ON" CACHE STRING "Build executables (ON/OFF)") +set(OX_RUN_TESTS "ON" CACHE STRING "Run tests (ON/OFF)") +set(OX_USE_STDLIB "ON" CACHE STRING "Build libraries that need the std lib (ON/OFF)") + +# can't run tests without building them +if(OX_BUILD_EXEC STREQUAL "OFF" OR OX_USE_STDLIB STREQUAL "OFF") + set(OX_BUILD_EXEC "OFF") + set(OX_RUN_TESTS "OFF") +endif() + +if(NOT MSVC) + add_definitions( + -std=c++11 + -Wall + -nostdlib + -fno-exceptions + -fno-rtti + -Wsign-compare + -Wunused-variable + #--analyze + #-Os # GCC size optimization flag + ) + + if (CMAKE_BUILD_TYPE STREQUAL "Release") + add_definitions( + -Werror + ) + endif() +endif(NOT MSVC) + +enable_testing() + +include_directories("src") + +install(FILES OxConfig.cmake DESTINATION lib/ox) + +add_subdirectory(src) diff --git a/deps/ox/LICENSE b/deps/ox/LICENSE new file mode 100644 index 00000000..14e2f777 --- /dev/null +++ b/deps/ox/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + 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/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/deps/ox/Makefile b/deps/ox/Makefile new file mode 100644 index 00000000..3c2b781f --- /dev/null +++ b/deps/ox/Makefile @@ -0,0 +1,72 @@ +OS=$(shell uname | tr [:upper:] [:lower:]) +HOST_ENV=${OS}-$(shell uname -m) +DEVENV=devenv$(shell pwd | sed 's/\//-/g') +DEVENV_IMAGE=wombatant/devenv +ifneq ($(shell which gmake),) + MAKE=gmake -s +else + MAKE=make -s +endif +ifneq ($(shell which docker 2>&1),) + ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running) + ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV} + endif +endif + +make: + ${ENV_RUN} ${MAKE} -j -C build HOST_ENV=${HOST_ENV} +preinstall: + ${ENV_RUN} ${MAKE} -j -C build ARGS="preinstall" HOST_ENV=${HOST_ENV} +install: + ${ENV_RUN} ${MAKE} -j -C build ARGS="install" HOST_ENV=${HOST_ENV} +clean: + ${ENV_RUN} ${MAKE} -j -C build ARGS="clean" HOST_ENV=${HOST_ENV} +purge: + ${ENV_RUN} rm -rf $(shell find build -mindepth 1 -maxdepth 1 -type d) +test: + ${ENV_RUN} ${MAKE} -j -C build ARGS="test" HOST_ENV=${HOST_ENV} +run: make + ./build/current/src/wombat/wombat -debug +gdb: make + gdb ./build/current/src/wombat/wombat + +devenv: + docker pull ${DEVENV_IMAGE} + docker run -d -v $(shell pwd):/usr/src/project \ + -e LOCAL_USER_ID=$(shell id -u ${USER}) \ + --name ${DEVENV} -t ${DEVENV_IMAGE} bash +devenv-destroy: + docker rm -f ${DEVENV} + +shell: + ${ENV_RUN} bash + +release: + ${ENV_RUN} rm -rf build/${HOST_ENV}-release + ${ENV_RUN} ./scripts/setup_build ${HOST_ENV} + ${ENV_RUN} rm -f build/current + ${ENV_RUN} ln -s ${HOST_ENV}-release build/current + +debug: + ${ENV_RUN} rm -rf build/${HOST_ENV}-debug + ${ENV_RUN} ./scripts/setup_build ${HOST_ENV} debug + ${ENV_RUN} rm -f build/current + ${ENV_RUN} ln -s ${HOST_ENV}-debug build/current + +windows: + ${ENV_RUN} rm -rf build/windows + ${ENV_RUN} ./scripts/setup_build windows + ${ENV_RUN} rm -f build/current + ${ENV_RUN} ln -s windows build/current + +windows-debug: + ${ENV_RUN} rm -rf build/windows + ${ENV_RUN} ./scripts/setup_build windows debug + ${ENV_RUN} rm -f build/current + ${ENV_RUN} ln -s windows build/current + +gba: + ${ENV_RUN} rm -rf build/gba-release + ${ENV_RUN} ./scripts/setup_build gba + ${ENV_RUN} rm -f build/current + ${ENV_RUN} ln -s gba-release build/current diff --git a/deps/ox/OxConfig.cmake b/deps/ox/OxConfig.cmake new file mode 100644 index 00000000..6312e31c --- /dev/null +++ b/deps/ox/OxConfig.cmake @@ -0,0 +1,11 @@ +if("${CMAKE_FIND_ROOT_PATH}" STREQUAL "") + set(Ox_INCLUDE_DIRS /usr/local/include/) + set(OxStd_LIBRARY /usr/local/lib/ox/libOxStd.a) + set(OxFS_LIBRARY /usr/local/lib/ox/libOxFS.a) + set(OxClArgs_LIBRARY /usr/local/lib/ox/libOxClArgs.a) +else("${CMAKE_FIND_ROOT_PATH}" STREQUAL "") + set(Ox_INCLUDE_DIRS ${CMAKE_FIND_ROOT_PATH}/include/) + set(OxStd_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxStd.a) + set(OxFS_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxFS.a) + set(OxClArgs_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxClArgs.a) +endif("${CMAKE_FIND_ROOT_PATH}" STREQUAL "") diff --git a/deps/ox/build/Makefile b/deps/ox/build/Makefile new file mode 100644 index 00000000..a1bd3c20 --- /dev/null +++ b/deps/ox/build/Makefile @@ -0,0 +1,32 @@ +ifneq ($(shell which gmake),) + MAKE=gmake -j +else + MAKE=make +endif + +all: gba_build native_build native_debug_build windows_release windows_debug + +gba_build: + @if [ -d gba-release ]; then \ + ${MAKE} -C gba-release ${ARGS}; \ + fi + +native_build: + @if [ -d ${HOST_ENV}-release ]; then \ + ${MAKE} -C ${HOST_ENV}-release ${ARGS}; \ + fi + +native_debug_build: + @if [ -d ${HOST_ENV}-debug ]; then \ + ${MAKE} -C ${HOST_ENV}-debug ${ARGS}; \ + fi + +windows_release: + @if [ -d windows-release ]; then \ + ${MAKE} -C windows-release ${ARGS}; \ + fi + +windows_debug: + @if [ -d windows-debug ]; then \ + ${MAKE} -C windows-debug ${ARGS}; \ + fi diff --git a/deps/ox/cmake/Modules/FindJansson.cmake b/deps/ox/cmake/Modules/FindJansson.cmake new file mode 100644 index 00000000..19ee0774 --- /dev/null +++ b/deps/ox/cmake/Modules/FindJansson.cmake @@ -0,0 +1,49 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +# - Try to find Jansson +# Once done this will define +# JANSSON_FOUND - System has Jansson +# JANSSON_INCLUDE_DIRS - The Jansson include directories +# JANSSON_LIBRARIES - The libraries needed to use Jansson +# JANSSON_DEFINITIONS - Compiler switches required for using Jansson + +find_path(JANSSON_INCLUDE_DIR jansson.h + PATHS + /usr/include + /usr/local/include +) + +find_library(JANSSON_LIBRARY + NAMES + jansson + PATHS + /usr/lib + /usr/local/lib +) + +set(JANSSON_LIBRARIES ${JANSSON_LIBRARY}) +set(JANSSON_INCLUDE_DIRS ${JANSSON_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set JANSSON_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(Jansson DEFAULT_MSG + JANSSON_LIBRARY JANSSON_INCLUDE_DIR) + +mark_as_advanced(JANSSON_INCLUDE_DIR JANSSON_LIBRARY) diff --git a/deps/ox/cmake/Modules/GBA.cmake b/deps/ox/cmake/Modules/GBA.cmake new file mode 100644 index 00000000..6440e228 --- /dev/null +++ b/deps/ox/cmake/Modules/GBA.cmake @@ -0,0 +1,41 @@ +set(CMAKE_SYSTEM_NAME "Generic") + +set(DEVKITARM $ENV{DEVKITARM}) +set(DEVKITPRO $ENV{DEVKITPRO}) + +if(NOT DEVKITPRO) + message(FATAL_ERROR "DEVKITPRO environment variable not set") +endif() + +if(NOT DEVKITARM) + message(FATAL_ERROR "DEVKITARM environment variable not set") +endif() + +set(CMAKE_C_COMPILER ${DEVKITARM}/bin/arm-none-eabi-gcc) +set(CMAKE_CXX_COMPILER ${DEVKITARM}/bin/arm-none-eabi-g++) +set(CMAKE_FIND_ROOT_PATH ${DEVKITARM} ${DEVKITPRO}/libgba) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + +set(CMAKE_FIND_LIBRARY_PREFIXES lib) +set(CMAKE_FIND_LIBRARY_SUFFIXES .a) + +set(LINKER_FLAGS "-specs=gba.specs") +add_definitions ( + -DARM7 +) + +find_library(GBA_LIBRARY + NAMES + gba + PATHS + /lib +) +find_path(GBA_INCLUDE_DIR gba.h + PATHS + /include +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(GBA DEFAULT_MSG GBA_LIBRARY) diff --git a/deps/ox/cmake/Modules/Mingw.cmake b/deps/ox/cmake/Modules/Mingw.cmake new file mode 100644 index 00000000..bf1d08f1 --- /dev/null +++ b/deps/ox/cmake/Modules/Mingw.cmake @@ -0,0 +1,18 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) + +# cross compilers to use for C and C++ +set(CMAKE_C_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-gcc) +set(CMAKE_CXX_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-g++) +set(CMAKE_RC_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-windres) + +# target environment on the build host system +# set 1st to dir with the cross compiler's C/C++ headers/libs +set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) + +# modify default behavior of FIND_XXX() commands to +# search for headers/libs in the target environment and +# search for programs in the build host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/deps/ox/cmake/Modules/address_sanitizer.cmake b/deps/ox/cmake/Modules/address_sanitizer.cmake new file mode 100644 index 00000000..f1076b24 --- /dev/null +++ b/deps/ox/cmake/Modules/address_sanitizer.cmake @@ -0,0 +1,52 @@ +# This file belongs Nick Overdijk, and is from https://github.com/NickNick/wubwubcmake +# The MIT License (MIT) +# +# Copyright (c) 2013 Nick Overdijk +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" ON) + +option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" OFF) +if(USE_ASAN) + include(CheckCXXSourceCompiles) + # If the compiler understands -fsanitize=address, add it to the flags (gcc since 4.8 & clang since version 3.2) + set(CMAKE_REQUIRED_FLAGS_BAK "${CMAKE_REQUIRED_FLAGS}") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fsanitize=address") + CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FSANA_SUPPORTED) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}") + + if(FLAG_FSANA_SUPPORTED) + set(asan_flag "-fsanitize=address") + else(FLAG_FSANA_SUPPORTED) + # Alternatively, try if it understands -faddress-sanitizer (clang until version 3.2) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -faddress-sanitizer") + CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FASAN_SUPPORTED) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}") + + if(FLAG_FASAN_SUPPORTED) + set(asan_flag "-faddress-sanitizer") + endif(FLAG_FASAN_SUPPORTED) + endif(FLAG_FSANA_SUPPORTED) + + if(FLAG_FSANA_SUPPORTED OR FLAG_FASAN_SUPPORTED) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${asan_flag}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${asan_flag}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${asan_flag}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${asan_flag}") + endif() + +endif(USE_ASAN) diff --git a/deps/ox/scripts/cibuild b/deps/ox/scripts/cibuild new file mode 100755 index 00000000..236a44cb --- /dev/null +++ b/deps/ox/scripts/cibuild @@ -0,0 +1,8 @@ +#! /usr/bin/env bash + +set -e + +make -j release +make -j debug +make -j +make -j test diff --git a/deps/ox/scripts/setup_build b/deps/ox/scripts/setup_build new file mode 100755 index 00000000..f416aa15 --- /dev/null +++ b/deps/ox/scripts/setup_build @@ -0,0 +1,30 @@ +#! /usr/bin/env bash + +set -e + +project=$(pwd)/ + +TARGET=$1 +BUILD_TYPE=$2 + +if [[ $TARGET == windows ]]; then + toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/Modules/Mingw.cmake" +elif [[ $TARGET == gba ]]; then + toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/Modules/GBA.cmake -DOX_USE_STDLIB=OFF -DCMAKE_INSTALL_PREFIX=$DEVKITARM" +fi + +if [[ $BUILD_TYPE == debug ]]; then + buildTypeArgs="-DUSE_ASAN=ON -DCMAKE_BUILD_TYPE=Debug" + buildDir="build/${TARGET}-debug" +else + buildTypeArgs="-DCMAKE_BUILD_TYPE=Release" + buildDir="build/${TARGET}-release" +fi + +mkdir -p $buildDir +pushd $buildDir +cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + $buildTypeArgs \ + $toolchain \ + $project +popd diff --git a/deps/ox/src/CMakeLists.txt b/deps/ox/src/CMakeLists.txt new file mode 100644 index 00000000..81ecf243 --- /dev/null +++ b/deps/ox/src/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8) + +add_subdirectory(ox) diff --git a/deps/ox/src/ox/CMakeLists.txt b/deps/ox/src/ox/CMakeLists.txt new file mode 100644 index 00000000..3dcead2c --- /dev/null +++ b/deps/ox/src/ox/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.8) + +if(OX_USE_STDLIB STREQUAL "ON") + add_subdirectory(clargs) +endif(OX_USE_STDLIB STREQUAL "ON") +add_subdirectory(fs) +add_subdirectory(log) +add_subdirectory(mc) +add_subdirectory(std) diff --git a/deps/ox/src/ox/clargs/CMakeLists.txt b/deps/ox/src/ox/clargs/CMakeLists.txt new file mode 100644 index 00000000..a096079c --- /dev/null +++ b/deps/ox/src/ox/clargs/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 2.8) + +add_library( + OxClArgs + clargs.cpp +) + +set_property( + TARGET + OxClArgs + PROPERTY + POSITION_INDEPENDENT_CODE ON +) + +install( + FILES + clargs.hpp + DESTINATION + include/ox/clargs +) + +install( + TARGETS + OxClArgs + LIBRARY DESTINATION lib/ox + ARCHIVE DESTINATION lib/ox +) diff --git a/deps/ox/src/ox/clargs/clargs.cpp b/deps/ox/src/ox/clargs/clargs.cpp new file mode 100644 index 00000000..c028e308 --- /dev/null +++ b/deps/ox/src/ox/clargs/clargs.cpp @@ -0,0 +1,53 @@ +/* + * Copyright 2015 - 2017 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 +#include "clargs.hpp" + +namespace ox { + +using namespace ::std; + +ClArgs::ClArgs(int argc, const char **args) { + for (int i = 0; i < argc; i++) { + string arg = args[i]; + if (arg[0] == '-') { + while (arg[0] == '-' && arg.size()) { + arg = arg.substr(1); + } + m_bools[arg] = true; + + // parse additional arguments + if (i < argc && args[i + 1]) { + string val = args[i + 1]; + if (val.size() && val[i] != '-') { + if (val == "false") { + m_bools[arg] = false; + } + m_strings[arg] = val; + m_ints[arg] = ox_atoi(val.c_str()); + i++; + } + } + } + } +} + +bool ClArgs::getBool(const char *arg) { + return m_bools[arg]; +} + +string ClArgs::getString(const char *arg) { + return m_strings[arg]; +} + +int ClArgs::getInt(const char *arg) { + return m_ints[arg]; +} + +} diff --git a/deps/ox/src/ox/clargs/clargs.hpp b/deps/ox/src/ox/clargs/clargs.hpp new file mode 100644 index 00000000..4b7b740f --- /dev/null +++ b/deps/ox/src/ox/clargs/clargs.hpp @@ -0,0 +1,32 @@ +/* + * Copyright 2015 - 2017 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 +#include + +namespace ox { + +class ClArgs { + private: + ::std::map<::std::string, bool> m_bools; + ::std::map<::std::string, ::std::string> m_strings; + ::std::map<::std::string, int> m_ints; + + public: + ClArgs(int argc, const char **args); + + bool getBool(const char *arg); + + ::std::string getString(const char *arg); + + int getInt(const char *arg); +}; + +} diff --git a/deps/ox/src/ox/fs/CMakeLists.txt b/deps/ox/src/ox/fs/CMakeLists.txt new file mode 100644 index 00000000..5c333217 --- /dev/null +++ b/deps/ox/src/ox/fs/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 2.8) + +add_library( + OxFS + filesystem.cpp + pathiterator.cpp +) + +set_property( + TARGET + OxFS + PROPERTY + POSITION_INDEPENDENT_CODE ON +) + +if(OX_BUILD_EXEC STREQUAL "ON") + add_executable( + oxfstool + toollib.cpp + oxfstool.cpp + ) + set_target_properties(oxfstool PROPERTIES OUTPUT_NAME oxfs) + target_link_libraries( + oxfstool + OxFS + OxLog + OxStd + ) +endif() + +install( + FILES + filestore.hpp + filesystem.hpp + pathiterator.hpp + DESTINATION + include/ox/fs +) + +install( + TARGETS + OxFS + LIBRARY DESTINATION lib/ox + ARCHIVE DESTINATION lib/ox +) + +if(OX_BUILD_EXEC STREQUAL "ON") + if(OX_RUN_TESTS STREQUAL "ON") + add_subdirectory(test) + endif() + install(TARGETS oxfstool + RUNTIME DESTINATION bin + ) +endif() diff --git a/deps/ox/src/ox/fs/filestore.hpp b/deps/ox/src/ox/fs/filestore.hpp new file mode 100644 index 00000000..99092bd9 --- /dev/null +++ b/deps/ox/src/ox/fs/filestore.hpp @@ -0,0 +1,923 @@ +/* + * Copyright 2015 - 2017 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 + +namespace ox { + +template +struct __attribute__((packed)) FileStoreHeader { + public: + typedef InodeId InodeId_t; + typedef FsT FsSize_t; + const static auto VERSION = 6; + + private: + uint16_t m_version; + uint16_t m_fsType; + FsSize_t m_size; + FsSize_t m_memUsed; + FsSize_t m_rootInode; + + public: + void setVersion(uint16_t); + uint16_t getVersion(); + + void setFsType(uint16_t); + uint16_t getFsType(); + + void setSize(FsSize_t); + FsSize_t getSize(); + + void setMemUsed(FsSize_t); + FsSize_t getMemUsed(); + + void setRootInode(FsSize_t); + FsSize_t getRootInode(); +}; + +template +void FileStoreHeader::setVersion(uint16_t version) { + m_version = bigEndianAdapt(version); +} + +template +uint16_t FileStoreHeader::getVersion() { + return bigEndianAdapt(m_version); +} + +template +void FileStoreHeader::setFsType(uint16_t fsType) { + m_fsType = bigEndianAdapt(fsType); +} + +template +uint16_t FileStoreHeader::getFsType() { + return bigEndianAdapt(m_fsType); +} + +template +void FileStoreHeader::setSize(FsSize_t size) { + m_size = bigEndianAdapt(size); +} + +template +FsSize_t FileStoreHeader::getSize() { + return bigEndianAdapt(m_size); +} + +template +void FileStoreHeader::setMemUsed(FsSize_t memUsed) { + m_memUsed = bigEndianAdapt(memUsed); +} + +template +FsSize_t FileStoreHeader::getMemUsed() { + return bigEndianAdapt(m_memUsed); +} + +template +void FileStoreHeader::setRootInode(FsSize_t rootInode) { + m_rootInode = bigEndianAdapt(rootInode); +} + +template +FsSize_t FileStoreHeader::getRootInode() { + return bigEndianAdapt(m_rootInode); +} + +template +class FileStore { + + public: + typedef typename Header::InodeId_t InodeId_t; + typedef typename Header::FsSize_t FsSize_t; + const static auto VERSION = Header::VERSION; + + struct StatInfo { + InodeId_t inodeId; + InodeId_t links; + typename Header::FsSize_t size; + uint8_t fileType; + }; + + private: + struct __attribute__((packed)) Inode { + private: + // the next Inode in memory + typename Header::FsSize_t m_prev; + typename Header::FsSize_t m_next; + typename Header::FsSize_t m_dataLen; + + InodeId_t m_id; + InodeId_t m_links; + uint8_t m_fileType; + typename Header::FsSize_t m_left; + typename Header::FsSize_t m_right; + + public: + typename Header::FsSize_t size(); + + void setDataLen(typename Header::FsSize_t); + typename Header::FsSize_t getDataLen(); + + void setPrev(typename Header::FsSize_t); + typename Header::FsSize_t getPrev(); + + void setNext(typename Header::FsSize_t); + typename Header::FsSize_t getNext(); + + void setId(InodeId_t); + InodeId_t getId(); + + void setLinks(InodeId_t); + InodeId_t getLinks(); + + void setFileType(uint8_t); + uint8_t getFileType(); + + void setLeft(typename Header::FsSize_t); + typename Header::FsSize_t getLeft(); + + void setRight(typename Header::FsSize_t); + typename Header::FsSize_t getRight(); + + void setData(void *data, typename Header::FsSize_t size); + uint8_t *getData(); + }; + + Header m_header; + + public: + /** + * Dumps this file store's inodes to the given file store. + */ + int dumpTo(FileStore
*dest); + + /** + * Compacts and resizes the file store to the minimum possible size for + * the contents. + * + * NOTE: This does NOT resize the buffer that this file store refers to! + */ + void resize(typename Header::FsSize_t size = 0); + + /** + * Writes the given data to a "file" with the given id. + * @param id the id of the file + * @param data the contents of the file + * @param dataLen the number of bytes data points to + */ + int write(InodeId_t id, void *data, typename Header::FsSize_t dataLen, uint8_t fileType = 0); + + /** + * Removes the inode of the given ID. + * @param id the id of the file + */ + int remove(InodeId_t id); + + /** + * Increments the links of the inode of the given ID. + * @param id the id of the inode + */ + int incLinks(InodeId_t id); + + /** + * Decrements the links of the inode of the given ID. + * @param id the id of the inode + */ + int decLinks(InodeId_t id); + + /** + * Removes all inodes of the type. + * @param fileType the type of file to remove + */ + int removeAllType(uint8_t fileType); + + /** + * Reads the "file" at the given id. You are responsible for freeing + * the data when done with it. + * @param id id of the "file" + * @param data pointer to the pointer where the data is stored + * @param size pointer to a value that will be assigned the size of data + * @return 0 if read is a success + */ + int read(InodeId_t id, void *data, typename Header::FsSize_t *size); + + /** + * Reads the "file" at the given id. You are responsible for freeing + * the data when done with it. + * @param id id of the "file" + * @param readStart where in the data to start reading + * @param readSize how much data to read + * @param data pointer to the pointer where the data is stored + * @param size pointer to a value that will be assigned the size of data + * @return 0 if read is a success + */ + int read(InodeId_t id, typename Header::FsSize_t readStart, + typename Header::FsSize_t readSize, void *data, + typename Header::FsSize_t *size); + + /** + * Reads the "file" at the given id. You are responsible for freeing + * the data when done with it. + * @param id id of the "file" + * @param readStart where in the data to start reading + * @param readSize how much data to read + * @param data pointer to the pointer where the data is stored + * @param size pointer to a value that will be assigned the size of data + * @return 0 if read is a success + */ + template + int read(InodeId_t id, typename Header::FsSize_t readStart, + typename Header::FsSize_t readSize, T *data, + typename Header::FsSize_t *size); + + /** + * Reads the stat information of the inode of the given inode id. + * If the returned inode id is 0, then the requested inode was not found. + * @param id id of the inode to stat + * @return the stat information of the inode of the given inode id + */ + StatInfo stat(InodeId_t id); + + /** + * Returns the space needed for this data at the given inode address. + * @param id the target inode id + * @param size the size of the data to insert + * @return the space currently available in this file store. + */ + typename Header::FsSize_t spaceNeeded(typename Header::FsSize_t size); + + /** + * Returns the size of the file store. + * @return the size of the file store. + */ + typename Header::FsSize_t size(); + + /** + * Returns the space currently available in this file store. + * @return the space currently available in this file store. + */ + typename Header::FsSize_t available(); + + void walk(int(*cb)(const char*, uint64_t start, uint64_t end)); + + uint16_t fsType(); + + uint16_t version(); + + static uint8_t *format(uint8_t *buffer, typename Header::FsSize_t size, uint16_t fsType = 0); + + private: + /** + * Gets the inode at the given id. + * @param root the root node to start comparing on + * @param id id of the "file" + * @param pathLen number of characters in pathLen + * @return the requested Inode, if available + */ + Inode *getInode(Inode *root, InodeId_t id); + + /** + * Gets the parent inode at the given id. + * @param root the root node to start comparing on + * @param id id of the "file" + * @param pathLen number of characters in pathLen + * @param targetAddr the address of the target inode + * @return the requested Inode, if available + */ + Inode *getInodeParent(Inode *root, InodeId_t id, typename Header::FsSize_t targetAddr); + + /** + * Reads the "file" at the given id. You are responsible for freeing + * the data when done with it. + * @param inode inode of the "file" + * @param readStart where in the data to start reading + * @param readSize how much data to read + * @param data pointer to the pointer where the data is stored + * @param size pointer to a value that will be assigned the size of data + * @return 0 if read is a success + */ + template + int read(Inode *inode, typename Header::FsSize_t readStart, + typename Header::FsSize_t readSize, T *data, + typename Header::FsSize_t *size); + + /** + * Removes the inode of the given ID. + * @param id the id of the file + */ + int remove(Inode *root, InodeId_t id); + + /** + * Removes the given node from the linked list. + * @param node node to remove + */ + void dealloc(Inode *node); + + /** + * Gets the address of the next available inode, assuming there is a next + * available inode. + */ + typename Header::FsSize_t nextInodeAddr(); + + /** + * Gets an address for a new Inode. + * @param size the size of the Inode + */ + void *alloc(typename Header::FsSize_t size); + + /** + * Compacts all of the inodes into a contiguous space, starting at the first inode. + */ + void compact(); + + /** + * Inserts the given insertValue into the tree of the given root. + * If the inode already exists, it replaces the old on deletes it. + * @return true if the inode was inserted + */ + bool insert(Inode *root, Inode *insertValue); + + typename Header::FsSize_t firstInode(); + + typename Header::FsSize_t lastInode(); + + /** + * Updates the address of the inode in the tree. + */ + void updateInodeAddress(InodeId_t id, typename Header::FsSize_t oldAddr, typename Header::FsSize_t newAddr); + + uint8_t *begin() { + return (uint8_t*) this; + } + + uint8_t *end() { + return begin() + this->m_header.getSize(); + } + + /** + * Converts an actual pointer to a FsSize_t. + */ + typename Header::FsSize_t ptr(void *ptr); + + /** + * Converts a FsSize_t to an actual pointer. + */ + template + T ptr(typename Header::FsSize_t ptr) { + return (T) (begin() + ptr); + }; + +}; + +template +typename Header::FsSize_t FileStore
::Inode::size() { + return sizeof(Inode) + getDataLen(); +} + +template +void FileStore
::Inode::setDataLen(typename Header::FsSize_t dataLen) { + this->m_dataLen = bigEndianAdapt(dataLen); +} + +template +typename Header::FsSize_t FileStore
::Inode::getDataLen() { + return bigEndianAdapt(m_dataLen); +} + +template +void FileStore
::Inode::setPrev(typename Header::FsSize_t prev) { + this->m_prev = bigEndianAdapt(prev); +} + +template +typename Header::FsSize_t FileStore
::Inode::getPrev() { + return bigEndianAdapt(m_prev); +} + +template +void FileStore
::Inode::setNext(typename Header::FsSize_t next) { + this->m_next = bigEndianAdapt(next); +} + +template +typename Header::FsSize_t FileStore
::Inode::getNext() { + return bigEndianAdapt(m_next); +} + +template +void FileStore
::Inode::setId(InodeId_t id) { + this->m_id = bigEndianAdapt(id); +} + +template +typename Header::InodeId_t FileStore
::Inode::getId() { + return bigEndianAdapt(m_id); +} + +template +void FileStore
::Inode::setLinks(InodeId_t links) { + this->m_links = bigEndianAdapt(links); +} + +template +typename Header::InodeId_t FileStore
::Inode::getLinks() { + return bigEndianAdapt(m_links); +} + +template +void FileStore
::Inode::setFileType(uint8_t fileType) { + this->m_fileType = bigEndianAdapt(fileType); +} + +template +uint8_t FileStore
::Inode::getFileType() { + return bigEndianAdapt(m_fileType); +} + +template +void FileStore
::Inode::setLeft(typename Header::FsSize_t left) { + this->m_left = bigEndianAdapt(left); +} + +template +typename Header::FsSize_t FileStore
::Inode::getLeft() { + return bigEndianAdapt(m_left); +} + +template +void FileStore
::Inode::setRight(typename Header::FsSize_t right) { + this->m_right = bigEndianAdapt(right); +} + +template +typename Header::FsSize_t FileStore
::Inode::getRight() { + return bigEndianAdapt(m_right); +} + +template +void FileStore
::Inode::setData(void *data, typename Header::FsSize_t size) { + ox_memcpy(getData(), data, size); + setDataLen(size); +} + +template +uint8_t *FileStore
::Inode::getData() { + return (uint8_t*) (this + 1); +} + + +// FileStore + +template +int FileStore
::dumpTo(FileStore
*dest) { + if (dest->size() >= size()) { + auto i = ptr(firstInode()); + do { + dest->write(i->getId(), i->getData(), i->getDataLen(), i->getFileType()); + i = ptr(i->getNext()); + } while (ptr(i) != firstInode()); + return 0; + } else { + return -1; + } +} + +template +void FileStore
::resize(typename Header::FsSize_t size) { + if (size < m_header.getSize()) { + // shrink file store + if (m_header.getMemUsed() > size) { + size = m_header.getMemUsed(); + } + compact(); + m_header.setSize(size); + } else if (size > m_header.getSize()) { + // grow file store + m_header.setSize(size); + } +} + +template +int FileStore
::write(InodeId_t id, void *data, typename Header::FsSize_t dataLen, uint8_t fileType) { + auto retval = 1; + const typename Header::FsSize_t size = sizeof(Inode) + dataLen; + if (size <= (m_header.getSize() - m_header.getMemUsed())) { + auto inode = (Inode*) alloc(size); + if (inode) { + remove(id); + inode->setId(id); + inode->setFileType(fileType); + inode->setData(data, dataLen); + auto root = ptr(m_header.getRootInode()); + if (insert(root, inode) || root == inode) { + retval = 0; + } else { + dealloc(inode); + retval = 2; + } + } else { + retval = 3; + } + } else { + retval = 4; + } + return retval; +} + +template +int FileStore
::remove(InodeId_t id) { + return remove(ptr(m_header.getRootInode()), id); +} + +/** + * Increments the links of the inode of the given ID. + * @param id the id of the inode + */ +template +int FileStore
::incLinks(InodeId_t id) { + auto inode = getInode(ptr(m_header.getRootInode()), id); + if (inode) { + inode->setLinks(inode->getLinks() + 1); + return 0; + } else { + return 1; + } +} + +/** + * Decrements the links of the inode of the given ID. + * @param id the id of the inode + */ +template +int FileStore
::decLinks(InodeId_t id) { + auto inode = getInode(ptr(m_header.getRootInode()), id); + if (inode) { + inode->setLinks(inode->getLinks() - 1); + return 0; + } else { + return 1; + } +} + +template +int FileStore
::remove(Inode *root, InodeId_t id) { + auto err = 1; + + if (root->getId() > id) { + if (root->getLeft()) { + auto left = ptr(root->getLeft()); + if (left->getId() != id) { + err = remove(left, id); + } else { + root->setLeft(0); + // pass children to parent + if (left->getRight()) { + insert(root, ptr(left->getRight())); + } + if (left->getLeft()) { + insert(root, ptr(left->getLeft())); + } + dealloc(left); + err = 0; + } + } + } else if (root->getId() < id) { + if (root->getRight()) { + auto right = ptr(root->getRight()); + if (right->getId() != id) { + err = remove(right, id); + } else { + root->setRight(0); + // pass children to parent + if (right->getRight()) { + insert(root, ptr(right->getRight())); + } + if (right->getLeft()) { + insert(root, ptr(right->getLeft())); + } + dealloc(right); + err = 0; + } + } + } else if (ptr(m_header.getRootInode())->getId() == id) { + m_header.setRootInode(root->getRight()); + if (root->getLeft()) { + insert(ptr(m_header.getRootInode()), ptr(root->getLeft())); + } + dealloc(root); + err = 0; + } + + return err; +} + +template +int FileStore
::removeAllType(uint8_t fileType) { + int err = 0; + auto first = ptr(firstInode()); + // skip the first inode for now, because removing the first inode will cause compact to run + auto current = first; + auto next = ptr(current->getNext()); + + while (next != first) { + current = next; + // get next before current is possibly cleared + next = ptr(current->getNext()); + + if (current->getFileType() == fileType) { + err |= remove(current->getId()); + } + } + + if (first->getFileType() == fileType) { + err |= remove(first->getId()); + } + + return err; +} + +template +void FileStore
::dealloc(Inode *inode) { + auto next = ptr(inode->getNext()); + auto prev = ptr(inode->getPrev()); + prev->setNext(ptr(next)); + next->setPrev(ptr(prev)); + + m_header.setMemUsed(m_header.getMemUsed() - inode->size()); + + ox_memset(inode, 0, inode->size()); +} + +template +void FileStore
::updateInodeAddress(InodeId_t id, typename Header::FsSize_t oldAddr, typename Header::FsSize_t newAddr) { + auto parent = getInodeParent(ptr(m_header.getRootInode()), id, oldAddr); + if (parent) { + if (parent->getLeft() == oldAddr) { + parent->setLeft(newAddr); + } else if (parent->getRight() == oldAddr) { + parent->setRight(newAddr); + } + } +} + +template +int FileStore
::read(InodeId_t id, void *data, typename Header::FsSize_t *size) { + auto inode = getInode(ptr(m_header.getRootInode()), id); + return inode ? read(inode, 0, inode->getDataLen(), (uint8_t*) data, size) : 1; +} + +template +int FileStore
::read(InodeId_t id, typename Header::FsSize_t readStart, + typename Header::FsSize_t readSize, void *data, typename Header::FsSize_t *size) { + auto inode = getInode(ptr(m_header.getRootInode()), id); + return inode ? read(inode, readStart, readSize, (uint8_t*) data, size) : 1; +} + +template +template +int FileStore
::read(InodeId_t id, typename Header::FsSize_t readStart, + typename Header::FsSize_t readSize, T *data, typename Header::FsSize_t *size) { + auto inode = getInode(ptr(m_header.getRootInode()), id); + return inode ? read(inode, readStart, readSize, data, size) : 1; +} + +template +template +int FileStore
::read(Inode *inode, typename Header::FsSize_t readStart, + typename Header::FsSize_t readSize, T *data, typename Header::FsSize_t *size) { + // be sure read size is not greater than what is available to read + if (inode->getDataLen() - readStart < readSize) { + readSize = inode->getDataLen() - readStart; + } + if (size) { + *size = readSize; + } + + readSize /= sizeof(T); + uint8_t *it = &(inode->getData()[readStart]); + for (typename Header::FsSize_t i = 0; i < readSize; i++) { + T val; + for (size_t i = 0; i < sizeof(T); i++) { + ((uint8_t*) (&val))[i] = *(it++); + } + *(data++) = val; + } + return 0; +} + +template +typename FileStore
::StatInfo FileStore
::stat(InodeId_t id) { + auto inode = getInode(ptr(m_header.getRootInode()), id); + StatInfo stat; + if (inode) { + stat.size = inode->getDataLen(); + stat.fileType = inode->getFileType(); + stat.links = inode->getLinks(); + stat.inodeId = id; + } else { + stat.inodeId = 0; + } + return stat; +} + +template +typename Header::FsSize_t FileStore
::spaceNeeded(typename Header::FsSize_t size) { + return sizeof(Inode) + size; +} + +template +typename Header::FsSize_t FileStore
::size() { + return m_header.getSize(); +} + +template +typename Header::FsSize_t FileStore
::available() { + return m_header.getSize() - m_header.getMemUsed(); +} + +template +typename FileStore
::Inode *FileStore
::getInode(Inode *root, InodeId_t id) { + Inode *retval = nullptr; + + if (root->getId() > id) { + if (root->getLeft()) { + retval = getInode(ptr(root->getLeft()), id); + } + } else if (root->getId() < id) { + if (root->getRight()) { + retval = getInode(ptr(root->getRight()), id); + } + } else if (root->getId() == id) { + retval = root; + } + + return retval; +} + +template +typename FileStore
::Inode *FileStore
::getInodeParent(Inode *root, InodeId_t id, typename Header::FsSize_t targetAddr) { + Inode *retval = nullptr; + + if (root->getId() > id) { + if (root->getLeft()) { + if (root->getLeft() == targetAddr) { + retval = root; + } else { + retval = getInodeParent(ptr(root->getLeft()), id, targetAddr); + } + } + } else if (root->getId() < id) { + if (root->getRight()) { + if (root->getRight() == targetAddr) { + retval = root; + } else { + retval = getInodeParent(ptr(root->getRight()), id, targetAddr); + } + } + } + + return retval; +} + +template +typename Header::FsSize_t FileStore
::nextInodeAddr() { + return lastInode() + ptr(lastInode())->size(); +} + +template +void *FileStore
::alloc(typename Header::FsSize_t size) { + auto next = nextInodeAddr(); + if ((next + size) > ptr(end())) { + compact(); + next = nextInodeAddr(); + if ((next + size) > ptr(end())) { + return nullptr; + } + } + + const auto retval = next; + const auto inode = ptr(retval); + ox_memset(inode, 0, size); + inode->setPrev(ptr(firstInode())->getPrev()); + inode->setNext(firstInode()); + m_header.setMemUsed(m_header.getMemUsed() + size); + ptr(lastInode())->setNext(retval); + ptr(firstInode())->setPrev(retval); + return inode; +} + +template +void FileStore
::compact() { + auto dest = ptr(firstInode()); + auto current = ptr(firstInode()); + while (current->getNext() > firstInode() && current->getNext() < ptr(end())) { + ox_memcpy(dest, current, current->size()); + if (dest->getNext() != firstInode()) { + dest->setNext(ptr(dest) + dest->size()); + } + ptr(dest->getNext())->setPrev(ptr(dest)); + updateInodeAddress(dest->getId(), ptr(current), ptr(dest)); + current = ptr(dest->getNext()); + dest = ptr(ptr(dest) + dest->size()); + } +} + +template +bool FileStore
::insert(Inode *root, Inode *insertValue) { + auto retval = false; + + if (root->getId() > insertValue->getId()) { + if (root->getLeft()) { + retval = insert(ptr(root->getLeft()), insertValue); + } else { + root->setLeft(ptr(insertValue)); + retval = true; + } + } else if (root->getId() < insertValue->getId()) { + if (root->getRight()) { + retval = insert(ptr(root->getRight()), insertValue); + } else { + root->setRight(ptr(insertValue)); + retval = true; + } + } else if (m_header.getRootInode() == 0) { + m_header.setRootInode(ptr(insertValue)); + retval = true; + } + + return retval; +} + +template +typename Header::FsSize_t FileStore
::ptr(void *ptr) { +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + return ((uint8_t*) ptr) - begin(); +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif +} + +template +typename Header::FsSize_t FileStore
::firstInode() { + return sizeof(FileStore
); +} + +template +typename Header::FsSize_t FileStore
::lastInode() { + return ptr(firstInode())->getPrev(); +} + +template +uint16_t FileStore
::fsType() { + return m_header.getFsType(); +}; + +template +uint16_t FileStore
::version() { + return m_header.getVersion(); +}; + +template +void FileStore
::walk(int(*cb)(const char*, uint64_t start, uint64_t end)) { + auto err = cb("Header", 0, sizeof(Header)); + auto inode = ptr(firstInode()); + do { + auto start = ptr(inode); + err = cb("Inode", start, start + inode->size()); + inode = ptr(inode->getNext()); + } while (!err && inode != ptr(firstInode())); +} + +template +uint8_t *FileStore
::format(uint8_t *buffer, typename Header::FsSize_t size, uint16_t fsType) { + ox_memset(buffer, 0, size); + + auto *fs = (FileStore*) buffer; + fs->m_header.setFsType(fsType); + fs->m_header.setVersion(Header::VERSION); + fs->m_header.setSize(size); + fs->m_header.setMemUsed(sizeof(FileStore
) + sizeof(Inode)); + fs->m_header.setRootInode(sizeof(FileStore
)); + ((Inode*) (fs + 1))->setPrev(sizeof(FileStore
)); + ((Inode*) (fs + 1))->setNext(sizeof(FileStore
)); + + return (uint8_t*) buffer; +} + +typedef FileStore> FileStore16; +typedef FileStore> FileStore32; +typedef FileStore> FileStore64; + +} diff --git a/deps/ox/src/ox/fs/filesystem.cpp b/deps/ox/src/ox/fs/filesystem.cpp new file mode 100644 index 00000000..b6f9b94f --- /dev/null +++ b/deps/ox/src/ox/fs/filesystem.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2015 - 2017 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 "filesystem.hpp" + +namespace ox { + +FileSystem *createFileSystem(uint8_t *buff, size_t buffSize, bool ownsBuff) { + auto version = ((FileStore16*) buff)->version(); + auto type = ((FileStore16*) buff)->fsType(); + FileSystem *fs = nullptr; + + switch (version) { + case 6: + switch (type) { + case ox::OxFS_16: + fs = new FileSystem16(buff, ownsBuff); + break; + case ox::OxFS_32: + fs = new FileSystem32(buff, ownsBuff); + break; + case ox::OxFS_64: + fs = new FileSystem64(buff, ownsBuff); + break; + } + break; + default: + break; + } + + if (fs && fs->size() > buffSize) { + delete fs; + fs = nullptr; + } + + return fs; +} + +FileSystem *expandCopy(FileSystem *fs, size_t size) { + auto fsBuff = fs->buff(); + FileSystem *retval = nullptr; + + if (fs->size() <= size) { + auto cloneBuff = new uint8_t[size]; + ox_memcpy(cloneBuff, fsBuff, fs->size()); + + fsBuff = cloneBuff; + retval = createFileSystem(fsBuff, size); + retval->resize(size); + } + + return retval; +} + +FileSystem *expandCopyCleanup(FileSystem *fs, size_t size) { + auto out = expandCopy(fs, size); + + if (out) { + delete[] fs->buff(); + delete fs; + } else { + out = fs; + } + + return out; +} + +} diff --git a/deps/ox/src/ox/fs/filesystem.hpp b/deps/ox/src/ox/fs/filesystem.hpp new file mode 100644 index 00000000..1092195e --- /dev/null +++ b/deps/ox/src/ox/fs/filesystem.hpp @@ -0,0 +1,884 @@ +/* + * Copyright 2015 - 2017 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 +#include "pathiterator.hpp" +#include "filestore.hpp" + +namespace ox { + +enum FsType { + OxFS_16 = 1, + OxFS_32 = 2, + OxFS_64 = 3 +}; + +enum FileType { + FileType_NormalFile = 1, + FileType_Directory = 2 +}; + +struct FileStat { + uint64_t inode; + uint64_t links; + uint64_t size; + uint8_t fileType; +}; + +template +struct DirectoryListing { + String name; + FileStat stat; + + DirectoryListing() = default; + + DirectoryListing(const char *name) { + this->name = name; + } +}; + +template +bool operator<(const DirectoryListing &a, const DirectoryListing &b) { + return a.name < b.name; +} + +template +struct __attribute__((packed)) DirectoryEntry { + InodeId_t inode; + + char *getName() { + return (char*) (this + 1); + } + + void setName(const char *name) { + auto data = getName(); + auto nameLen = ox_strlen(name); + ox_memcpy(data, name, nameLen); + data[nameLen] = 0; + } + + static uint64_t spaceNeeded(const char *fileName) { + return sizeof(DirectoryEntry) + ox_strlen(fileName) + 1; + } + + /** + * The size in bytes. + */ + uint64_t size() { + return spaceNeeded(getName()); + } +}; + +template +struct __attribute__((packed)) Directory { + /** + * Number of bytes after this Directory struct. + */ + FsSize_t size = 0; + FsSize_t children = 0; + + DirectoryEntry *files() { + return size ? (DirectoryEntry*) (this + 1) : nullptr; + } + + uint64_t getFileInode(const char *name); + + int getChildrenInodes(InodeId_t *inodes, size_t inodesLen); + + int rmFile(const char *name); + + int copy(Directory *dirOut); + + template + int ls(List *list); +}; + +template +uint64_t Directory::getFileInode(const char *name) { + uint64_t inode = 0; + auto current = files(); + if (current) { + for (uint64_t i = 0; ox_strcmp(current->getName(), name) != 0;) { + i += current->size(); + if (i < this->size) { + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + } else { + current = nullptr; + break; + } + } + if (current) { + inode = current->inode; + } + } + return inode; +} + +template +int Directory::getChildrenInodes(InodeId_t *inodes, size_t inodesLen) { + if (inodesLen >= this->children) { + auto current = files(); + if (current) { + for (uint64_t i = 0; i < this->children; i++) { + if (ox_strcmp(current->getName(), ".") and ox_strcmp(current->getName(), "..")) { + inodes[i] = current->inode; + } + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + } + return 0; + } else { + return 1; + } + } else { + return 2; + } +} + +template +int Directory::rmFile(const char *name) { + int err = 1; + auto current = files(); + if (current) { + for (uint64_t i = 0; i < this->size;) { + i += current->size(); + if (ox_strcmp(current->getName(), name) == 0) { + auto dest = (uint8_t*) current; + auto src = dest + current->size(); + ox_memcpy(dest, src, this->size - i); + this->size -= current->size(); + this->children--; + err = 0; + break; + } + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + } + } + return err; +} + +template +int Directory::copy(Directory *dirOut) { + auto current = files(); + auto dirOutBuff = (uint8_t*) dirOut; + dirOutBuff += sizeof(Directory); + dirOut->size = this->size; + dirOut->children = this->children; + if (current) { + for (uint64_t i = 0; i < this->children; i++) { + auto entry = (DirectoryEntry*) dirOutBuff; + entry->inode = current->inode; + entry->setName(current->getName()); + + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + dirOutBuff += entry->size(); + } + return 0; + } else { + return 1; + } +} + +template +template +int Directory::ls(List *list) { + auto current = files(); + if (current) { + for (uint64_t i = 0; i < this->children; i++) { + list->push_back(current->getName()); + (*list)[i].stat.inode = current->inode; + current = (DirectoryEntry*) (((uint8_t*) current) + current->size()); + } + return 0; + } else { + return 1; + } +} + + +class FileSystem { + public: + virtual ~FileSystem() {}; + + virtual int stripDirectories() = 0; + + virtual int mkdir(const char *path) = 0; + + /** + * Moves an entry from one directory to another. + * @param src the path to the file + * @param dest the path of the destination directory + */ + virtual int move(const char *src, const char *dest) = 0; + + template + int ls(const char *path, List *list); + + virtual int read(const char *path, void *buffer, size_t buffSize) = 0; + + virtual int read(uint64_t inode, void *buffer, size_t size) = 0; + + virtual int read(uint64_t inode, size_t readStart, size_t readSize, void *buffer, size_t *size) = 0; + + virtual uint8_t *read(uint64_t inode, size_t *size) = 0; + + virtual int remove(uint64_t inode, bool recursive = false) = 0; + + virtual int remove(const char *path, bool recursive = false) = 0; + + virtual void resize(uint64_t size = 0) = 0; + + virtual int write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0; + + virtual int write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) = 0; + + virtual FileStat stat(uint64_t inode) = 0; + + virtual FileStat stat(const char *path) = 0; + + virtual uint64_t spaceNeeded(uint64_t size) = 0; + + virtual uint64_t available() = 0; + + virtual uint64_t size() = 0; + + virtual uint8_t *buff() = 0; + + virtual void walk(int(*cb)(const char*, uint64_t, uint64_t)) = 0; + + protected: + virtual int readDirectory(const char *path, Directory *dirOut) = 0; +}; + +template +int FileSystem::ls(const char *path, List *list) { + int err = 0; + auto s = stat(path); + if (s.fileType == FileType_Directory) { + uint8_t dirBuff[s.size * 4]; + auto dir = (Directory*) dirBuff; + err = readDirectory(path, dir); + err |= dir->ls(list); + } + return err; +} + +FileSystem *createFileSystem(uint8_t *buff, size_t buffSize, bool ownsBuff = false); + +/** + * Creates a larger version of the given FileSystem. + */ +FileSystem *expandCopy(FileSystem *src); + +/** + * Calls expandCopy and deletes the original FileSystem and buff a resize was + * performed. + */ +FileSystem *expandCopyCleanup(FileSystem *fs, size_t size); + +template +class FileSystemTemplate: public FileSystem { + + private: + FileStore *m_store = nullptr; + bool m_ownsBuff = false; + + public: + // static members + static typename FileStore::InodeId_t INODE_RANDOM; + static typename FileStore::InodeId_t INODE_ROOT_DIR; + static typename FileStore::InodeId_t INODE_RESERVED_END; + + explicit FileSystemTemplate(uint8_t *buff, bool ownsBuff = false); + + ~FileSystemTemplate(); + + int stripDirectories() override; + + int mkdir(const char *path) override; + + int read(const char *path, void *buffer, size_t buffSize) override; + + int read(uint64_t inode, void *buffer, size_t buffSize) override; + + int read(uint64_t inode, size_t readStart, size_t readSize, void *buffer, size_t *size) override; + + uint8_t *read(uint64_t inode, size_t *size) override; + + void resize(uint64_t size = 0) override; + + int remove(uint64_t inode, bool recursive = false) override; + + int remove(const char *path, bool recursive = false) override; + + int write(const char *path, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override; + + int write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType = FileType_NormalFile) override; + + FileStat stat(const char *path) override; + + FileStat stat(uint64_t inode) override; + + uint64_t findInodeOf(const char *name); + + uint64_t spaceNeeded(uint64_t size) override; + + uint64_t available() override; + + uint64_t size() override; + + uint8_t *buff() override; + + int move(const char *src, const char *dest) override; + + /** + * Removes an entry from a directory. This does not delete the referred to file. + */ + int rmDirectoryEntry(const char *path); + + void walk(int(*cb)(const char*, uint64_t, uint64_t)) override; + + static uint8_t *format(uint8_t *buffer, typename FileStore::FsSize_t size, bool useDirectories); + + protected: + int readDirectory(const char *path, Directory *dirOut) override; + + private: + uint64_t generateInodeId(); + + int insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode); + + void expand(uint64_t size); +}; + +template +FileSystemTemplate::FileSystemTemplate(uint8_t *buff, bool ownsBuff) { + m_store = (FileStore*) buff; + m_ownsBuff = ownsBuff; +} + +template +FileSystemTemplate::~FileSystemTemplate() { + if (m_ownsBuff) { + delete[] (uint8_t*) m_store; + } +} + +template +typename FileStore::InodeId_t FileSystemTemplate::INODE_RANDOM = 1; + +template +typename FileStore::InodeId_t FileSystemTemplate::INODE_ROOT_DIR = 2; + +template +typename FileStore::InodeId_t FileSystemTemplate::INODE_RESERVED_END = 100; + +template +int FileSystemTemplate::stripDirectories() { + return m_store->removeAllType(FileType::FileType_Directory); +} + +template +int FileSystemTemplate::mkdir(const char *pathIn) { + if (!findInodeOf(pathIn)) { + auto pathLen = ox_strlen(pathIn); + char path[pathLen + 1]; + ox_memcpy(path, pathIn, pathLen + 1); + + // make sure last character does not end with / + if (pathLen >= 1 && path[pathLen - 1] == '/') { + path[pathLen - 1] = 0; + pathLen--; + } + + Directory dir; + auto err = write(path, &dir, sizeof(dir), FileType::FileType_Directory); + if (err) { + return err; + } + + // add . entry for self + auto inode = findInodeOf(path); + err = insertDirectoryEntry(path, ".", inode); + if (err) { + remove(inode); + return err; + } + + // add .. entry for parent + char dirPath[pathLen]; + PathIterator pathReader(path, pathLen); + err |= pathReader.dirPath(dirPath, pathLen); + err = insertDirectoryEntry(path, "..", findInodeOf(dirPath)); + if (err) { + remove(inode); + return err; + } + + return err; + } else { + return 1; + } +} + +template +FileStat FileSystemTemplate::stat(const char *path) { + auto inode = findInodeOf(path); + FileStat stat; + auto s = m_store->stat(inode); + stat.size = s.size; + stat.inode = s.inodeId; + stat.fileType = s.fileType; + return stat; +} + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +FileStat FileSystemTemplate::stat(uint64_t inode) { + FileStat stat; + auto s = m_store->stat(inode); + stat.size = s.size; + stat.inode = s.inodeId; + stat.links = s.links; + stat.fileType = s.fileType; + return stat; +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +int FileSystemTemplate::read(const char *path, void *buffer, size_t buffSize) { + int retval = -1; + + // find the inode for the given path + auto inode = findInodeOf(path); + + // if inode exists, read the data into buffer + if (inode) { + retval = read(inode, buffer, buffSize); + } + + return retval; +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +int FileSystemTemplate::read(uint64_t inode, void *buffer, size_t buffSize) { + auto stat = m_store->stat(inode); + if (stat.size <= buffSize) { + return m_store->read(inode, buffer, nullptr); + } + return -1; +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +int FileSystemTemplate::read(uint64_t inode, size_t readStart, + size_t readSize, void *buffer, + size_t *size) { + if (size) { + auto stat = m_store->stat(inode); + *size = stat.size; + } + return m_store->read(inode, readStart, readSize, buffer, nullptr); +} +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +uint8_t *FileSystemTemplate::read(uint64_t inode, size_t *size) { + auto s = m_store->stat(inode); + auto buff = new uint8_t[s.size]; + if (size) { + *size = s.size; + } + if (m_store->read(inode, buff, nullptr)) { + delete []buff; + buff = nullptr; + } + return buff; +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +template +int FileSystemTemplate::remove(const char *path, bool recursive) { + auto inode = findInodeOf(path); + if (inode) { + return rmDirectoryEntry(path) | remove(inode, recursive); + } else { + return 1; + } +} + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +int FileSystemTemplate::remove(uint64_t inode, bool recursive) { + auto fileType = stat(inode).fileType; + if (fileType != FileType::FileType_Directory) { + return m_store->remove(inode); + } else if (fileType == FileType::FileType_Directory && recursive) { + int err = 0; + auto dirStat = stat(inode); + auto dirBuffLen = dirStat.size; + uint8_t dirBuff[dirBuffLen]; + auto dir = (Directory*) dirBuff; + + err = read(dirStat.inode, dirBuff, dirBuffLen); + if (err) { + return 1; + } + + typename FileStore::InodeId_t inodes[dir->children]; + ox_memset(inodes, 0, sizeof(typename FileStore::InodeId_t) * dir->children); + dir->getChildrenInodes(inodes, dir->children); + + for (auto i : inodes) { + if (i) { + err |= remove(i, true); + } + } + + if (!err) { + err |= m_store->remove(inode); + } + + return err; + } else { + return 1; + } +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +int FileSystemTemplate::write(const char *path, void *buffer, uint64_t size, uint8_t fileType) { + int err = 0; + size_t pathLen = ox_strlen(path); + char dirPath[pathLen]; + char fileName[pathLen]; + PathIterator pathReader(path, pathLen); + err |= pathReader.fileName(fileName, pathLen); + err |= pathReader.dirPath(dirPath, pathLen); + if (err) { + return err; + } + + uint64_t inode = findInodeOf(path); + // find an inode value for the given path + if (!inode) { + inode = generateInodeId(); + err |= write(inode, buffer, 0, fileType); // ensure file exists before indexing it + err |= insertDirectoryEntry(dirPath, fileName, inode); + } + + if (!err) { + err = write(inode, buffer, size, fileType); + } + + return err; +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +int FileSystemTemplate::write(uint64_t inode, void *buffer, uint64_t size, uint8_t fileType) { + if (m_ownsBuff) { + while (m_store->spaceNeeded(size) > m_store->available()) { + expand(this->size() * 2); + } + } + return m_store->write(inode, buffer, size, fileType); +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +uint64_t FileSystemTemplate::findInodeOf(const char *path) { + const auto pathLen = ox_strlen(path); + PathIterator it(path, pathLen); + char fileName[pathLen]; + uint64_t inode = INODE_ROOT_DIR; + while (it.hasNext() && it.next(fileName, pathLen) == 0 && ox_strlen(fileName)) { + auto dirStat = stat(inode); + if (dirStat.inode && dirStat.size >= sizeof(Directory)) { + uint8_t dirBuffer[dirStat.size]; + auto dir = (Directory*) dirBuffer; + if (read(inode, dirBuffer, dirStat.size) == 0) { + if (dirStat.fileType == FileType::FileType_Directory) { + inode = dir->getFileInode(fileName); + } else { + inode = 0; // null out inode and break + break; + } + } else { + inode = 0; // null out inode and break + break; + } + } else { + inode = 0; // null out inode and break + break; + } + } + return inode; +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +template +void FileSystemTemplate::resize(uint64_t size) { + return m_store->resize(size); +} + +template +uint64_t FileSystemTemplate::spaceNeeded(uint64_t size) { + return m_store->spaceNeeded(size); +} + +template +uint64_t FileSystemTemplate::available() { + return m_store->available(); +} + +template +uint64_t FileSystemTemplate::size() { + return m_store->size(); +} + +template +uint8_t *FileSystemTemplate::buff() { + return (uint8_t*) m_store; +} + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +uint8_t *FileSystemTemplate::format(uint8_t *buffer, typename FileStore::FsSize_t size, bool useDirectories) { + buffer = FileStore::format(buffer, size, (uint16_t) FS_TYPE); + + if (buffer && useDirectories) { + Directory dir; + FileSystemTemplate fs((uint8_t*) buffer); + fs.write(INODE_ROOT_DIR, &dir, sizeof(dir), FileType::FileType_Directory); + } + + return (uint8_t*) buffer; +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +template +uint64_t FileSystemTemplate::generateInodeId() { + Random rand; + read(INODE_RANDOM, &rand, sizeof(rand)); + + uint64_t inode = 0; + // find an inode value for the given path + while (!inode) { + inode = rand.gen(); + inode >>= 64 - 8 * sizeof(typename FileStore::InodeId_t); + + // make sure this does not already exist + if (inode < INODE_RESERVED_END || stat(inode).inode) { + // that result was unusable, try again + inode = 0; + } + } + + write(INODE_RANDOM, &rand, sizeof(rand)); + + return inode; +} + +#ifdef _MSC_VER +#pragma warning(disable:4244) +#endif +template +int FileSystemTemplate::insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode) { + auto s = stat(dirPath); + if (s.inode) { + auto spaceNeeded = DirectoryEntry::spaceNeeded(fileName); + size_t dirBuffSize = s.size + spaceNeeded; + uint8_t dirBuff[dirBuffSize]; + int err = read(s.inode, dirBuff, dirBuffSize); + + if (!err) { + auto dir = (Directory*) dirBuff; + dir->size += spaceNeeded; + dir->children++; + auto entry = (DirectoryEntry*) &dirBuff[s.size]; + entry->inode = inode; + entry->setName(fileName); + err = write(s.inode, dirBuff, dirBuffSize, FileType_Directory); + err |= m_store->incLinks(inode); + return err; + } else { + return 1; + } + } else { + return 2; + } +} +#ifdef _MSC_VER +#pragma warning(default:4244) +#endif + +template +int FileSystemTemplate::move(const char *src, const char *dest) { + auto inode = stat(src).inode; + if (inode && !stat(dest).inode) { + int err = 0; + + size_t srcLen = ox_strlen(src); + char srcDirPath[srcLen]; + char srcFileName[srcLen]; + PathIterator srcPathReader(src, srcLen); + err |= srcPathReader.fileName(srcFileName, srcLen); + err |= srcPathReader.dirPath(srcDirPath, srcLen); + if (err) { + return err; + } + + size_t destLen = ox_strlen(dest); + char destDirPath[destLen]; + char destFileName[destLen]; + PathIterator destPathReader(dest, destLen); + err |= destPathReader.fileName(destFileName, destLen); + err |= destPathReader.dirPath(destDirPath, destLen); + if (err) { + return err; + } + + err = rmDirectoryEntry(src); + if (err) { + return err; + } + + err = insertDirectoryEntry(destDirPath, destFileName, inode); + if (!err) { + return err; + } + + return 0; + } else { + return 1; + } +} + +template +int FileSystemTemplate::rmDirectoryEntry(const char *path) { + int err = 0; + size_t pathLen = ox_strlen(path); + char dirPath[pathLen]; + char fileName[pathLen]; + PathIterator pathReader(path, pathLen); + err |= pathReader.fileName(fileName, pathLen); + err |= pathReader.dirPath(dirPath, pathLen); + if (err) { + return err; + } + + auto dirStat = stat(dirPath); + auto dirBuffLen = dirStat.size; + uint8_t dirBuff[dirBuffLen]; + + err = read(dirStat.inode, dirBuff, dirBuffLen); + if (err) { + return err; + } + + auto dir = (Directory*) dirBuff; + auto inode = dir->getFileInode(fileName); + err |= dir->rmFile(fileName); + err |= m_store->decLinks(inode); + + if (err) { + return err; + } + + err = write(dirStat.inode, dirBuff, dirBuffLen - DirectoryEntry::spaceNeeded(fileName)); + + return err; +} + +template +int FileSystemTemplate::readDirectory(const char *path, Directory *dirOut) { + int err = 0; + auto inode = findInodeOf(path); + auto dirStat = stat(inode); + auto dirBuffLen = dirStat.size; + uint8_t dirBuff[dirBuffLen]; + auto dir = (Directory*) dirBuff; + + err = read(dirStat.inode, dirBuff, dirBuffLen); + if (!err) { + return dir->copy(dirOut); + } else { + return 1; + } +} + +template +void FileSystemTemplate::expand(uint64_t newSize) { + if (newSize > size()) { + auto newBuff = new uint8_t[newSize]; + ox_memcpy(newBuff, m_store, m_store->size()); + delete[] m_store; + m_store = (FileStore*) newBuff; + resize(newSize); + } +} + +template +void FileSystemTemplate::walk(int(*cb)(const char*, uint64_t, uint64_t)) { + m_store->walk(cb); +} + +typedef FileSystemTemplate FileSystem16; +typedef FileSystemTemplate FileSystem32; +typedef FileSystemTemplate FileSystem64; + +} diff --git a/deps/ox/src/ox/fs/oxfstool.cpp b/deps/ox/src/ox/fs/oxfstool.cpp new file mode 100644 index 00000000..ae13ffe0 --- /dev/null +++ b/deps/ox/src/ox/fs/oxfstool.cpp @@ -0,0 +1,395 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include +#include +#include +#include +#include +#include + +#include "toollib.hpp" + +// suppress warnings about using fopen +#ifdef _MSC_VER +#pragma warning(disable:4996) +#endif + +using namespace ox; +using namespace std; + +const static auto oxfstoolVersion = "1.4.0"; +const static auto usage = "usage:\n" +"\toxfs format [16,32,64] \n" +"\toxfs read \n" +"\toxfs write \n" +"\toxfs write-expand \n" +"\toxfs rm \n" +"\toxfs compact \n" +"\toxfs walk \n" +"\toxfs version\n"; + +size_t bytes(const char *str) { + auto size = ::ox_strlen(str); + const auto lastChar = str[size-1]; + auto multiplier = 1; + char copy[size + 1]; + ox_memcpy(copy, str, size + 1); + // parse size unit + if (lastChar < '0' || lastChar > '9') { + copy[size-1] = 0; + switch (lastChar) { + case 'k': + case 'K': + multiplier = 1024; + break; + case 'm': + case 'M': + multiplier = 1024 * 1024; + break; + case 'g': + case 'G': + multiplier = 1024 * 1024 * 1024; + break; + default: + multiplier = -1; + } + } + return ox_atoi(copy) * multiplier; +} + +int format(int argc, char **args) { + printf("Creating file system...\n"); + auto err = 0; + if (argc >= 5) { + auto type = ox_atoi(args[2]); + auto size = bytes(args[3]); + auto path = args[4]; + auto buff = new uint8_t[size]; + + + if (size < sizeof(FileStore64)) { + err = 1; + cerr << "File system size " << size << " too small, must be at least " << sizeof(FileStore64) << endl; + } + + if (!err) { + // format + switch (type) { + case 16: + FileSystem16::format(buff, (FileStore16::FsSize_t) size, true); + break; + case 32: + FileSystem32::format(buff, (FileStore32::FsSize_t) size, true); + break; + case 64: + FileSystem64::format(buff, size, true); + break; + default: + err = 1; + } + + if (!err) { + auto file = fopen(path, "wb"); + if (file) { + err = fwrite(buff, size, 1, file) != 1; + err |= fclose(file); + if (err) { + fprintf(stderr, "Could not write to file: %s.\n", path); + } + } else { + fprintf(stderr, "Could not open file: %s.\n", path); + } + } + } + + delete []buff; + + if (err == 0) { + cerr << "Created file system " << path << endl; + cerr << " type " << type << endl; + cerr << " wrote " << size << " bytes\n"; + } + } else { + fprintf(stderr, "Insufficient arguments\n"); + } + + return err; +} + +int read(int argc, char **args) { + auto err = 1; + if (argc >= 4) { + auto fsPath = args[2]; + auto inode = ox_atoi(args[3]); + size_t fsSize; + size_t fileSize; + + auto fsBuff = loadFileBuff(fsPath, &fsSize); + + if (fsBuff) { + auto fs = createFileSystem(fsBuff, fsSize); + + if (fs) { + auto output = fs->read(inode, &fileSize); + + if (output) { + fwrite(output, fileSize, 1, stdout); + delete []output; + err = 0; + } + + delete fs; + delete []fsBuff; + } else { + fprintf(stderr, "Invalid file system type: %d.\n", *(uint32_t*) fsBuff); + } + } else { + fprintf(stderr, "Could not open file: %s\n", fsPath); + } + } else { + fprintf(stderr, "Insufficient arguments\n"); + } + return err; +} + +int write(int argc, char **args, bool expand) { + auto err = 0; + if (argc >= 5) { + auto fsPath = args[2]; + auto inode = ox_atoi(args[3]); + auto srcPath = args[4]; + size_t srcSize; + + auto fsFile = fopen(fsPath, "rb"); + if (fsFile) { + fseek(fsFile, 0, SEEK_END); + + auto fsSize = (size_t) ftell(fsFile); + rewind(fsFile); + auto fsBuff = new uint8_t[fsSize]; + auto itemsRead = fread(fsBuff, fsSize, 1, fsFile); + fclose(fsFile); + + if (itemsRead) { + auto srcBuff = loadFileBuff(srcPath, &srcSize); + if (srcBuff) { + auto expanded = false; + auto fs = createFileSystem(fsBuff, fsSize); + if (fs) { + if (expand && fs->available() <= srcSize) { + auto needed = fs->size() + fs->spaceNeeded(srcSize); + fsSize = needed; + fs = expandCopyCleanup(fs, needed); + fsBuff = fs->buff(); + } + err |= fs->write(inode, srcBuff, srcSize); + + // compact the file system if it was expanded + if (expanded) { + fs->resize(); + } + + if (err) { + fprintf(stderr, "Could not write to file system.\n"); + } + delete fs; + } else { + fprintf(stderr, "Invalid file system type: %d.\n", *(uint32_t*) fsBuff); + err = 1; + } + + if (!err) { + fsFile = fopen(fsPath, "wb"); + + if (fsFile) { + err = fwrite(fsBuff, fsSize, 1, fsFile) != 1; + err |= fclose(fsFile); + if (err) { + fprintf(stderr, "Could not write to file system file.\n"); + } + } else { + err = 1; + } + } + delete []srcBuff; + } else { + err = 1; + fprintf(stderr, "Could not load source file: %s.\n", srcPath); + } + } + + delete []fsBuff; + } else { + fprintf(stderr, "Could not open file system\n"); + } + } else { + fprintf(stderr, "Insufficient arguments\n"); + } + return err; +} + +int compact(int argc, char **args) { + auto err = 1; + if (argc >= 2) { + auto fsPath = args[2]; + size_t fsSize; + + auto fsBuff = loadFileBuff(fsPath, &fsSize); + if (fsBuff) { + auto fs = createFileSystem(fsBuff, fsSize); + + if (fs) { + fs->resize(); + } else { + fprintf(stderr, "Invalid file system.\n"); + } + + // write back to file + auto fsFile = fopen(fsPath, "wb"); + if (fsFile) { + err = fwrite(fsBuff, fs->size(), 1, fsFile) != 1; + err |= fclose(fsFile); + if (err) { + fprintf(stderr, "Could not write to file system file.\n"); + } + } else { + err = 1; + } + + delete fs; + delete []fsBuff; + } else { + fprintf(stderr, "Could not open file: %s\n", fsPath); + } + } else { + fprintf(stderr, "Insufficient arguments\n"); + } + return err; +} + +int remove(int argc, char **args) { + auto err = 1; + if (argc >= 4) { + auto fsPath = args[2]; + auto inode = ox_atoi(args[3]); + size_t fsSize; + + auto fsBuff = loadFileBuff(fsPath, &fsSize); + if (fsBuff) { + auto fs = createFileSystem(fsBuff, fsSize); + + if (fs) { + err = fs->remove(inode); + } else { + fprintf(stderr, "Invalid file system.\n"); + } + + if (err) { + fprintf(stderr, "Could not write to file system.\n"); + } else { + auto fsFile = fopen(fsPath, "wb"); + if (fsFile) { + err = fwrite(fsBuff, fsSize, 1, fsFile) != 1; + err |= fclose(fsFile); + if (err) { + fprintf(stderr, "Could not write to file system file.\n"); + } + } else { + err = 1; + } + } + + delete fs; + delete []fsBuff; + } else { + fprintf(stderr, "Could not open file: %s\n", fsPath); + } + } else { + fprintf(stderr, "Insufficient arguments\n"); + } + return err; +} + +int walk(int argc, char **args) { + int err = 0; + size_t fsSize; + auto fsPath = args[2]; + auto fsBuff = loadFileBuff(fsPath, &fsSize); + if (fsBuff) { + auto fs = createFileSystem(fsBuff, fsSize); + if (fs) { + cout << setw(9) << "Type |"; + cout << setw(10) << "Start |"; + cout << setw(10) << "End |"; + cout << setw(8) << "Size"; + cout << endl; + cout << "-------------------------------------"; + cout << endl; + fs->walk([](const char *type, uint64_t start, uint64_t end) { + cout << setw(7) << type << " |"; + cout << setw(8) << start << " |"; + cout << setw(8) << end << " |"; + cout << setw(8) << (end - start); + cout << endl; + return 0; + }); + delete fs; + } else { + cerr << "Invalid file system.\n"; + err = 1; + } + delete []fsBuff; + } else { + err = 2; + } + return err; +} + +int help(int, char**) { + cout << usage << endl; + return 0; +} + +int version(int, char**) { + cout << "oxfstool version " << oxfstoolVersion << endl; + cout << "oxfs format version " << FileStore16::VERSION << endl; + return 0; +} + +int main(int argc, char **args) { + auto err = 0; + map cmdMap = { + { "format", format }, + { "read", read }, + { "write", [](int argc, char **args) { return write(argc, args, false); } }, + { "write-expand", [](int argc, char **args) { return write(argc, args, true); } }, + { "compact", compact }, + { "rm", remove }, + { "walk", walk }, + { "help", help }, + { "version", version }, + }; + + if (argc > 1) { + auto cmd = args[1]; + auto f = cmdMap[cmd]; + if (f) { + err = f(argc, args); + } else { + cout << "Command '" << cmd << "' not recognized." << endl; + err = 1; + } + } else { + help(argc, args); + } + + return err; +} diff --git a/deps/ox/src/ox/fs/pathiterator.cpp b/deps/ox/src/ox/fs/pathiterator.cpp new file mode 100644 index 00000000..dae07a7e --- /dev/null +++ b/deps/ox/src/ox/fs/pathiterator.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include "pathiterator.hpp" + +namespace ox { + +PathIterator::PathIterator(const char *path, size_t maxSize) { + m_path = path; + m_maxSize = maxSize; +} + +/** + * @return 0 if no error + */ +int PathIterator::dirPath(char *out, size_t outSize) { + int idx = ox_lastIndexOf(m_path, '/', m_maxSize); + size_t size = idx + 1; + if (idx >= 0 && size < outSize) { + ox_memcpy(out, m_path, size); + out[size] = 0; + return 0; + } else { + return 1; + } +} + +/** + * @return 0 if no error + */ +int PathIterator::fileName(char *out, size_t outSize) { + auto idx = ox_lastIndexOf(m_path, '/', m_maxSize); + if (idx >= 0) { + idx++; // pass up the preceding / + size_t fileNameSize = ox_strlen(&m_path[idx]); + if (fileNameSize < outSize) { + ox_memcpy(out, &m_path[idx], fileNameSize); + out[fileNameSize] = 0; + return 0; + } else { + return 1; + } + } else { + return 2; + } +} + +// Gets the next item in the path +int PathIterator::next(char *pathOut, size_t pathOutSize) { + size_t size = 0; + int retval = 1; + if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) { + retval = 0; + if (m_path[m_iterator] == '/') { + m_iterator++; + } + size_t start = m_iterator; + // end is at the next / + const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); + // correct end if it is invalid, which happens if there is no next / + if (!substr) { + substr = ox_strchr(&m_path[start], 0, m_maxSize - start); + } + size_t end = substr - m_path; + size = end - start; + // cannot fit the output in the output parameter + if (size >= pathOutSize) { + return -1; + } + ox_memcpy(pathOut, &m_path[start], size); + } + // truncate trailing / + if (size && pathOut[size - 1] == '/') { + size--; + } + pathOut[size] = 0; // end with null terminator + m_iterator += size; + return retval; +} + +bool PathIterator::hasNext() { + size_t size = 0; + if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) { + size_t start = m_iterator; + if (m_path[start] == '/') { + start++; + } + // end is at the next / + const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); + // correct end if it is invalid, which happens if there is no next / + if (!substr) { + substr = ox_strchr(&m_path[start], 0, m_maxSize - start); + } + size_t end = substr - m_path; + size = end - start; + } + return size > 0; +} + +} diff --git a/deps/ox/src/ox/fs/pathiterator.hpp b/deps/ox/src/ox/fs/pathiterator.hpp new file mode 100644 index 00000000..4d55f7f0 --- /dev/null +++ b/deps/ox/src/ox/fs/pathiterator.hpp @@ -0,0 +1,42 @@ +/* + * Copyright 2015 - 2017 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 + +namespace ox { + +class PathIterator { + private: + const char *m_path = nullptr; + size_t m_iterator = 0; + size_t m_maxSize = 0; + + public: + PathIterator(const char *path, size_t maxSize); + + /** + * @return 0 if no error + */ + int dirPath(char *pathOut, size_t pathOutSize); + + /** + * @return 0 if no error + */ + int fileName(char *out, size_t outSize); + + /** + * @return 0 if no error + */ + int next(char *pathOut, size_t pathOutSize); + + bool hasNext(); +}; + +} diff --git a/deps/ox/src/ox/fs/test/CMakeLists.txt b/deps/ox/src/ox/fs/test/CMakeLists.txt new file mode 100644 index 00000000..c6454ef8 --- /dev/null +++ b/deps/ox/src/ox/fs/test/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 2.8) + +add_executable( + FileStoreFormat + filestore_format.cpp +) + +add_executable( + FileSystemFormat + filesystem_format.cpp +) + +add_executable( + FileStoreIO + filestoreio.cpp +) + +add_executable( + FSTests + tests.cpp +) + +target_link_libraries( + FileStoreFormat + OxFS + OxStd + OxLog +) + +target_link_libraries( + FileSystemFormat + OxFS + OxStd + OxLog +) + +target_link_libraries( + FileStoreIO + OxFS + OxStd + OxLog +) + +target_link_libraries( + FSTests + OxFS + OxStd + OxLog +) + +add_test("FileStoreFormat" FileStoreFormat) +add_test("FileSystemFormat" FileSystemFormat) +add_test("FileStoreIO" FileStoreIO) +add_test("Test\\ PathIterator::next1" FSTests PathIterator::next1) +add_test("Test\\ PathIterator::next2" FSTests PathIterator::next2) +add_test("Test\\ PathIterator::next3" FSTests PathIterator::next3) +add_test("Test\\ PathIterator::next4" FSTests PathIterator::next4) +add_test("Test\\ PathIterator::next5" FSTests PathIterator::next5) + +add_test("Test\\ PathIterator::dirPath" FSTests PathIterator::dirPath) +add_test("Test\\ PathIterator::fileName" FSTests PathIterator::fileName) + +add_test("Test\\ FileSystem32::findInodeOf\\ /" FSTests "FileSystem32::findInodeOf /") +add_test("Test\\ FileSystem32::write\\(string\\)" FSTests "FileSystem32::write(string)") +add_test("Test\\ FileSystem32::rmDirectoryEntry\\(string\\)" FSTests "FileSystem32::rmDirectoryEntry(string)") +add_test("Test\\ FileSystem32::remove\\(string,\\ true\\)" FSTests "FileSystem32::remove(string, true)") +add_test("Test\\ FileSystem32::move" FSTests "FileSystem32::move") +add_test("Test\\ FileSystem32::stripDirectories" FSTests "FileSystem32::stripDirectories") +add_test("Test\\ FileSystem32::ls" FSTests "FileSystem32::ls") diff --git a/deps/ox/src/ox/fs/test/filestore_format.cpp b/deps/ox/src/ox/fs/test/filestore_format.cpp new file mode 100644 index 00000000..68e761ef --- /dev/null +++ b/deps/ox/src/ox/fs/test/filestore_format.cpp @@ -0,0 +1,18 @@ +/* + * Copyright 2015 - 2017 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 + +using namespace ox; + +int main() { + const auto size = 65535; + uint8_t volume[size]; + uint32_t err = 0; + FileStore32::format(volume, size); + return err; +} diff --git a/deps/ox/src/ox/fs/test/filestoreio.cpp b/deps/ox/src/ox/fs/test/filestoreio.cpp new file mode 100644 index 00000000..26c1b641 --- /dev/null +++ b/deps/ox/src/ox/fs/test/filestoreio.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include + +using namespace ox; + +template +int test() { + const uint16_t size = ~0; + uint8_t volume[size]; + char out[6]; + typename FileStore::FsSize_t outSize; + FileStore::format(volume, size); + FileStore *fs = (FileStore*) volume; + + if (fs->write(1, (void*) "Hello", 6) || + fs->read(1, (char*) out, &outSize) || + ox_strcmp("Hello", out)) { + printf("Failure 1\n"); + return 1; + } + + if (fs->write(2, (void*) "World", 6) || + fs->read(2, (char*) out, &outSize) || + ox_strcmp("World", out)) { + printf("Failure 2\n"); + return 2; + } + + // make sure first value was not overwritten + if (fs->read(1, (char*) out, &outSize) || + ox_strcmp("Hello", out)) { + printf("Failure 3\n"); + return 3; + } + + if (fs->remove(1)) { + printf("Failure 4\n"); + return 4; + } + + // make sure inode is not found + if (fs->read(1, (char*) out, &outSize) == 0) { + printf("Failure 5\n"); + return 5; + } + + // make sure 2 is still available + if (fs->write(2, (void*) "World", 6) || + fs->read(2, (char*) out, &outSize) || + ox_strcmp("World", out)) { + printf("Failure 6\n"); + return 6; + } + + return 0; +} + +int main() { + return test() || test() | test(); +} diff --git a/deps/ox/src/ox/fs/test/filesystem_format.cpp b/deps/ox/src/ox/fs/test/filesystem_format.cpp new file mode 100644 index 00000000..ff4f020a --- /dev/null +++ b/deps/ox/src/ox/fs/test/filesystem_format.cpp @@ -0,0 +1,23 @@ +/* + * Copyright 2015 - 2017 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 + +using namespace ox; + +template +int test() { + const uint16_t size = ~0; + uint8_t volume[size]; + FileSystem::format(volume, size, true); + return 0; +} + +int main() { + return test() | test() | test(); +} diff --git a/deps/ox/src/ox/fs/test/tests.cpp b/deps/ox/src/ox/fs/test/tests.cpp new file mode 100644 index 00000000..47e5a4a2 --- /dev/null +++ b/deps/ox/src/ox/fs/test/tests.cpp @@ -0,0 +1,346 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace ox; + +map tests = { + { + { + "PathIterator::next1", + [](string) { + int retval = 0; + string path = "/usr/share/charset.gbag"; + PathIterator it(path.c_str(), path.size()); + const auto buffSize = 1024; + char buff[buffSize]; + assert(buffSize >= path.size()); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0); + return retval; + } + }, + { + "PathIterator::next2", + [](string) { + int retval = 0; + string path = "/usr/share/"; + PathIterator it(path.c_str(), path.size()); + const auto buffSize = 1024; + char buff[buffSize]; + assert(buffSize >= path.size()); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0); + return retval; + } + }, + { + "PathIterator::next3", + [](string) { + int retval = 0; + string path = "/"; + PathIterator it(path.c_str(), path.size()); + const auto buffSize = 1024; + char buff[buffSize]; + assert(buffSize >= path.size()); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "\0") == 0); + return retval; + } + }, + { + "PathIterator::next4", + [](string) { + int retval = 0; + string path = "usr/share/charset.gbag"; + PathIterator it(path.c_str(), path.size()); + const auto buffSize = 1024; + char buff[buffSize]; + assert(buffSize >= path.size()); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0); + return retval; + } + }, + { + "PathIterator::next5", + [](string) { + int retval = 0; + string path = "usr/share/"; + PathIterator it(path.c_str(), path.size()); + const auto buffSize = 1024; + char buff[buffSize]; + assert(buffSize >= path.size()); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "usr") == 0); + retval |= !(it.next(buff, path.size()) == 0 && ox_strcmp(buff, "share") == 0); + return retval; + } + }, + { + "PathIterator::dirPath", + [] (string) { + int retval = 0; + string path = "/usr/share/charset.gbag"; + PathIterator it(path.c_str(), path.size()); + const auto buffSize = 1024; + char buff[buffSize]; + assert(buffSize >= path.size()); + retval |= !(it.dirPath(buff, path.size()) == 0 && ox_strcmp(buff, "/usr/share/") == 0); + return retval; + } + }, + { + "PathIterator::fileName", + [](string) { + int retval = 0; + string path = "/usr/share/charset.gbag"; + PathIterator it(path.c_str(), path.size()); + const auto buffSize = 1024; + char buff[buffSize]; + assert(buffSize >= path.size()); + retval |= !(it.fileName(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0); + return retval; + } + }, + { + "FileSystem32::findInodeOf /", + [](string) { + int retval = 0; + const auto size = 1024; + uint8_t buff[size]; + FileSystem32::format(buff, (FileStore32::FsSize_t) size, true); + auto fs = (FileSystem32*) createFileSystem(buff, size); + retval |= !(fs->findInodeOf("/") == FileSystem32::INODE_ROOT_DIR); + delete fs; + return retval; + } + }, + { + "FileSystem32::write(string)", + [](string) { + int retval = 0; + auto path = "/usr/share/test.txt"; + auto dataIn = "test string"; + auto dataOutLen = ox_strlen(dataIn) + 1; + auto dataOut = new char[dataOutLen]; + + const auto size = 1024 * 1024; + auto buff = new uint8_t[size]; + FileSystem32::format(buff, (FileStore32::FsSize_t) size, true); + auto fs = (FileSystem32*) createFileSystem(buff, size); + + retval |= fs->mkdir("/usr"); + retval |= fs->mkdir("/usr/share"); + retval |= fs->mkdir("/usr/lib"); + + retval |= fs->write(path, (void*) dataIn, ox_strlen(dataIn) + 1); + retval |= fs->read(path, dataOut, dataOutLen); + retval |= ox_strcmp(dataIn, dataOut) != 0; + + delete fs; + delete []buff; + delete []dataOut; + + return retval; + } + }, + { + "FileSystem32::rmDirectoryEntry(string)", + [](string) { + int retval = 0; + auto path = "/usr/share/test.txt"; + auto dataIn = "test string"; + auto dataOutLen = ox_strlen(dataIn) + 1; + auto dataOut = new char[dataOutLen]; + + const auto size = 1024 * 1024 * 10; + auto buff = new uint8_t[size]; + FileSystem32::format(buff, (FileStore32::FsSize_t) size, true); + auto fs = (FileSystem32*) createFileSystem(buff, size); + + retval |= fs->mkdir("/usr"); + retval |= fs->mkdir("/usr/share"); + + retval |= fs->write(path, (void*) dataIn, ox_strlen(dataIn) + 1); + retval |= fs->read(path, dataOut, dataOutLen); + retval |= ox_strcmp(dataIn, dataOut) != 0; + + retval |= fs->rmDirectoryEntry(path); + // the lookup should fail + retval |= fs->read(path, dataOut, dataOutLen) == 0; + + delete fs; + delete []buff; + delete []dataOut; + + return retval; + } + }, + { + "FileSystem32::remove(string, true)", + [](string) { + int retval = 0; + auto dataIn = "test string"; + auto dataOutLen = 1024 * 64; + auto dataOut = new char[dataOutLen]; + vector inodes; + + const auto size = 1024 * 1024; + auto buff = new uint8_t[size]; + FileSystem32::format(buff, (FileStore32::FsSize_t) size, true); + auto fs = (FileSystem32*) createFileSystem(buff, size); + + retval |= fs->mkdir("/usr"); + retval |= fs->mkdir("/usr/share"); + retval |= fs->write("/usr/share/test.txt", (void*) dataIn, ox_strlen(dataIn) + 1); + + inodes.push_back(fs->stat("/usr").inode); + inodes.push_back(fs->stat("/usr/share").inode); + inodes.push_back(fs->stat("/usr/share/test.txt").inode); + + retval |= fs->remove("/usr", true); + + // the lookup should fail + for (auto inode : inodes) { + retval |= fs->read(inode, dataOut, dataOutLen) == 0; + } + + delete fs; + delete []buff; + delete []dataOut; + + return retval; + } + }, + { + "FileSystem32::move", + [](string) { + int retval = 0; + auto dataIn = "test string"; + auto dataOutLen = ox_strlen(dataIn) + 1; + auto dataOut = new char[dataOutLen]; + vector inodes; + + const auto size = 1024 * 1024; + auto buff = new uint8_t[size]; + FileSystem32::format(buff, (FileStore32::FsSize_t) size, true); + auto fs = (FileSystem32*) createFileSystem(buff, size); + + retval |= fs->mkdir("/usr"); + retval |= fs->mkdir("/usr/share"); + retval |= fs->write("/usr/share/test.txt", (void*) dataIn, ox_strlen(dataIn) + 1); + + retval |= fs->move("/usr/share", "/share"); + retval |= fs->read("/share/test.txt", dataOut, dataOutLen); + retval |= !(ox_strcmp(dataIn, dataOut) == 0); + + delete fs; + delete []buff; + delete []dataOut; + + return retval; + } + }, + { + "FileSystem32::stripDirectories", + [](string) { + int retval = 0; + auto dataIn = "test string"; + auto dataOutLen = ox_strlen(dataIn) + 1; + auto dataOut = new char[dataOutLen]; + vector inodes; + + const auto size = 1024 * 1024; + auto buff = new uint8_t[size]; + FileSystem32::format(buff, (FileStore32::FsSize_t) size, true); + auto fs = (FileSystem32*) createFileSystem(buff, size); + + retval |= fs->mkdir("/usr"); + retval |= fs->mkdir("/usr/share"); + retval |= fs->write("/usr/share/test.txt", (void*) dataIn, ox_strlen(dataIn) + 1); + + auto inode = fs->stat("/usr/share/test.txt").inode; + + retval |= fs->stripDirectories(); + + // make sure normal file is still there and the directories are gone + retval |= fs->read(inode, dataOut, dataOutLen); + retval |= !(ox_strcmp(dataIn, dataOut) == 0); + retval |= !(fs->stat("/usr").inode == 0); + retval |= !(fs->stat("/usr/share").inode == 0); + + delete fs; + delete []buff; + delete []dataOut; + + return retval; + } + }, + { + "FileSystem32::ls", + [](string) { + int retval = 0; + auto dataIn = "test string"; + auto dataOutLen = ox_strlen(dataIn) + 1; + auto dataOut = new char[dataOutLen]; + vector inodes; + vector> files; + + const auto size = 1024 * 1024; + auto buff = new uint8_t[size]; + FileSystem32::format(buff, (FileStore32::FsSize_t) size, true); + auto fs = (FileSystem32*) createFileSystem(buff, size); + + retval |= fs->mkdir("/usr"); + retval |= fs->mkdir("/usr/share"); + retval |= fs->write("/usr/share/a.txt", (void*) dataIn, ox_strlen(dataIn) + 1); + retval |= fs->write("/usr/share/b.txt", (void*) dataIn, ox_strlen(dataIn) + 1); + retval |= fs->write("/usr/share/c.txt", (void*) dataIn, ox_strlen(dataIn) + 1); + + fs->ls("/usr/share/", &files); + + retval |= !(files[0].name == "."); + retval |= !(files[1].name == ".."); + retval |= !(files[2].name == "a.txt"); + retval |= !(files[3].name == "b.txt"); + retval |= !(files[4].name == "c.txt"); + + delete fs; + delete []buff; + delete []dataOut; + + return retval; + } + }, + }, +}; + +int main(int argc, const char **args) { + int retval = -1; + if (argc > 1) { + auto testName = args[1]; + string testArg = ""; + if (args[2]) { + testArg = args[2]; + } + if (tests.find(testName) != tests.end()) { + retval = tests[testName](testArg); + } + } + return retval; +} diff --git a/deps/ox/src/ox/fs/toollib.cpp b/deps/ox/src/ox/fs/toollib.cpp new file mode 100644 index 00000000..fc7836e9 --- /dev/null +++ b/deps/ox/src/ox/fs/toollib.cpp @@ -0,0 +1,33 @@ +/* + * Copyright 2015 - 2017 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 +#include + +#include "toollib.hpp" + +uint8_t *loadFileBuff(FILE *file, ::size_t *sizeOut) { + if (file) { + fseek(file, 0, SEEK_END); + const auto size = ftell(file); + rewind(file); + auto buff = new uint8_t[size]; + auto itemsRead = fread(buff, size, 1, file); + fclose(file); + if (sizeOut) { + *sizeOut = itemsRead ? size : 0; + } + return buff; + } else { + return nullptr; + } +} + +uint8_t *loadFileBuff(const char *path, ::size_t *sizeOut) { + return loadFileBuff(fopen(path, "rb"), sizeOut); +} diff --git a/deps/ox/src/ox/fs/toollib.hpp b/deps/ox/src/ox/fs/toollib.hpp new file mode 100644 index 00000000..8c51b776 --- /dev/null +++ b/deps/ox/src/ox/fs/toollib.hpp @@ -0,0 +1,14 @@ +/* + * Copyright 2015 - 2017 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 +#include + +uint8_t *loadFileBuff(FILE *file, size_t *sizeOut = nullptr); + +uint8_t *loadFileBuff(const char *path, size_t *sizeOut = nullptr); diff --git a/deps/ox/src/ox/log/CMakeLists.txt b/deps/ox/src/ox/log/CMakeLists.txt new file mode 100644 index 00000000..ca9dfcc4 --- /dev/null +++ b/deps/ox/src/ox/log/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 2.8) + +add_library( + OxLog + log.cpp +) + +set_property( + TARGET + OxLog + PROPERTY + POSITION_INDEPENDENT_CODE ON +) + +install( + FILES + log.hpp + DESTINATION + include/ox/mc +) + +install(TARGETS OxLog + LIBRARY DESTINATION lib/ox + ARCHIVE DESTINATION lib/ox +) diff --git a/deps/ox/src/ox/log/log.cpp b/deps/ox/src/ox/log/log.cpp new file mode 100644 index 00000000..0624fd0d --- /dev/null +++ b/deps/ox/src/ox/log/log.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2015 - 2017 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 +#include + +#include "log.hpp" + +namespace ox { + +class Logger { + + private: + // void* stand-in for FILE* + const char *m_path = nullptr; + + public: + Logger(const char *path = nullptr); + + ~Logger(); + + void log(LogLevel_t level, const char *msg, va_list args); + + void info(const char *msg, ...); + + void debug(const char *msg, ...); + + void error(const char *msg, ...); +}; + +Logger::Logger(const char *path) { + m_path = path; +} + +Logger::~Logger() { +} + +void Logger::log(LogLevel_t level, const char *msg, va_list args) { + if (m_path) { + auto file = fopen(m_path, "a"); + vfprintf(file, msg, args); + fprintf(file, "\n"); + fclose(file); + } +} + +void Logger::info(const char *msg, ...) { + va_list args; + va_start(args, msg); + log(LogLevel_t::Info, msg, args); + va_end(args); +} + +void Logger::debug(const char *msg, ...) { + va_list args; + va_start(args, msg); + log(LogLevel_t::Debug, msg, args); + va_end(args); +} + +void Logger::error(const char *msg, ...) { + va_list args; + va_start(args, msg); + log(LogLevel_t::Error, msg, args); + va_end(args); +} + + +static Logger logger; + +void logFile(const char *path) { + logger = Logger(path); +} + +void log(LogLevel_t level, const char *msg, va_list args) { + logger.log(level, msg, args); +} + +void info(const char *msg, ...) { + va_list args; + va_start(args, msg); + log(LogLevel_t::Info, msg, args); + va_end(args); +} + +void debug(const char *msg, ...) { + va_list args; + va_start(args, msg); + log(LogLevel_t::Debug, msg, args); + va_end(args); +} + +void error(const char *msg, ...) { + va_list args; + va_start(args, msg); + log(LogLevel_t::Error, msg, args); + va_end(args); +} + +} diff --git a/deps/ox/src/ox/log/log.hpp b/deps/ox/src/ox/log/log.hpp new file mode 100644 index 00000000..29b7ccf3 --- /dev/null +++ b/deps/ox/src/ox/log/log.hpp @@ -0,0 +1,27 @@ +/* + * Copyright 2015 - 2017 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 LogLevel_t: int { + Info, + Debug, + Error, +}; + +void logFile(const char *path); + +void info(const char *msg, ...); + +void debug(const char *msg, ...); + +void error(const char *msg, ...); + +} diff --git a/deps/ox/src/ox/mc/CMakeLists.txt b/deps/ox/src/ox/mc/CMakeLists.txt new file mode 100644 index 00000000..0312e35f --- /dev/null +++ b/deps/ox/src/ox/mc/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8) + +add_library( + OxMetalClaw + presencemask.cpp + read.cpp + write.cpp +) + +set_property( + TARGET + OxMetalClaw + PROPERTY + POSITION_INDEPENDENT_CODE ON +) + +install( + FILES + err.hpp + presencemask.hpp + read.hpp + write.hpp + DESTINATION + include/ox/mc +) + +install(TARGETS OxMetalClaw + LIBRARY DESTINATION lib/ox + ARCHIVE DESTINATION lib/ox +) + +if(OX_RUN_TESTS STREQUAL "ON") + add_subdirectory(test) +endif() diff --git a/deps/ox/src/ox/mc/err.hpp b/deps/ox/src/ox/mc/err.hpp new file mode 100644 index 00000000..19510387 --- /dev/null +++ b/deps/ox/src/ox/mc/err.hpp @@ -0,0 +1,19 @@ +/* + * Copyright 2015 - 2017 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 { + MC_PRESENCEMASKOUTBOUNDS = 1, + MC_BUFFENDED = 2, + MC_OUTBUFFENDED = 4 +}; + +} diff --git a/deps/ox/src/ox/mc/mc.hpp b/deps/ox/src/ox/mc/mc.hpp new file mode 100644 index 00000000..953e4721 --- /dev/null +++ b/deps/ox/src/ox/mc/mc.hpp @@ -0,0 +1,12 @@ +/* + * Copyright 2015 - 2017 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" diff --git a/deps/ox/src/ox/mc/presencemask.cpp b/deps/ox/src/ox/mc/presencemask.cpp new file mode 100644 index 00000000..2ae87bb3 --- /dev/null +++ b/deps/ox/src/ox/mc/presencemask.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2015 - 2017 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 +#include "err.hpp" +#include "presencemask.hpp" + +namespace ox { + +FieldPresenseMask::FieldPresenseMask(uint8_t *mask, size_t maxLen) { + m_mask = mask; + m_maxLen = maxLen; +} + +bool FieldPresenseMask::get(int i) { + if (i / 8 < m_maxLen) { + return (m_mask[i / 8] >> (i % 8)) & 1; + } else { + return MC_PRESENCEMASKOUTBOUNDS; + } +} + +int FieldPresenseMask::set(int i, bool on) { + if (i / 8 < m_maxLen) { + if (on) { + m_mask[i / 8] |= 1 << (i % 8); + } else { + m_mask[i / 8] &= ~(1 << (i % 8)); + } + return 0; + } else { + return MC_PRESENCEMASKOUTBOUNDS; + } +} + +void FieldPresenseMask::setMaxLen(int maxLen) { + m_maxLen = maxLen; +} + +int FieldPresenseMask::getMaxLen() { + return m_maxLen; +} + +} diff --git a/deps/ox/src/ox/mc/presencemask.hpp b/deps/ox/src/ox/mc/presencemask.hpp new file mode 100644 index 00000000..13da66c3 --- /dev/null +++ b/deps/ox/src/ox/mc/presencemask.hpp @@ -0,0 +1,32 @@ +/* + * Copyright 2015 - 2017 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 + +namespace ox { + +class FieldPresenseMask { + private: + uint8_t *m_mask; + int m_maxLen = 0; + + public: + FieldPresenseMask(uint8_t *mask, size_t maxLen); + + bool get(int i); + + int set(int i, bool on); + + void setMaxLen(int); + + int getMaxLen(); +}; + +} diff --git a/deps/ox/src/ox/mc/read.cpp b/deps/ox/src/ox/mc/read.cpp new file mode 100644 index 00000000..3d4f5100 --- /dev/null +++ b/deps/ox/src/ox/mc/read.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include "read.hpp" + +namespace ox { + +MetalClawReader::MetalClawReader(uint8_t *buff, size_t buffLen): m_fieldPresence(buff, buffLen) { + m_buff = buff; + m_buffLen = buffLen; +} + +int MetalClawReader::op(const char*, int16_t *val) { + return readInteger(val); +} + +int MetalClawReader::op(const char*, int32_t *val) { + return readInteger(val); +} + +int MetalClawReader::op(const char*, int64_t *val) { + return readInteger(val); +} + +int MetalClawReader::op(const char*, uint16_t *val) { + return readInteger(val); +} + +int MetalClawReader::op(const char*, uint32_t *val) { + return readInteger(val); +} + +int MetalClawReader::op(const char*, uint64_t *val) { + return readInteger(val); +} + +int MetalClawReader::op(const char*, bool *val) { + *val = m_fieldPresence.get(m_field++); + return 0; +} + +void MetalClawReader::setFields(int fields) { + m_fields = fields; + m_buffIt = (fields / 8 + 1) - (fields % 8 == 0); + m_fieldPresence.setMaxLen(m_buffIt); +} + +} diff --git a/deps/ox/src/ox/mc/read.hpp b/deps/ox/src/ox/mc/read.hpp new file mode 100644 index 00000000..11b39287 --- /dev/null +++ b/deps/ox/src/ox/mc/read.hpp @@ -0,0 +1,154 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include "err.hpp" +#include "presencemask.hpp" + +namespace ox { + +class MetalClawReader { + + private: + FieldPresenseMask m_fieldPresence; + int m_fields = 0; + int m_field = 0; + size_t m_buffIt = 0; + size_t m_buffLen = 0; + uint8_t *m_buff = nullptr; + + public: + MetalClawReader(uint8_t *buff, size_t buffLen); + + int op(const char*, int16_t *val); + int op(const char*, int32_t *val); + int op(const char*, int64_t *val); + + int op(const char*, uint16_t *val); + int op(const char*, uint32_t *val); + int op(const char*, uint64_t *val); + + int op(const char*, bool *val); + + template + int op(const char*, T *val, size_t len); + + template + int op(const char*, T *val); + + template + int op(const char*, ox::bstring *val); + + void setFields(int fields); + + private: + template + int readInteger(I *val); +}; + +template +int MetalClawReader::op(const char*, T *val) { + int err = 0; + if (m_fieldPresence.get(m_field)) { + MetalClawReader reader(m_buff + m_buffIt, m_buffLen - m_buffIt); + err |= ioOp(&reader, val); + m_buffIt += reader.m_buffIt; + } + m_field++; + return err; +}; + +template +int MetalClawReader::op(const char*, ox::bstring *val) { + int err = 0; + if (m_fieldPresence.get(m_field)) { + // read the length + typedef uint32_t StringLength; + size_t size = 0; + if (m_buffIt + sizeof(StringLength) < m_buffLen) { + size = ox::bigEndianAdapt(*((StringLength*) &m_buff[m_buffIt])); + m_buffIt += sizeof(StringLength); + } else { + err |= MC_BUFFENDED; + } + + // read the string + if (val->cap() >= size) { + if (m_buffIt + size < m_buffLen) { + ox_memcpy(val, &m_buff[m_buffIt], size); + m_buffIt += size; + } else { + err |= MC_BUFFENDED; + } + } else { + err |= MC_OUTBUFFENDED; + } + } else { + *val = ""; + } + m_field++; + return err; +}; + +template +int MetalClawReader::readInteger(I *val) { + int err = 0; + if (m_fieldPresence.get(m_field)) { + if (m_buffIt + sizeof(I) < m_buffLen) { + *val = ox::bigEndianAdapt(*((I*) &m_buff[m_buffIt])); + m_buffIt += sizeof(I); + } else { + err = MC_BUFFENDED; + } + } else { + *val = 0; + } + m_field++; + return err; +}; + +template +int MetalClawReader::op(const char*, T *val, size_t valLen) { + int err = 0; + if (m_fieldPresence.get(m_field)) { + // read the length + typedef uint32_t ArrayLength; + size_t len = 0; + if (m_buffIt + sizeof(ArrayLength) < m_buffLen) { + len = ox::bigEndianAdapt(*((T*) &m_buff[m_buffIt])); + m_buffIt += sizeof(ArrayLength); + } else { + err = MC_BUFFENDED; + } + + // read the list + if (valLen >= len) { + MetalClawReader reader(m_buff + m_buffIt, m_buffLen - m_buffIt); + reader.setFields(len); + for (size_t i = 0; i < len; i++) { + err |= reader.op("", &val[i]); + } + m_buffIt += reader.m_buffIt; + } else { + err = MC_OUTBUFFENDED; + } + } + m_field++; + return err; +}; + +template +int read(uint8_t *buff, size_t buffLen, T *val) { + MetalClawReader reader(buff, buffLen); + return ioOp(&reader, val); +} + +} diff --git a/deps/ox/src/ox/mc/test/CMakeLists.txt b/deps/ox/src/ox/mc/test/CMakeLists.txt new file mode 100644 index 00000000..26848191 --- /dev/null +++ b/deps/ox/src/ox/mc/test/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 2.8) + +add_executable( + McTest + tests.cpp +) + +target_link_libraries( + McTest + OxMetalClaw + OxStd + OxLog +) + +add_test("Test\\ McTest\\ Writer" McTest MetalClawWriter) +add_test("Test\\ McTest\\ Reader" McTest MetalClawReader) diff --git a/deps/ox/src/ox/mc/test/tests.cpp b/deps/ox/src/ox/mc/test/tests.cpp new file mode 100644 index 00000000..4190f7e6 --- /dev/null +++ b/deps/ox/src/ox/mc/test/tests.cpp @@ -0,0 +1,158 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace ox; + +struct TestStructNest { + bool Bool = false; + uint32_t Int = 0; + 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; + bstring<32> String = ""; + uint32_t List[4] = {0, 0, 0 , 0}; + TestStructNest EmptyStruct; + TestStructNest Struct; +}; + +template +int ioOp(T *io, TestStructNest *obj) { + int32_t err = 0; + io->setFields(3); + err |= io->op("Bool", &obj->Bool); + err |= io->op("Int", &obj->Int); + err |= io->op("String", &obj->String); + return err; +} + +template +int ioOp(T *io, TestStruct *obj) { + int err = 0; + io->setFields(13); + err |= io->op("Bool", &obj->Bool); + err |= io->op("Int", &obj->Int); + err |= io->op("Int1", &obj->Int1); + err |= io->op("Int2", &obj->Int2); + err |= io->op("Int3", &obj->Int3); + err |= io->op("Int4", &obj->Int4); + err |= io->op("Int5", &obj->Int5); + err |= io->op("Int6", &obj->Int6); + err |= io->op("Int7", &obj->Int7); + err |= io->op("Int8", &obj->Int8); + err |= io->op("String", &obj->String); + err |= io->op("List", obj->List, 4); + err |= io->op("EmptyStruct", &obj->EmptyStruct); + err |= io->op("Struct", &obj->Struct); + return err; +} + +map tests = { + { + { + "MetalClawWriter", + [](string) { + // This test doesn't confirm much, but it does show that the writer + // doesn't segfault + size_t buffLen = 1024; + auto buff = new uint8_t[buffLen]; + int err = 0; + TestStruct ts; + + err |= write(buff, buffLen, &ts); + + delete []buff; + + return err; + } + }, + { + "MetalClawReader", + [](string) { + int err = 0; + size_t buffLen = 1024; + auto buff = new uint8_t[buffLen]; + 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"; + + err |= write(buff, buffLen, &testIn); + err |= read(buff, buffLen, &testOut); + + err |= !(testIn.Bool == testOut.Bool); + err |= !(testIn.Int == testOut.Int); + err |= !(testIn.Int1 == testOut.Int1); + err |= !(testIn.Int2 == testOut.Int2); + err |= !(testIn.Int3 == testOut.Int3); + err |= !(testIn.Int4 == testOut.Int4); + err |= !(testIn.Int5 == testOut.Int5); + err |= !(testIn.Int6 == testOut.Int6); + err |= !(testIn.Int7 == testOut.Int7); + err |= !(testIn.Int8 == testOut.Int8); + err |= !(testIn.String == testOut.String); + err |= !(testIn.List[0] == testOut.List[0]); + err |= !(testIn.List[1] == testOut.List[1]); + err |= !(testIn.List[2] == testOut.List[2]); + err |= !(testIn.List[3] == testOut.List[3]); + err |= !(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool); + err |= !(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int); + err |= !(testIn.EmptyStruct.String == testOut.EmptyStruct.String); + err |= !(testIn.Struct.Int == testOut.Struct.Int); + err |= !(testIn.Struct.String == testOut.Struct.String); + err |= !(testIn.Struct.Bool == testOut.Struct.Bool); + + delete []buff; + + return err; + } + }, + } +}; + +int main(int argc, const char **args) { + int retval = -1; + if (argc > 1) { + auto testName = args[1]; + string testArg = ""; + if (args[2]) { + testArg = args[2]; + } + if (tests.find(testName) != tests.end()) { + retval = tests[testName](testArg); + } + } + return retval; +} diff --git a/deps/ox/src/ox/mc/write.cpp b/deps/ox/src/ox/mc/write.cpp new file mode 100644 index 00000000..cf214d0e --- /dev/null +++ b/deps/ox/src/ox/mc/write.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include "write.hpp" + +namespace ox { + +MetalClawWriter::MetalClawWriter(uint8_t *buff, size_t buffLen): m_fieldPresence(buff, buffLen) { + m_buff = buff; + m_buffLen = buffLen; +} + +int MetalClawWriter::op(const char*, int16_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, int32_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, int64_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, uint16_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, uint32_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, uint64_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, bool *val) { + return m_fieldPresence.set(m_field++, *val); +} + +void MetalClawWriter::setFields(int fields) { + m_fields = fields; + m_buffIt = (fields / 8 + 1) - (fields % 8 == 0); + m_fieldPresence.setMaxLen(m_buffIt); +} + +} diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp new file mode 100644 index 00000000..8380b3c7 --- /dev/null +++ b/deps/ox/src/ox/mc/write.hpp @@ -0,0 +1,152 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include "err.hpp" +#include "presencemask.hpp" + +namespace ox { + +class MetalClawWriter { + + private: + FieldPresenseMask m_fieldPresence; + int m_fields = 0; + int m_field = 0; + size_t m_buffIt = 0; + size_t m_buffLen = 0; + uint8_t *m_buff = nullptr; + + public: + MetalClawWriter(uint8_t *buff, size_t buffLen); + + int op(const char*, int16_t *val); + int op(const char*, int32_t *val); + int op(const char*, int64_t *val); + + int op(const char*, uint16_t *val); + int op(const char*, uint32_t *val); + int op(const char*, uint64_t *val); + + int op(const char*, bool *val); + + template + int op(const char*, T *val, size_t len); + + template + int op(const char*, ox::bstring *val); + + template + int op(const char*, T *val); + + void setFields(int fields); + + private: + template + int appendInteger(I val); +}; + +template +int MetalClawWriter::op(const char*, ox::bstring *val) { + int err = 0; + bool fieldSet = false; + if (val->len()) { + // write the length + typedef uint32_t StringLength; + if (m_buffIt + sizeof(StringLength) + val->size() < m_buffLen) { + *((StringLength*) &m_buff[m_buffIt]) = ox::bigEndianAdapt((StringLength) val->size()); + m_buffIt += sizeof(StringLength); + + // write the string + ox_memcpy(&m_buff[m_buffIt], val, val->size()); + m_buffIt += val->size(); + fieldSet = true; + } else { + err = MC_BUFFENDED; + } + } + err |= m_fieldPresence.set(m_field, fieldSet); + m_field++; + return err; +}; + +template +int MetalClawWriter::op(const char*, T *val) { + int err = 0; + bool fieldSet = false; + MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); + err |= ioOp(&writer, val); + if ((size_t) writer.m_fieldPresence.getMaxLen() < writer.m_buffIt) { + m_buffIt += writer.m_buffIt; + fieldSet = true; + } + err |= m_fieldPresence.set(m_field, fieldSet); + m_field++; + return err; +}; + +template +int MetalClawWriter::appendInteger(I val) { + int err = 0; + bool fieldSet = false; + if (val) { + if (m_buffIt + sizeof(I) < m_buffLen) { + *((I*) &m_buff[m_buffIt]) = ox::bigEndianAdapt(val); + fieldSet = true; + m_buffIt += sizeof(I); + } else { + err |= MC_BUFFENDED; + } + } + err |= m_fieldPresence.set(m_field, fieldSet); + m_field++; + return err; +}; + +template +int MetalClawWriter::op(const char*, T *val, size_t len) { + int err = 0; + bool fieldSet = false; + + if (len) { + // write the length + typedef uint32_t ArrayLength; + if (m_buffIt + sizeof(ArrayLength) < m_buffLen) { + *((T*) &m_buff[m_buffIt]) = ox::bigEndianAdapt((ArrayLength) len); + m_buffIt += sizeof(ArrayLength); + } else { + err = MC_BUFFENDED; + } + + MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); + writer.setFields(len); + + // write the array + for (size_t i = 0; i < len; i++) { + err |= writer.op("", &val[i]); + } + + m_buffIt += writer.m_buffIt; + fieldSet = true; + } + + err |= m_fieldPresence.set(m_field, fieldSet); + m_field++; + return err; +}; + +template +int write(uint8_t *buff, size_t buffLen, T *val) { + MetalClawWriter writer(buff, buffLen); + return ioOp(&writer, val); +} + +} diff --git a/deps/ox/src/ox/std/CMakeLists.txt b/deps/ox/src/ox/std/CMakeLists.txt new file mode 100644 index 00000000..5bd0ac2b --- /dev/null +++ b/deps/ox/src/ox/std/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 2.8) + +add_library( + OxStd + memops.cpp + random.cpp + strops.cpp +) + +set_property( + TARGET + OxStd + PROPERTY + POSITION_INDEPENDENT_CODE ON +) + +install( + FILES + bitops.hpp + byteswap.hpp + memops.hpp + random.hpp + string.hpp + strops.hpp + std.hpp + types.hpp + DESTINATION + include/ox/std +) + +install(TARGETS OxStd + LIBRARY DESTINATION lib/ox + ARCHIVE DESTINATION lib/ox +) + +if(OX_RUN_TESTS STREQUAL "ON") + add_subdirectory(test) +endif() diff --git a/deps/ox/src/ox/std/bitops.hpp b/deps/ox/src/ox/std/bitops.hpp new file mode 100644 index 00000000..86379023 --- /dev/null +++ b/deps/ox/src/ox/std/bitops.hpp @@ -0,0 +1,19 @@ +/* + * Copyright 2015 - 2017 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 "types.hpp" + +namespace ox { + +inline uint64_t rotateLeft(uint64_t i, int shift) { + return (i << shift) | (i >> (64 - shift)); +} + +} diff --git a/deps/ox/src/ox/std/byteswap.hpp b/deps/ox/src/ox/std/byteswap.hpp new file mode 100644 index 00000000..9bb199ee --- /dev/null +++ b/deps/ox/src/ox/std/byteswap.hpp @@ -0,0 +1,141 @@ +/* + * Copyright 2015 - 2017 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 "types.hpp" + +namespace ox { + +inline int16_t byteSwap(int16_t i) { + return (i << 8) | (i >> 8); +} + +inline int32_t byteSwap(int32_t i) { + return ((i >> 24) & 0x000000ff) | + ((i >> 8) & 0x0000ff00) | + ((i << 8) & 0x00ff0000) | + ((i << 24) & 0xff000000); +} + +inline int64_t byteSwap(int64_t i) { + return ((i >> 56) & 0x00000000000000ff) | + ((i >> 40) & 0x000000000000ff00) | + ((i >> 24) & 0x0000000000ff0000) | + ((i >> 8) & 0x00000000ff000000) | + ((i << 8) & 0x000000ff00000000) | + ((i << 24) & 0x0000ff0000000000) | + ((i << 40) & 0x00ff000000000000) | + ((i << 56) & 0xff00000000000000); +} + +inline uint16_t byteSwap(uint16_t i) { + return (i << 8) | (i >> 8); +} + +inline uint32_t byteSwap(uint32_t i) { + return ((i >> 24) & 0x000000ff) | + ((i >> 8) & 0x0000ff00) | + ((i << 8) & 0x00ff0000) | + ((i << 24) & 0xff000000); +} + +inline uint64_t byteSwap(uint64_t i) { + return ((i >> 56) & 0x00000000000000ff) | + ((i >> 40) & 0x000000000000ff00) | + ((i >> 24) & 0x0000000000ff0000) | + ((i >> 8) & 0x00000000ff000000) | + ((i << 8) & 0x000000ff00000000) | + ((i << 24) & 0x0000ff0000000000) | + ((i << 40) & 0x00ff000000000000) | + ((i << 56) & 0xff00000000000000); +} + + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline int8_t bigEndianAdapt(int8_t i) { + return i; +} + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline int16_t bigEndianAdapt(int16_t i) { +#ifdef __BIG_ENDIAN__ + return byteSwap(i); +#else + return i; +#endif +} + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline int32_t bigEndianAdapt(int32_t i) { +#ifdef __BIG_ENDIAN__ + return byteSwap(i); +#else + return i; +#endif +} + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline int64_t bigEndianAdapt(int64_t i) { +#ifdef __BIG_ENDIAN__ + return byteSwap(i); +#else + return i; +#endif +} + + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline uint8_t bigEndianAdapt(uint8_t i) { + return i; +} + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline uint16_t bigEndianAdapt(uint16_t i) { +#ifdef __BIG_ENDIAN__ + return byteSwap(i); +#else + return i; +#endif +} + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline uint32_t bigEndianAdapt(uint32_t i) { +#ifdef __BIG_ENDIAN__ + return byteSwap(i); +#else + return i; +#endif +} + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline uint64_t bigEndianAdapt(uint64_t i) { +#ifdef __BIG_ENDIAN__ + return byteSwap(i); +#else + return i; +#endif +} + +} diff --git a/deps/ox/src/ox/std/memops.cpp b/deps/ox/src/ox/std/memops.cpp new file mode 100644 index 00000000..ab7b5779 --- /dev/null +++ b/deps/ox/src/ox/std/memops.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2015 - 2017 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 "memops.hpp" + +int ox_memcmp(const void *ptr1, const void *ptr2, size_t size) { + int retval = 0; + auto block1 = ((uint8_t*) ptr1); + auto block2 = ((uint8_t*) ptr2); + for (size_t i = 0; i < size; i++) { + if (block1[i] < block2[i]) { + retval = -1; + break; + } else if (block1[i] > block2[i]) { + retval = 1; + break; + } + } + return retval; +} + +void *ox_memcpy(void *dest, const void *src, int64_t size) { + char *srcBuf = (char*) src; + char *dstBuf = (char*) dest; + for (int64_t i = 0; i < size; i++) { + dstBuf[i] = (char) srcBuf[i]; + } + return dest; +} + +void *ox_memset(void *ptr, int val, int64_t size) { + char *buf = (char*) ptr; + for (int64_t i = 0; i < size; i++) { + buf[i] = val; + } + return ptr; +} diff --git a/deps/ox/src/ox/std/memops.hpp b/deps/ox/src/ox/std/memops.hpp new file mode 100644 index 00000000..ffba6669 --- /dev/null +++ b/deps/ox/src/ox/std/memops.hpp @@ -0,0 +1,16 @@ +/* + * Copyright 2015 - 2017 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 "types.hpp" + +int ox_memcmp(const void *ptr1, const void *ptr2, size_t size); + +void *ox_memcpy(void *src, const void *dest, int64_t size); + +void *ox_memset(void *ptr, int val, int64_t size); diff --git a/deps/ox/src/ox/std/random.cpp b/deps/ox/src/ox/std/random.cpp new file mode 100644 index 00000000..247cab5a --- /dev/null +++ b/deps/ox/src/ox/std/random.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2015 - 2017 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 "bitops.hpp" +#include "random.hpp" + +namespace ox { + +RandomSeed Random::DEFAULT_SEED = {540932923848, 540932540932}; + +Random::Random(RandomSeed seed) { + m_seed[0] = seed[0]; + m_seed[1] = seed[1]; +} + +uint64_t Random::gen() { + // An implementation of the Xoroshiro128+ algorithm + auto s0 = m_seed[0]; + auto s1 = m_seed[1]; + auto retval = s0 + s1; + + s1 ^= s0; + m_seed[0] = ox::rotateLeft(s0, 55) ^ s1 ^ (s1 << 14); + m_seed[1] = ox::rotateLeft(s1, 36); + + return retval; +} + +} + + +uint64_t ox_rand() { + static ox::Random rand; + return rand.gen(); +} diff --git a/deps/ox/src/ox/std/random.hpp b/deps/ox/src/ox/std/random.hpp new file mode 100644 index 00000000..43d4daaf --- /dev/null +++ b/deps/ox/src/ox/std/random.hpp @@ -0,0 +1,30 @@ +/* + * Copyright 2015 - 2017 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 + +uint64_t ox_rand(); + +namespace ox { + +typedef uint64_t RandomSeed[2]; + +class Random { + public: + static RandomSeed DEFAULT_SEED; + + private: + RandomSeed m_seed; + + public: + Random(RandomSeed seed = DEFAULT_SEED); + + uint64_t gen(); +}; + +} diff --git a/deps/ox/src/ox/std/std.hpp b/deps/ox/src/ox/std/std.hpp new file mode 100644 index 00000000..f0858ad6 --- /dev/null +++ b/deps/ox/src/ox/std/std.hpp @@ -0,0 +1,16 @@ +/* + * Copyright 2015 - 2017 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 "bitops.hpp" +#include "byteswap.hpp" +#include "memops.hpp" +#include "random.hpp" +#include "strops.hpp" +#include "string.hpp" +#include "types.hpp" diff --git a/deps/ox/src/ox/std/string.hpp b/deps/ox/src/ox/std/string.hpp new file mode 100644 index 00000000..31863db8 --- /dev/null +++ b/deps/ox/src/ox/std/string.hpp @@ -0,0 +1,128 @@ +/* + * Copyright 2015 - 2017 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 "memops.hpp" +#include "strops.hpp" +#include "types.hpp" + +namespace ox { + +// Bounded String +template +class bstring { + private: + uint8_t m_buff[buffLen]; + + public: + bstring(); + + bstring(const char *str); + + const bstring &operator=(const char *str); + + const bstring &operator=(char *str); + + bool operator==(const bstring &other); + + char *data(); + + /** + * Returns the number of characters in this string. + */ + size_t len(); + + /** + * Returns the number of bytes used for this string. + */ + size_t size(); + + /** + * Returns the capacity of bytes for this string. + */ + size_t cap(); +}; + +template +bstring::bstring() { + m_buff[0] = 0; +} + +template +bstring::bstring(const char *str) { + *this = str; +} + +template +const bstring &bstring::operator=(const char *str) { + size_t strLen = ox_strlen(str) + 1; + if (cap() < strLen) { + strLen = cap(); + } + ox_memcpy(m_buff, str, strLen); + // make sure last element is a null terminator + m_buff[cap() - 1] = 0; + return *this; +} + +template +const bstring &bstring::operator=(char *str) { + return *this = (const char*) str; +} + +template +bool bstring::operator==(const bstring &other) { + bool retval = true; + size_t i = 0; + while (i < buffLen && (m_buff[i] || other.m_buff[i])) { + if (m_buff[i] != other.m_buff[i]) { + retval = false; + break; + } + i++; + } + return retval; +} + +template +char *bstring::data() { + return (char*) m_buff; +} + +template +size_t bstring::len() { + size_t length = 0; + for (size_t i = 0; i < buffLen; i++) { + uint8_t b = m_buff[i]; + if (b) { + if ((b & 128) == 0) { // normal ASCII character + length++; + } else if ((b & (256 << 6)) == (256 << 6)) { // start of UTF-8 character + length++; + } + } else { + break; + } + } + return length; +} + +template +size_t bstring::size() { + size_t i; + for (i = 0; i < buffLen && m_buff[i]; i++); + return i + 1; // add one for null terminator +} + +template +size_t bstring::cap() { + return buffLen; +} + +} diff --git a/deps/ox/src/ox/std/strops.cpp b/deps/ox/src/ox/std/strops.cpp new file mode 100644 index 00000000..5176b9b0 --- /dev/null +++ b/deps/ox/src/ox/std/strops.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2015 - 2017 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 "strops.hpp" + +int ox_strcmp(const char *str1, const char *str2) { + auto retval = 0; + auto i = 0; + while (str1[i] || str2[i]) { + if (str1[i] < str2[i]) { + retval = -1; + break; + } else if (str1[i] > str2[i]) { + retval = 1; + break; + } + i++; + } + return retval; +} + +int ox_strlen(const char *str1) { + int len; + for (len = 0; str1[len]; len++); + return len; +} + +int ox_strlen(char *str1) { + int len; + for (len = 0; str1[len]; len++); + return len; +} + +const char *ox_strchr(const char *str, int character, size_t maxLen) { + for (size_t i = 0; i <= maxLen; i++) { + if (str[i] == character) { + return &str[i]; + } else if (str[i] == 0) { + return nullptr; + } + } + return nullptr; +} + +char *ox_strchr(char *str, int character, size_t maxLen) { + for (size_t i = 0; i < maxLen; i++) { + if (str[i] == character) { + return &str[i]; + } else if (str[i] == 0) { + return nullptr; + } + } + return nullptr; +} + +int ox_lastIndexOf(const char *str, int character, int maxLen) { + int retval = -1; + for (int i = 0; i < maxLen && str[i]; i++) { + if (str[i] == character) { + retval = i; + } + } + return retval; +} + +int ox_lastIndexOf(char *str, int character, int maxLen) { + int retval = -1; + for (int i = 0; i < maxLen && str[i]; i++) { + if (str[i] == character) { + retval = i; + } + } + return retval; +} + +int ox_atoi(const char *str) { + int total = 0; + int multiplier = 1; + + for (auto i = ox_strlen(str) - 1; i != -1; i--) { + total += (str[i] - '0') * multiplier; + multiplier *= 10; + } + + return total; +} diff --git a/deps/ox/src/ox/std/strops.hpp b/deps/ox/src/ox/std/strops.hpp new file mode 100644 index 00000000..4fc8b915 --- /dev/null +++ b/deps/ox/src/ox/std/strops.hpp @@ -0,0 +1,27 @@ +/* + * Copyright 2015 - 2017 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 "types.hpp" + +int ox_strcmp(const char *str1, const char *str2); + +int ox_strlen(const char *str1); + +int ox_strlen(char *str1); + +const char *ox_strchr(const char *str, int character, size_t maxLen = 0xFFFFFFFF); + +char *ox_strchr(char *str, int character, size_t maxLen = 0xFFFFFFFF); + +int ox_lastIndexOf(const char *str, int character, int maxLen = 0xFFFFFFFF); + +int ox_lastIndexOf(char *str, int character, int maxLen = 0xFFFFFFFF); + +int ox_atoi(const char *str); diff --git a/deps/ox/src/ox/std/test/CMakeLists.txt b/deps/ox/src/ox/std/test/CMakeLists.txt new file mode 100644 index 00000000..1b25b3ba --- /dev/null +++ b/deps/ox/src/ox/std/test/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 2.8) + +add_executable( + StdTest + tests.cpp +) + +target_link_libraries(StdTest OxLog OxStd) + +add_test("Test\\ ox_memcmp\\ ABCDEFG\\ !=\\ HIJKLMN" StdTest "ABCDEFG != HIJKLMN") +add_test("Test\\ ox_memcmp\\ HIJKLMN\\ !=\\ ABCDEFG" StdTest "HIJKLMN != ABCDEFG") +add_test("Test\\ ox_memcmp\\ ABCDEFG\\ ==\\ ABCDEFG" StdTest "ABCDEFG == ABCDEFG") +add_test("Test\\ ox_memcmp\\ ABCDEFGHI\\ ==\\ ABCDEFG" StdTest "ABCDEFGHI == ABCDEFG") + + +################################################################################ +# StrOps Tests + +add_executable( + StrOpsTest + strops_test.cpp +) + +target_link_libraries( + StrOpsTest + OxStd + OxLog +) + +add_test("Test\\ ox_strcmp\\ asdf\\ !=\\ hijk" StrOpsTest "asdf < hijk") +add_test("Test\\ ox_strcmp\\ hijk\\ !=\\ asdf" StrOpsTest "hijk > asdf") +add_test("Test\\ ox_strcmp\\ read\\ !=\\ resize" StrOpsTest "read < resize") +add_test("Test\\ ox_strcmp\\ resize\\ !=\\ read" StrOpsTest "resize > read") +add_test("Test\\ ox_strcmp\\ resize\\ ==\\ resize" StrOpsTest "resize == resize") +add_test("Test\\ ox_strcmp\\ ''\\ ==\\ ''" StrOpsTest " == ") +add_test("Test\\ ox_strchr\\ 0" StrOpsTest "ox_strchr 0") +add_test("Test\\ ox_lastIndexOf\\ aaaa\\ a" StrOpsTest "ox_lastIndexOf aaaa a") + + +################################################################################ +# Byte Swap Tests + +add_executable( + ByteSwapTest + byteswap_test.cpp +) + +target_link_libraries( + ByteSwapTest + OxStd + OxLog +) + +add_test("Test\\ bigEndianAdapt\\ 0x00ff" ByteSwapTest bigEndianAdapt 0x00ff) +add_test("Test\\ bigEndianAdapt\\ 0xff00" ByteSwapTest bigEndianAdapt 0xff00) + +add_test("Test\\ bigEndianAdapt\\ 0x000000ff" ByteSwapTest bigEndianAdapt 0x000000ff) +add_test("Test\\ bigEndianAdapt\\ 0x0000ff00" ByteSwapTest bigEndianAdapt 0x0000ff00) +add_test("Test\\ bigEndianAdapt\\ 0x00ff0000" ByteSwapTest bigEndianAdapt 0x00ff0000) +add_test("Test\\ bigEndianAdapt\\ 0xff000000" ByteSwapTest bigEndianAdapt 0xff000000) + +add_test("Test\\ bigEndianAdapt\\ 0x00000000000000ff" ByteSwapTest bigEndianAdapt 0x00000000000000ff) +add_test("Test\\ bigEndianAdapt\\ 0x000000000000ff00" ByteSwapTest bigEndianAdapt 0x000000000000ff00) +add_test("Test\\ bigEndianAdapt\\ 0x0000000000ff0000" ByteSwapTest bigEndianAdapt 0x0000000000ff0000) +add_test("Test\\ bigEndianAdapt\\ 0x00000000ff000000" ByteSwapTest bigEndianAdapt 0x00000000ff000000) +add_test("Test\\ bigEndianAdapt\\ 0x000000ff00000000" ByteSwapTest bigEndianAdapt 0x000000ff00000000) +add_test("Test\\ bigEndianAdapt\\ 0x0000ff0000000000" ByteSwapTest bigEndianAdapt 0x0000ff0000000000) +add_test("Test\\ bigEndianAdapt\\ 0x00ff000000000000" ByteSwapTest bigEndianAdapt 0x00ff000000000000) +add_test("Test\\ bigEndianAdapt\\ 0xff00000000000000" ByteSwapTest bigEndianAdapt 0xff00000000000000) diff --git a/deps/ox/src/ox/std/test/byteswap_test.cpp b/deps/ox/src/ox/std/test/byteswap_test.cpp new file mode 100644 index 00000000..ff05de99 --- /dev/null +++ b/deps/ox/src/ox/std/test/byteswap_test.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include + +using namespace std; +using namespace ox; + +template +int testBigEndianAdapt(string str) { + auto i = (T) stoull(str, nullptr, 16); + return !(bigEndianAdapt(bigEndianAdapt(i)) == i); +} + +map tests = { + { + { "bigEndianAdapt", testBigEndianAdapt }, + { "bigEndianAdapt", testBigEndianAdapt }, + { "bigEndianAdapt", testBigEndianAdapt }, + }, +}; + +int main(int argc, const char **args) { + int retval = -1; + if (argc > 1) { + auto testName = args[1]; + string testArg = args[2]; + if (tests.find(testName) != tests.end()) { + retval = tests[testName](testArg); + } + } + return retval; +} diff --git a/deps/ox/src/ox/std/test/strops_test.cpp b/deps/ox/src/ox/std/test/strops_test.cpp new file mode 100644 index 00000000..9aaf14be --- /dev/null +++ b/deps/ox/src/ox/std/test/strops_test.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include +#include + +using namespace std; + +map> tests = { + { + "asdf < hijk", + []() { + return !(ox_strcmp("asdf", "hijk") < 0); + } + }, + { + "hijk > asdf", + []() { + return !(ox_strcmp("hijk", "asdf") > 0); + } + }, + { + "resize > read", + []() { + return !(ox_strcmp("resize", "read") > 0); + } + }, + { + "read < resize", + []() { + return !(ox_strcmp("read", "resize") < 0); + } + }, + { + "resize == resize", + []() { + return !(ox_strcmp("resize", "resize") == 0); + } + }, + { + " == ", + []() { + return !(ox_strcmp("", "") == 0); + } + }, + { + "ox_strchr 0", + []() { + auto testStr = "asdf"; + return !(ox_strchr(testStr, 0, 4) == &testStr[4]); + } + }, + { + "ox_lastIndexOf aaaa a", + []() { + int retval = 0; + auto testStr = "aaaa"; + retval |= !(ox_lastIndexOf((char*) testStr, 'a', ox_strlen(testStr)) == 3); + retval |= !(ox_lastIndexOf((const char*) testStr, 'a', ox_strlen(testStr)) == 3); + return retval; + } + }, +}; + +int main(int argc, const char **args) { + if (argc > 1) { + auto testName = args[1]; + if (tests.find(testName) != tests.end()) { + return tests[testName](); + } + } + return -1; +} diff --git a/deps/ox/src/ox/std/test/tests.cpp b/deps/ox/src/ox/std/test/tests.cpp new file mode 100644 index 00000000..68c09b38 --- /dev/null +++ b/deps/ox/src/ox/std/test/tests.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2015 - 2017 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 +#include +#include +#include + +using namespace std; + +map> tests = { + { + "ABCDEFG != HIJKLMN", + []() { + return !(ox_memcmp("ABCDEFG", "HIJKLMN", 7) < 0); + } + }, + { + "HIJKLMN != ABCDEFG", + []() { + return !(ox_memcmp("HIJKLMN", "ABCDEFG", 7) > 0); + } + }, + { + "ABCDEFG == ABCDEFG", + []() { + return !(ox_memcmp("ABCDEFG", "ABCDEFG", 7) == 0); + } + }, + { + "ABCDEFGHI == ABCDEFG", + []() { + return !(ox_memcmp("ABCDEFGHI", "ABCDEFG", 7) == 0); + } + }, +}; + +int main(int argc, const char **args) { + if (argc > 1) { + auto testName = args[1]; + if (tests.find(testName) != tests.end()) { + return tests[testName](); + } + } + return -1; +} diff --git a/deps/ox/src/ox/std/types.hpp b/deps/ox/src/ox/std/types.hpp new file mode 100644 index 00000000..c57108f9 --- /dev/null +++ b/deps/ox/src/ox/std/types.hpp @@ -0,0 +1,40 @@ +/* + * Copyright 2015 - 2017 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 + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef unsigned uint_t; +#if defined(_WIN32) || defined(__APPLE__) || defined(__arm__) || defined(__ppc__) +typedef long long int64_t; +typedef unsigned long long uint64_t; +#else +typedef long int64_t; +typedef unsigned long uint64_t; +#endif + +namespace ox { + +typedef uint32_t Error; + +} + +#if defined(_LP64) || defined(__ppc64__) || defined(__aarch64__) +typedef unsigned long size_t; +#elif defined(_WIN64) +typedef uint64_t size_t; +#elif defined(_LP32) || defined(__ppc__) || defined(_WIN32) || defined(__arm__) +typedef uint32_t size_t; +#else +#error size_t undefined +#endif