Squashed 'deps/ox/' content from commit c63e0c1

git-subtree-dir: deps/ox
git-subtree-split: c63e0c1d72f30cfb7b3076c69744b0f53d4d79b1
This commit is contained in:
Gary Talent 2017-10-11 19:20:46 -05:00
commit 8559ab53cc
63 changed files with 5684 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
build/current
build/gba
build/*-debug
build/*-release
tags

9
.liccor.yml Normal file
View File

@ -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/.

11
.travis.yml Normal file
View File

@ -0,0 +1,11 @@
language: cpp
sudo: false
dist: trusty
compiler:
- clang
- gcc
addons:
apt:
packages:
- cmake
script: ./scripts/cibuild

44
CMakeLists.txt Normal file
View File

@ -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)

373
LICENSE Normal file
View File

@ -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.

72
Makefile Normal file
View File

@ -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

11
OxConfig.cmake Normal file
View File

@ -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 "")

32
build/Makefile Normal file
View File

@ -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

View File

@ -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)

41
cmake/Modules/GBA.cmake Normal file
View File

@ -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)

18
cmake/Modules/Mingw.cmake Normal file
View File

@ -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)

View File

@ -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)

8
scripts/cibuild Executable file
View File

@ -0,0 +1,8 @@
#! /usr/bin/env bash
set -e
make -j release
make -j debug
make -j
make -j test

30
scripts/setup_build Executable file
View File

@ -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

3
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 2.8)
add_subdirectory(ox)

9
src/ox/CMakeLists.txt Normal file
View File

@ -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)

View File

@ -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
)

53
src/ox/clargs/clargs.cpp Normal file
View File

@ -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 <ox/std/strops.hpp>
#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];
}
}

32
src/ox/clargs/clargs.hpp Normal file
View File

@ -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 <map>
#include <string>
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);
};
}

54
src/ox/fs/CMakeLists.txt Normal file
View File

@ -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()

923
src/ox/fs/filestore.hpp Normal file
View File

@ -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 <ox/std/std.hpp>
namespace ox {
template<typename FsT, typename InodeId>
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<typename FsSize_t, typename InodeId_t>
void FileStoreHeader<FsSize_t, InodeId_t>::setVersion(uint16_t version) {
m_version = bigEndianAdapt(version);
}
template<typename FsSize_t, typename InodeId_t>
uint16_t FileStoreHeader<FsSize_t, InodeId_t>::getVersion() {
return bigEndianAdapt(m_version);
}
template<typename FsSize_t, typename InodeId_t>
void FileStoreHeader<FsSize_t, InodeId_t>::setFsType(uint16_t fsType) {
m_fsType = bigEndianAdapt(fsType);
}
template<typename FsSize_t, typename InodeId_t>
uint16_t FileStoreHeader<FsSize_t, InodeId_t>::getFsType() {
return bigEndianAdapt(m_fsType);
}
template<typename FsSize_t, typename InodeId_t>
void FileStoreHeader<FsSize_t, InodeId_t>::setSize(FsSize_t size) {
m_size = bigEndianAdapt(size);
}
template<typename FsSize_t, typename InodeId_t>
FsSize_t FileStoreHeader<FsSize_t, InodeId_t>::getSize() {
return bigEndianAdapt(m_size);
}
template<typename FsSize_t, typename InodeId_t>
void FileStoreHeader<FsSize_t, InodeId_t>::setMemUsed(FsSize_t memUsed) {
m_memUsed = bigEndianAdapt(memUsed);
}
template<typename FsSize_t, typename InodeId_t>
FsSize_t FileStoreHeader<FsSize_t, InodeId_t>::getMemUsed() {
return bigEndianAdapt(m_memUsed);
}
template<typename FsSize_t, typename InodeId_t>
void FileStoreHeader<FsSize_t, InodeId_t>::setRootInode(FsSize_t rootInode) {
m_rootInode = bigEndianAdapt(rootInode);
}
template<typename FsSize_t, typename InodeId_t>
FsSize_t FileStoreHeader<FsSize_t, InodeId_t>::getRootInode() {
return bigEndianAdapt(m_rootInode);
}
template<typename Header>
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<Header> *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<typename T>
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<typename T>
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<typename T>
T ptr(typename Header::FsSize_t ptr) {
return (T) (begin() + ptr);
};
};
template<typename Header>
typename Header::FsSize_t FileStore<Header>::Inode::size() {
return sizeof(Inode) + getDataLen();
}
template<typename Header>
void FileStore<Header>::Inode::setDataLen(typename Header::FsSize_t dataLen) {
this->m_dataLen = bigEndianAdapt(dataLen);
}
template<typename Header>
typename Header::FsSize_t FileStore<Header>::Inode::getDataLen() {
return bigEndianAdapt(m_dataLen);
}
template<typename Header>
void FileStore<Header>::Inode::setPrev(typename Header::FsSize_t prev) {
this->m_prev = bigEndianAdapt(prev);
}
template<typename Header>
typename Header::FsSize_t FileStore<Header>::Inode::getPrev() {
return bigEndianAdapt(m_prev);
}
template<typename Header>
void FileStore<Header>::Inode::setNext(typename Header::FsSize_t next) {
this->m_next = bigEndianAdapt(next);
}
template<typename Header>
typename Header::FsSize_t FileStore<Header>::Inode::getNext() {
return bigEndianAdapt(m_next);
}
template<typename Header>
void FileStore<Header>::Inode::setId(InodeId_t id) {
this->m_id = bigEndianAdapt(id);
}
template<typename Header>
typename Header::InodeId_t FileStore<Header>::Inode::getId() {
return bigEndianAdapt(m_id);
}
template<typename Header>
void FileStore<Header>::Inode::setLinks(InodeId_t links) {
this->m_links = bigEndianAdapt(links);
}
template<typename Header>
typename Header::InodeId_t FileStore<Header>::Inode::getLinks() {
return bigEndianAdapt(m_links);
}
template<typename Header>
void FileStore<Header>::Inode::setFileType(uint8_t fileType) {
this->m_fileType = bigEndianAdapt(fileType);
}
template<typename Header>
uint8_t FileStore<Header>::Inode::getFileType() {
return bigEndianAdapt(m_fileType);
}
template<typename Header>
void FileStore<Header>::Inode::setLeft(typename Header::FsSize_t left) {
this->m_left = bigEndianAdapt(left);
}
template<typename Header>
typename Header::FsSize_t FileStore<Header>::Inode::getLeft() {
return bigEndianAdapt(m_left);
}
template<typename Header>
void FileStore<Header>::Inode::setRight(typename Header::FsSize_t right) {
this->m_right = bigEndianAdapt(right);
}
template<typename Header>
typename Header::FsSize_t FileStore<Header>::Inode::getRight() {
return bigEndianAdapt(m_right);
}
template<typename Header>
void FileStore<Header>::Inode::setData(void *data, typename Header::FsSize_t size) {
ox_memcpy(getData(), data, size);
setDataLen(size);
}
template<typename Header>
uint8_t *FileStore<Header>::Inode::getData() {
return (uint8_t*) (this + 1);
}
// FileStore
template<typename Header>
int FileStore<Header>::dumpTo(FileStore<Header> *dest) {
if (dest->size() >= size()) {
auto i = ptr<Inode*>(firstInode());
do {
dest->write(i->getId(), i->getData(), i->getDataLen(), i->getFileType());
i = ptr<Inode*>(i->getNext());
} while (ptr(i) != firstInode());
return 0;
} else {
return -1;
}
}
template<typename Header>
void FileStore<Header>::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<typename Header>
int FileStore<Header>::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<Inode*>(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<typename Header>
int FileStore<Header>::remove(InodeId_t id) {
return remove(ptr<Inode*>(m_header.getRootInode()), id);
}
/**
* Increments the links of the inode of the given ID.
* @param id the id of the inode
*/
template<typename Header>
int FileStore<Header>::incLinks(InodeId_t id) {
auto inode = getInode(ptr<Inode*>(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<typename Header>
int FileStore<Header>::decLinks(InodeId_t id) {
auto inode = getInode(ptr<Inode*>(m_header.getRootInode()), id);
if (inode) {
inode->setLinks(inode->getLinks() - 1);
return 0;
} else {
return 1;
}
}
template<typename Header>
int FileStore<Header>::remove(Inode *root, InodeId_t id) {
auto err = 1;
if (root->getId() > id) {
if (root->getLeft()) {
auto left = ptr<Inode*>(root->getLeft());
if (left->getId() != id) {
err = remove(left, id);
} else {
root->setLeft(0);
// pass children to parent
if (left->getRight()) {
insert(root, ptr<Inode*>(left->getRight()));
}
if (left->getLeft()) {
insert(root, ptr<Inode*>(left->getLeft()));
}
dealloc(left);
err = 0;
}
}
} else if (root->getId() < id) {
if (root->getRight()) {
auto right = ptr<Inode*>(root->getRight());
if (right->getId() != id) {
err = remove(right, id);
} else {
root->setRight(0);
// pass children to parent
if (right->getRight()) {
insert(root, ptr<Inode*>(right->getRight()));
}
if (right->getLeft()) {
insert(root, ptr<Inode*>(right->getLeft()));
}
dealloc(right);
err = 0;
}
}
} else if (ptr<Inode*>(m_header.getRootInode())->getId() == id) {
m_header.setRootInode(root->getRight());
if (root->getLeft()) {
insert(ptr<Inode*>(m_header.getRootInode()), ptr<Inode*>(root->getLeft()));
}
dealloc(root);
err = 0;
}
return err;
}
template<typename Header>
int FileStore<Header>::removeAllType(uint8_t fileType) {
int err = 0;
auto first = ptr<Inode*>(firstInode());
// skip the first inode for now, because removing the first inode will cause compact to run
auto current = first;
auto next = ptr<Inode*>(current->getNext());
while (next != first) {
current = next;
// get next before current is possibly cleared
next = ptr<Inode*>(current->getNext());
if (current->getFileType() == fileType) {
err |= remove(current->getId());
}
}
if (first->getFileType() == fileType) {
err |= remove(first->getId());
}
return err;
}
template<typename Header>
void FileStore<Header>::dealloc(Inode *inode) {
auto next = ptr<Inode*>(inode->getNext());
auto prev = ptr<Inode*>(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<typename Header>
void FileStore<Header>::updateInodeAddress(InodeId_t id, typename Header::FsSize_t oldAddr, typename Header::FsSize_t newAddr) {
auto parent = getInodeParent(ptr<Inode*>(m_header.getRootInode()), id, oldAddr);
if (parent) {
if (parent->getLeft() == oldAddr) {
parent->setLeft(newAddr);
} else if (parent->getRight() == oldAddr) {
parent->setRight(newAddr);
}
}
}
template<typename Header>
int FileStore<Header>::read(InodeId_t id, void *data, typename Header::FsSize_t *size) {
auto inode = getInode(ptr<Inode*>(m_header.getRootInode()), id);
return inode ? read(inode, 0, inode->getDataLen(), (uint8_t*) data, size) : 1;
}
template<typename Header>
int FileStore<Header>::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<Inode*>(m_header.getRootInode()), id);
return inode ? read<uint8_t>(inode, readStart, readSize, (uint8_t*) data, size) : 1;
}
template<typename Header>
template<typename T>
int FileStore<Header>::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<Inode*>(m_header.getRootInode()), id);
return inode ? read(inode, readStart, readSize, data, size) : 1;
}
template<typename Header>
template<typename T>
int FileStore<Header>::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 Header>
typename FileStore<Header>::StatInfo FileStore<Header>::stat(InodeId_t id) {
auto inode = getInode(ptr<Inode*>(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>
typename Header::FsSize_t FileStore<Header>::spaceNeeded(typename Header::FsSize_t size) {
return sizeof(Inode) + size;
}
template<typename Header>
typename Header::FsSize_t FileStore<Header>::size() {
return m_header.getSize();
}
template<typename Header>
typename Header::FsSize_t FileStore<Header>::available() {
return m_header.getSize() - m_header.getMemUsed();
}
template<typename Header>
typename FileStore<Header>::Inode *FileStore<Header>::getInode(Inode *root, InodeId_t id) {
Inode *retval = nullptr;
if (root->getId() > id) {
if (root->getLeft()) {
retval = getInode(ptr<Inode*>(root->getLeft()), id);
}
} else if (root->getId() < id) {
if (root->getRight()) {
retval = getInode(ptr<Inode*>(root->getRight()), id);
}
} else if (root->getId() == id) {
retval = root;
}
return retval;
}
template<typename Header>
typename FileStore<Header>::Inode *FileStore<Header>::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<Inode*>(root->getLeft()), id, targetAddr);
}
}
} else if (root->getId() < id) {
if (root->getRight()) {
if (root->getRight() == targetAddr) {
retval = root;
} else {
retval = getInodeParent(ptr<Inode*>(root->getRight()), id, targetAddr);
}
}
}
return retval;
}
template<typename Header>
typename Header::FsSize_t FileStore<Header>::nextInodeAddr() {
return lastInode() + ptr<Inode*>(lastInode())->size();
}
template<typename Header>
void *FileStore<Header>::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<Inode*>(retval);
ox_memset(inode, 0, size);
inode->setPrev(ptr<Inode*>(firstInode())->getPrev());
inode->setNext(firstInode());
m_header.setMemUsed(m_header.getMemUsed() + size);
ptr<Inode*>(lastInode())->setNext(retval);
ptr<Inode*>(firstInode())->setPrev(retval);
return inode;
}
template<typename Header>
void FileStore<Header>::compact() {
auto dest = ptr<Inode*>(firstInode());
auto current = ptr<Inode*>(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<Inode*>(dest->getNext())->setPrev(ptr(dest));
updateInodeAddress(dest->getId(), ptr(current), ptr(dest));
current = ptr<Inode*>(dest->getNext());
dest = ptr<Inode*>(ptr(dest) + dest->size());
}
}
template<typename Header>
bool FileStore<Header>::insert(Inode *root, Inode *insertValue) {
auto retval = false;
if (root->getId() > insertValue->getId()) {
if (root->getLeft()) {
retval = insert(ptr<Inode*>(root->getLeft()), insertValue);
} else {
root->setLeft(ptr(insertValue));
retval = true;
}
} else if (root->getId() < insertValue->getId()) {
if (root->getRight()) {
retval = insert(ptr<Inode*>(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>
typename Header::FsSize_t FileStore<Header>::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>
typename Header::FsSize_t FileStore<Header>::firstInode() {
return sizeof(FileStore<Header>);
}
template<typename Header>
typename Header::FsSize_t FileStore<Header>::lastInode() {
return ptr<Inode*>(firstInode())->getPrev();
}
template<typename Header>
uint16_t FileStore<Header>::fsType() {
return m_header.getFsType();
};
template<typename Header>
uint16_t FileStore<Header>::version() {
return m_header.getVersion();
};
template<typename Header>
void FileStore<Header>::walk(int(*cb)(const char*, uint64_t start, uint64_t end)) {
auto err = cb("Header", 0, sizeof(Header));
auto inode = ptr<Inode*>(firstInode());
do {
auto start = ptr(inode);
err = cb("Inode", start, start + inode->size());
inode = ptr<Inode*>(inode->getNext());
} while (!err && inode != ptr<Inode*>(firstInode()));
}
template<typename Header>
uint8_t *FileStore<Header>::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<Header>) + sizeof(Inode));
fs->m_header.setRootInode(sizeof(FileStore<Header>));
((Inode*) (fs + 1))->setPrev(sizeof(FileStore<Header>));
((Inode*) (fs + 1))->setNext(sizeof(FileStore<Header>));
return (uint8_t*) buffer;
}
typedef FileStore<FileStoreHeader<uint16_t, uint16_t>> FileStore16;
typedef FileStore<FileStoreHeader<uint32_t, uint64_t>> FileStore32;
typedef FileStore<FileStoreHeader<uint64_t, uint64_t>> FileStore64;
}

73
src/ox/fs/filesystem.cpp Normal file
View File

@ -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;
}
}

884
src/ox/fs/filesystem.hpp Normal file
View File

@ -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 <ox/std/std.hpp>
#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<typename String>
struct DirectoryListing {
String name;
FileStat stat;
DirectoryListing() = default;
DirectoryListing(const char *name) {
this->name = name;
}
};
template<typename String>
bool operator<(const DirectoryListing<String> &a, const DirectoryListing<String> &b) {
return a.name < b.name;
}
template<typename InodeId_t>
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<typename InodeId_t, typename FsSize_t>
struct __attribute__((packed)) Directory {
/**
* Number of bytes after this Directory struct.
*/
FsSize_t size = 0;
FsSize_t children = 0;
DirectoryEntry<InodeId_t> *files() {
return size ? (DirectoryEntry<InodeId_t>*) (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<uint64_t, uint64_t> *dirOut);
template<typename List>
int ls(List *list);
};
template<typename InodeId_t, typename FsSize_t>
uint64_t Directory<InodeId_t, FsSize_t>::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<InodeId_t>*) (((uint8_t*) current) + current->size());
} else {
current = nullptr;
break;
}
}
if (current) {
inode = current->inode;
}
}
return inode;
}
template<typename InodeId_t, typename FsSize_t>
int Directory<InodeId_t, FsSize_t>::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<InodeId_t>*) (((uint8_t*) current) + current->size());
}
return 0;
} else {
return 1;
}
} else {
return 2;
}
}
template<typename InodeId_t, typename FsSize_t>
int Directory<InodeId_t, FsSize_t>::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<InodeId_t>*) (((uint8_t*) current) + current->size());
}
}
return err;
}
template<typename InodeId_t, typename FsSize_t>
int Directory<InodeId_t, FsSize_t>::copy(Directory<uint64_t, uint64_t> *dirOut) {
auto current = files();
auto dirOutBuff = (uint8_t*) dirOut;
dirOutBuff += sizeof(Directory<uint64_t, uint64_t>);
dirOut->size = this->size;
dirOut->children = this->children;
if (current) {
for (uint64_t i = 0; i < this->children; i++) {
auto entry = (DirectoryEntry<uint64_t>*) dirOutBuff;
entry->inode = current->inode;
entry->setName(current->getName());
current = (DirectoryEntry<InodeId_t>*) (((uint8_t*) current) + current->size());
dirOutBuff += entry->size();
}
return 0;
} else {
return 1;
}
}
template<typename InodeId_t, typename FsSize_t>
template<typename List>
int Directory<InodeId_t, FsSize_t>::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<InodeId_t>*) (((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<typename List>
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<uint64_t, uint64_t> *dirOut) = 0;
};
template<typename List>
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<uint64_t, uint64_t>*) 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<typename FileStore, FsType FS_TYPE>
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<uint64_t, uint64_t> *dirOut) override;
private:
uint64_t generateInodeId();
int insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode);
void expand(uint64_t size);
};
template<typename FileStore, FsType FS_TYPE>
FileSystemTemplate<FileStore, FS_TYPE>::FileSystemTemplate(uint8_t *buff, bool ownsBuff) {
m_store = (FileStore*) buff;
m_ownsBuff = ownsBuff;
}
template<typename FileStore, FsType FS_TYPE>
FileSystemTemplate<FileStore, FS_TYPE>::~FileSystemTemplate() {
if (m_ownsBuff) {
delete[] (uint8_t*) m_store;
}
}
template<typename FileStore, FsType FS_TYPE>
typename FileStore::InodeId_t FileSystemTemplate<FileStore, FS_TYPE>::INODE_RANDOM = 1;
template<typename FileStore, FsType FS_TYPE>
typename FileStore::InodeId_t FileSystemTemplate<FileStore, FS_TYPE>::INODE_ROOT_DIR = 2;
template<typename FileStore, FsType FS_TYPE>
typename FileStore::InodeId_t FileSystemTemplate<FileStore, FS_TYPE>::INODE_RESERVED_END = 100;
template<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::stripDirectories() {
return m_store->removeAllType(FileType::FileType_Directory);
}
template<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore::InodeId_t, typename FileStore::FsSize_t> 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<typename FileStore, FsType FS_TYPE>
FileStat FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
FileStat FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
uint8_t *FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore::InodeId_t, typename FileStore::FsSize_t>*) 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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
uint64_t FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore::InodeId_t, typename FileStore::FsSize_t>)) {
uint8_t dirBuffer[dirStat.size];
auto dir = (Directory<typename FileStore::InodeId_t, typename FileStore::FsSize_t>*) 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<typename FileStore, FsType FS_TYPE>
void FileSystemTemplate<FileStore, FS_TYPE>::resize(uint64_t size) {
return m_store->resize(size);
}
template<typename FileStore, FsType FS_TYPE>
uint64_t FileSystemTemplate<FileStore, FS_TYPE>::spaceNeeded(uint64_t size) {
return m_store->spaceNeeded(size);
}
template<typename FileStore, FsType FS_TYPE>
uint64_t FileSystemTemplate<FileStore, FS_TYPE>::available() {
return m_store->available();
}
template<typename FileStore, FsType FS_TYPE>
uint64_t FileSystemTemplate<FileStore, FS_TYPE>::size() {
return m_store->size();
}
template<typename FileStore, FsType FS_TYPE>
uint8_t *FileSystemTemplate<FileStore, FS_TYPE>::buff() {
return (uint8_t*) m_store;
}
#ifdef _MSC_VER
#pragma warning(disable:4244)
#endif
template<typename FileStore, FsType FS_TYPE>
uint8_t *FileSystemTemplate<FileStore, FS_TYPE>::format(uint8_t *buffer, typename FileStore::FsSize_t size, bool useDirectories) {
buffer = FileStore::format(buffer, size, (uint16_t) FS_TYPE);
if (buffer && useDirectories) {
Directory<typename FileStore::InodeId_t, typename FileStore::FsSize_t> dir;
FileSystemTemplate<FileStore, FS_TYPE> 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<typename FileStore, FsType FS_TYPE>
uint64_t FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode) {
auto s = stat(dirPath);
if (s.inode) {
auto spaceNeeded = DirectoryEntry<typename FileStore::InodeId_t>::spaceNeeded(fileName);
size_t dirBuffSize = s.size + spaceNeeded;
uint8_t dirBuff[dirBuffSize];
int err = read(s.inode, dirBuff, dirBuffSize);
if (!err) {
auto dir = (Directory<typename FileStore::InodeId_t, typename FileStore::FsSize_t>*) dirBuff;
dir->size += spaceNeeded;
dir->children++;
auto entry = (DirectoryEntry<typename FileStore::InodeId_t>*) &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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore::InodeId_t, typename FileStore::FsSize_t>*) 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<typename FileStore::InodeId_t>::spaceNeeded(fileName));
return err;
}
template<typename FileStore, FsType FS_TYPE>
int FileSystemTemplate<FileStore, FS_TYPE>::readDirectory(const char *path, Directory<uint64_t, uint64_t> *dirOut) {
int err = 0;
auto inode = findInodeOf(path);
auto dirStat = stat(inode);
auto dirBuffLen = dirStat.size;
uint8_t dirBuff[dirBuffLen];
auto dir = (Directory<typename FileStore::InodeId_t, typename FileStore::FsSize_t>*) dirBuff;
err = read(dirStat.inode, dirBuff, dirBuffLen);
if (!err) {
return dir->copy(dirOut);
} else {
return 1;
}
}
template<typename FileStore, FsType FS_TYPE>
void FileSystemTemplate<FileStore, FS_TYPE>::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<typename FileStore, FsType FS_TYPE>
void FileSystemTemplate<FileStore, FS_TYPE>::walk(int(*cb)(const char*, uint64_t, uint64_t)) {
m_store->walk(cb);
}
typedef FileSystemTemplate<FileStore16, OxFS_16> FileSystem16;
typedef FileSystemTemplate<FileStore32, OxFS_32> FileSystem32;
typedef FileSystemTemplate<FileStore64, OxFS_64> FileSystem64;
}

395
src/ox/fs/oxfstool.cpp Normal file
View File

@ -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 <iomanip>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <map>
#include <ox/std/strops.hpp>
#include <ox/fs/filesystem.hpp>
#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] <size> <path>\n"
"\toxfs read <FS file> <inode>\n"
"\toxfs write <FS file> <inode> <insertion file>\n"
"\toxfs write-expand <FS file> <inode> <insertion file>\n"
"\toxfs rm <FS file> <inode>\n"
"\toxfs compact <FS file>\n"
"\toxfs walk <FS file>\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<string, int(*)(int, char**)> 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;
}

107
src/ox/fs/pathiterator.cpp Normal file
View File

@ -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 <ox/std/memops.hpp>
#include <ox/std/strops.hpp>
#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;
}
}

View File

@ -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 <ox/std/types.hpp>
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();
};
}

View File

@ -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")

View File

@ -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 <ox/fs/filestore.hpp>
using namespace ox;
int main() {
const auto size = 65535;
uint8_t volume[size];
uint32_t err = 0;
FileStore32::format(volume, size);
return err;
}

View File

@ -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 <stdio.h>
#include <ox/std/std.hpp>
#include <ox/fs/filestore.hpp>
using namespace ox;
template<typename FileStore>
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<FileStore16>() || test<FileStore32>() | test<FileStore64>();
}

View File

@ -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 <ox/fs/filesystem.hpp>
using namespace ox;
template<typename FileSystem>
int test() {
const uint16_t size = ~0;
uint8_t volume[size];
FileSystem::format(volume, size, true);
return 0;
}
int main() {
return test<FileSystem16>() | test<FileSystem32>() | test<FileSystem64>();
}

346
src/ox/fs/test/tests.cpp Normal file
View File

@ -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 <iostream>
#include <assert.h>
#include <map>
#include <vector>
#include <string>
#include <ox/fs/filesystem.hpp>
#include <ox/fs/pathiterator.hpp>
#include <ox/std/std.hpp>
using namespace std;
using namespace ox;
map<string, int(*)(string)> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> inodes;
vector<DirectoryListing<string>> 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;
}

33
src/ox/fs/toollib.cpp Normal file
View File

@ -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 <iostream>
#include <string.h>
#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);
}

14
src/ox/fs/toollib.hpp Normal file
View File

@ -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 <stdio.h>
#include <stdlib.h>
uint8_t *loadFileBuff(FILE *file, size_t *sizeOut = nullptr);
uint8_t *loadFileBuff(const char *path, size_t *sizeOut = nullptr);

25
src/ox/log/CMakeLists.txt Normal file
View File

@ -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
)

105
src/ox/log/log.cpp Normal file
View File

@ -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 <stdarg.h>
#include <stdio.h>
#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);
}
}

27
src/ox/log/log.hpp Normal file
View File

@ -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, ...);
}

34
src/ox/mc/CMakeLists.txt Normal file
View File

@ -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()

19
src/ox/mc/err.hpp Normal file
View File

@ -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
};
}

12
src/ox/mc/mc.hpp Normal file
View File

@ -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"

View File

@ -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 <ox/std/byteswap.hpp>
#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;
}
}

View File

@ -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 <ox/std/types.hpp>
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();
};
}

55
src/ox/mc/read.cpp Normal file
View File

@ -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 <ox/std/byteswap.hpp>
#include <ox/std/memops.hpp>
#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);
}
}

154
src/ox/mc/read.hpp Normal file
View File

@ -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 <ox/std/byteswap.hpp>
#include <ox/std/string.hpp>
#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<typename T>
int op(const char*, T *val, size_t len);
template<typename T>
int op(const char*, T *val);
template<size_t L>
int op(const char*, ox::bstring<L> *val);
void setFields(int fields);
private:
template<typename I>
int readInteger(I *val);
};
template<typename T>
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<size_t L>
int MetalClawReader::op(const char*, ox::bstring<L> *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<typename I>
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<typename T>
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<typename T>
int read(uint8_t *buff, size_t buffLen, T *val) {
MetalClawReader reader(buff, buffLen);
return ioOp(&reader, val);
}
}

View File

@ -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)

158
src/ox/mc/test/tests.cpp Normal file
View File

@ -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 <iostream>
#include <assert.h>
#include <map>
#include <vector>
#include <string>
#include <ox/mc/mc.hpp>
#include <ox/std/std.hpp>
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<typename T>
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<typename T>
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<string, int(*)(string)> 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;
}

54
src/ox/mc/write.cpp Normal file
View File

@ -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 <ox/std/byteswap.hpp>
#include <ox/std/memops.hpp>
#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);
}
}

152
src/ox/mc/write.hpp Normal file
View File

@ -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 <ox/std/string.hpp>
#include <ox/std/types.hpp>
#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<typename T>
int op(const char*, T *val, size_t len);
template<size_t L>
int op(const char*, ox::bstring<L> *val);
template<typename T>
int op(const char*, T *val);
void setFields(int fields);
private:
template<typename I>
int appendInteger(I val);
};
template<size_t L>
int MetalClawWriter::op(const char*, ox::bstring<L> *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<typename T>
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<typename I>
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<typename T>
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<typename T>
int write(uint8_t *buff, size_t buffLen, T *val) {
MetalClawWriter writer(buff, buffLen);
return ioOp(&writer, val);
}
}

38
src/ox/std/CMakeLists.txt Normal file
View File

@ -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()

19
src/ox/std/bitops.hpp Normal file
View File

@ -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));
}
}

141
src/ox/std/byteswap.hpp Normal file
View File

@ -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
}
}

41
src/ox/std/memops.cpp Normal file
View File

@ -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;
}

16
src/ox/std/memops.hpp Normal file
View File

@ -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);

40
src/ox/std/random.cpp Normal file
View File

@ -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();
}

30
src/ox/std/random.hpp Normal file
View File

@ -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();
};
}

16
src/ox/std/std.hpp Normal file
View File

@ -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"

128
src/ox/std/string.hpp Normal file
View File

@ -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<size_t buffLen>
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<size_t size>
bstring<size>::bstring() {
m_buff[0] = 0;
}
template<size_t size>
bstring<size>::bstring(const char *str) {
*this = str;
}
template<size_t size>
const bstring<size> &bstring<size>::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<size_t size>
const bstring<size> &bstring<size>::operator=(char *str) {
return *this = (const char*) str;
}
template<size_t buffLen>
bool bstring<buffLen>::operator==(const bstring<buffLen> &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<size_t buffLen>
char *bstring<buffLen>::data() {
return (char*) m_buff;
}
template<size_t buffLen>
size_t bstring<buffLen>::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 buffLen>
size_t bstring<buffLen>::size() {
size_t i;
for (i = 0; i < buffLen && m_buff[i]; i++);
return i + 1; // add one for null terminator
}
template<size_t buffLen>
size_t bstring<buffLen>::cap() {
return buffLen;
}
}

91
src/ox/std/strops.cpp Normal file
View File

@ -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;
}

27
src/ox/std/strops.hpp Normal file
View File

@ -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);

View File

@ -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<uint16_t> 0x00ff)
add_test("Test\\ bigEndianAdapt\\ 0xff00" ByteSwapTest bigEndianAdapt<uint16_t> 0xff00)
add_test("Test\\ bigEndianAdapt\\ 0x000000ff" ByteSwapTest bigEndianAdapt<uint32_t> 0x000000ff)
add_test("Test\\ bigEndianAdapt\\ 0x0000ff00" ByteSwapTest bigEndianAdapt<uint32_t> 0x0000ff00)
add_test("Test\\ bigEndianAdapt\\ 0x00ff0000" ByteSwapTest bigEndianAdapt<uint32_t> 0x00ff0000)
add_test("Test\\ bigEndianAdapt\\ 0xff000000" ByteSwapTest bigEndianAdapt<uint32_t> 0xff000000)
add_test("Test\\ bigEndianAdapt\\ 0x00000000000000ff" ByteSwapTest bigEndianAdapt<uint64_t> 0x00000000000000ff)
add_test("Test\\ bigEndianAdapt\\ 0x000000000000ff00" ByteSwapTest bigEndianAdapt<uint64_t> 0x000000000000ff00)
add_test("Test\\ bigEndianAdapt\\ 0x0000000000ff0000" ByteSwapTest bigEndianAdapt<uint64_t> 0x0000000000ff0000)
add_test("Test\\ bigEndianAdapt\\ 0x00000000ff000000" ByteSwapTest bigEndianAdapt<uint64_t> 0x00000000ff000000)
add_test("Test\\ bigEndianAdapt\\ 0x000000ff00000000" ByteSwapTest bigEndianAdapt<uint64_t> 0x000000ff00000000)
add_test("Test\\ bigEndianAdapt\\ 0x0000ff0000000000" ByteSwapTest bigEndianAdapt<uint64_t> 0x0000ff0000000000)
add_test("Test\\ bigEndianAdapt\\ 0x00ff000000000000" ByteSwapTest bigEndianAdapt<uint64_t> 0x00ff000000000000)
add_test("Test\\ bigEndianAdapt\\ 0xff00000000000000" ByteSwapTest bigEndianAdapt<uint64_t> 0xff00000000000000)

View File

@ -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 <map>
#include <string>
#include <ox/std/std.hpp>
using namespace std;
using namespace ox;
template<typename T>
int testBigEndianAdapt(string str) {
auto i = (T) stoull(str, nullptr, 16);
return !(bigEndianAdapt(bigEndianAdapt(i)) == i);
}
map<string, int(*)(string)> tests = {
{
{ "bigEndianAdapt<uint16_t>", testBigEndianAdapt<uint16_t> },
{ "bigEndianAdapt<uint32_t>", testBigEndianAdapt<uint32_t> },
{ "bigEndianAdapt<uint64_t>", testBigEndianAdapt<uint64_t> },
},
};
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;
}

View File

@ -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 <iostream>
#include <map>
#include <functional>
#include <ox/std/std.hpp>
using namespace std;
map<string, function<int()>> 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;
}

50
src/ox/std/test/tests.cpp Normal file
View File

@ -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 <iostream>
#include <map>
#include <functional>
#include <ox/std/std.hpp>
using namespace std;
map<string, function<int()>> 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;
}

40
src/ox/std/types.hpp Normal file
View File

@ -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