mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
First working version with some test executables
This commit is contained in:
commit
10b5b80675
38
CMakeLists.txt
Normal file
38
CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
# define the minimum cmake version (as required by cmake)
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
#set(CMAKE_TOOLCHAIN_FILE /opt/raspberrypi/Toolchain-RaspberryPi.cmake)
|
||||
|
||||
# Define the main-project name
|
||||
project(Hyperion)
|
||||
|
||||
# Add project specific cmake modules (find, etc)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
# Define the global output path of binaries
|
||||
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
|
||||
|
||||
file(MAKE_DIRECTORY ${LIBRARY_OUTPUT_PATH})
|
||||
file(MAKE_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
|
||||
|
||||
# Add the project include directory as additional include path
|
||||
include_directories(${CMAKE_SOURCE_DIR}/dependencies/include)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
# Prefer static linking over dynamic
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so")
|
||||
|
||||
#set(CMAKE_BUILD_TYPE "Release")
|
||||
|
||||
# enable C++11
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall")
|
||||
|
||||
configure_file(bin/install_hyperion.sh ${LIBRARY_OUTPUT_PATH} @ONLY)
|
||||
configure_file(config/Hyperion.config.json ${LIBRARY_OUTPUT_PATH} @ONLY)
|
||||
configure_file(config/Hyperion.schema.json ${LIBRARY_OUTPUT_PATH} @ONLY)
|
||||
|
||||
# Add the source/lib directories
|
||||
add_subdirectory(dependencies)
|
||||
add_subdirectory(libsrc)
|
||||
add_subdirectory(src)
|
24
bin/install_hyperion.sh
Normal file
24
bin/install_hyperion.sh
Normal file
@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Script for removing the existing boblight library and replacing it with Hyperion
|
||||
|
||||
# First stop the current BobLight demon and XBMC
|
||||
initctl stop xbmc
|
||||
initctl stop boblight
|
||||
|
||||
# Install the RapsiLight library
|
||||
cp libbob2hyperion.so /usr/lib/libbob2hyperion.so
|
||||
chmod 755 /usr/lib/libbob2hyperion.so
|
||||
cp hyperion.config.json /etc/
|
||||
cp hyperion.schema.json /etc/
|
||||
|
||||
# Remove the existing boblight client library (make backup)
|
||||
cp /usr/lib/libboblight.so.0.0.0 /usr/lib/libboblight.old
|
||||
# Rename the settings file to ensure that the boblight-deamon does not start
|
||||
mv /etc/bobconfig.txt /etc/bobconfig.txt.old
|
||||
|
||||
# Link libboblight to the new installed library
|
||||
ln -s /usr/lib/libbob2hyperion.so /usr/lib/libboblight.so.0.0.0
|
||||
|
||||
# Restart only XBMC
|
||||
initctl start xbmc
|
63
cmake/FindPNG.cmake
Normal file
63
cmake/FindPNG.cmake
Normal file
@ -0,0 +1,63 @@
|
||||
# - Find the native PNG includes and library
|
||||
#
|
||||
|
||||
# This module defines
|
||||
# PNG_INCLUDE_DIR, where to find png.h, etc.
|
||||
# PNG_LIBRARIES, the libraries to link against to use PNG.
|
||||
# PNG_DEFINITIONS - You should ADD_DEFINITONS(${PNG_DEFINITIONS}) before compiling code that includes png library files.
|
||||
# PNG_FOUND, If false, do not try to use PNG.
|
||||
# also defined, but not for general use are
|
||||
# PNG_LIBRARY, where to find the PNG library.
|
||||
# None of the above will be defined unles zlib can be found.
|
||||
# PNG depends on Zlib
|
||||
#
|
||||
# Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
|
||||
# See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
|
||||
|
||||
|
||||
INCLUDE(FindZLIB)
|
||||
|
||||
SET(PNG_FOUND "NO")
|
||||
|
||||
IF(ZLIB_FOUND)
|
||||
FIND_PATH(PNG_PNG_INCLUDE_DIR png.h
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
/usr/local/include/libpng # OpenBSD
|
||||
)
|
||||
|
||||
SET(PNG_NAMES ${PNG_NAMES} png libpng)
|
||||
FIND_LIBRARY(PNG_LIBRARY
|
||||
NAMES ${PNG_NAMES}
|
||||
PATHS /usr/lib64 /usr/lib /usr/local/lib
|
||||
)
|
||||
|
||||
IF (PNG_LIBRARY AND PNG_PNG_INCLUDE_DIR)
|
||||
# png.h includes zlib.h. Sigh.
|
||||
SET(PNG_INCLUDE_DIR ${PNG_PNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} )
|
||||
SET(PNG_LIBRARIES ${PNG_LIBRARY} ${ZLIB_LIBRARY})
|
||||
SET(PNG_FOUND "YES")
|
||||
SET(HAVE_PNG_H)
|
||||
IF (CYGWIN)
|
||||
IF(BUILD_SHARED_LIBS)
|
||||
# No need to define PNG_USE_DLL here, because it's default for Cygwin.
|
||||
ELSE(BUILD_SHARED_LIBS)
|
||||
SET (PNG_DEFINITIONS -DPNG_STATIC)
|
||||
ENDIF(BUILD_SHARED_LIBS)
|
||||
ENDIF (CYGWIN)
|
||||
|
||||
ENDIF (PNG_LIBRARY AND PNG_PNG_INCLUDE_DIR)
|
||||
|
||||
ENDIF(ZLIB_FOUND)
|
||||
|
||||
IF (PNG_FOUND)
|
||||
IF (NOT PNG_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found PNG: ${PNG_LIBRARY}")
|
||||
ENDIF (NOT PNG_FIND_QUIETLY)
|
||||
ELSE (PNG_FOUND)
|
||||
IF (PNG_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find PNG library")
|
||||
ENDIF (PNG_FIND_REQUIRED)
|
||||
ENDIF (PNG_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(PNG_PNG_INCLUDE_DIR PNG_LIBRARY )
|
291
config/Hyperion.config.json
Normal file
291
config/Hyperion.config.json
Normal file
@ -0,0 +1,291 @@
|
||||
// Automatically generated configuration file for 'Hyperion'
|
||||
// Generation script: ./WriteConfig
|
||||
|
||||
{
|
||||
"device" :
|
||||
{
|
||||
"name" : "MyPi",
|
||||
"type" : "ws2801",
|
||||
"output" : "/dev/spidev0.0",
|
||||
"interval" : 20000,
|
||||
"rate" : 48000
|
||||
},
|
||||
"color" :
|
||||
{
|
||||
"red" :
|
||||
{
|
||||
"gamma" : 1.0,
|
||||
"adjust" : 1.0,
|
||||
"blacklevel" : 0.0
|
||||
},
|
||||
"green" :
|
||||
{
|
||||
"gamma" : 1.0,
|
||||
"adjust" : 1.0,
|
||||
"blacklevel" : 0.0
|
||||
},
|
||||
"blue" :
|
||||
{
|
||||
"gamma" : 1.0,
|
||||
"adjust" : 1.0,
|
||||
"blacklevel" : 0.0
|
||||
}
|
||||
},
|
||||
"leds" :
|
||||
[
|
||||
{
|
||||
"index" : 0,
|
||||
"hscan" : { "minimum" : 47.0588, "maximum" : 52.9412 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 1,
|
||||
"hscan" : { "minimum" : 41.1765, "maximum" : 47.0588 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 2,
|
||||
"hscan" : { "minimum" : 35.2941, "maximum" : 41.1765 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 3,
|
||||
"hscan" : { "minimum" : 29.4118, "maximum" : 35.2941 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 4,
|
||||
"hscan" : { "minimum" : 23.5294, "maximum" : 29.4118 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 5,
|
||||
"hscan" : { "minimum" : 17.6471, "maximum" : 23.5294 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 6,
|
||||
"hscan" : { "minimum" : 11.7647, "maximum" : 17.6471 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 7,
|
||||
"hscan" : { "minimum" : 5.88235, "maximum" : 11.7647 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
// TOP-LEFT Corner
|
||||
{
|
||||
"index" : 8,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 5.88235 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 9,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 10 },
|
||||
"vscan" : { "minimum" : 10, "maximum" : 20 }
|
||||
},
|
||||
{
|
||||
"index" : 10,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 10 },
|
||||
"vscan" : { "minimum" : 20, "maximum" : 30 }
|
||||
},
|
||||
{
|
||||
"index" : 11,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 10 },
|
||||
"vscan" : { "minimum" : 30, "maximum" : 40 }
|
||||
},
|
||||
{
|
||||
"index" : 12,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 10 },
|
||||
"vscan" : { "minimum" : 40, "maximum" : 50 }
|
||||
},
|
||||
{
|
||||
"index" : 13,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 10 },
|
||||
"vscan" : { "minimum" : 50, "maximum" : 60 }
|
||||
},
|
||||
{
|
||||
"index" : 14,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 10 },
|
||||
"vscan" : { "minimum" : 60, "maximum" : 70 }
|
||||
},
|
||||
{
|
||||
"index" : 15,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 10 },
|
||||
"vscan" : { "minimum" : 70, "maximum" : 80 }
|
||||
},
|
||||
{
|
||||
"index" : 16,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 10 },
|
||||
"vscan" : { "minimum" : 80, "maximum" : 90 }
|
||||
},
|
||||
// BOTTOM-LEFT Corner
|
||||
{
|
||||
"index" : 17,
|
||||
"hscan" : { "minimum" : 0, "maximum" : 5.88235 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 18,
|
||||
"hscan" : { "minimum" : 5.88235, "maximum" : 11.7647 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 19,
|
||||
"hscan" : { "minimum" : 11.7647, "maximum" : 17.6471 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 20,
|
||||
"hscan" : { "minimum" : 17.6471, "maximum" : 23.5294 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 21,
|
||||
"hscan" : { "minimum" : 23.5294, "maximum" : 29.4118 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 22,
|
||||
"hscan" : { "minimum" : 29.4118, "maximum" : 35.2941 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 23,
|
||||
"hscan" : { "minimum" : 35.2941, "maximum" : 41.1765 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 24,
|
||||
"hscan" : { "minimum" : 41.1765, "maximum" : 47.0588 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 25,
|
||||
"hscan" : { "minimum" : 47.0588, "maximum" : 52.9412 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 26,
|
||||
"hscan" : { "minimum" : 52.9412, "maximum" : 58.8235 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 27,
|
||||
"hscan" : { "minimum" : 58.8235, "maximum" : 64.7059 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 28,
|
||||
"hscan" : { "minimum" : 64.7059, "maximum" : 70.5882 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 29,
|
||||
"hscan" : { "minimum" : 70.5882, "maximum" : 76.4706 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 30,
|
||||
"hscan" : { "minimum" : 76.4706, "maximum" : 82.3529 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 31,
|
||||
"hscan" : { "minimum" : 82.3529, "maximum" : 88.2353 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 32,
|
||||
"hscan" : { "minimum" : 88.2353, "maximum" : 94.1176 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
// BOTTOM-RIGHT Corner
|
||||
{
|
||||
"index" : 33,
|
||||
"hscan" : { "minimum" : 94.1176, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 90, "maximum" : 100 }
|
||||
},
|
||||
{
|
||||
"index" : 34,
|
||||
"hscan" : { "minimum" : 90, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 80, "maximum" : 90 }
|
||||
},
|
||||
{
|
||||
"index" : 35,
|
||||
"hscan" : { "minimum" : 90, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 70, "maximum" : 80 }
|
||||
},
|
||||
{
|
||||
"index" : 36,
|
||||
"hscan" : { "minimum" : 90, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 60, "maximum" : 70 }
|
||||
},
|
||||
{
|
||||
"index" : 37,
|
||||
"hscan" : { "minimum" : 90, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 50, "maximum" : 60 }
|
||||
},
|
||||
{
|
||||
"index" : 38,
|
||||
"hscan" : { "minimum" : 90, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 40, "maximum" : 50 }
|
||||
},
|
||||
{
|
||||
"index" : 39,
|
||||
"hscan" : { "minimum" : 90, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 30, "maximum" : 40 }
|
||||
},
|
||||
{
|
||||
"index" : 40,
|
||||
"hscan" : { "minimum" : 90, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 20, "maximum" : 30 }
|
||||
},
|
||||
{
|
||||
"index" : 41,
|
||||
"hscan" : { "minimum" : 90, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 10, "maximum" : 20 }
|
||||
},
|
||||
// TOP-RIGHT Corner
|
||||
{
|
||||
"index" : 42,
|
||||
"hscan" : { "minimum" : 94.1176, "maximum" : 100 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 43,
|
||||
"hscan" : { "minimum" : 88.2353, "maximum" : 94.1176 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 44,
|
||||
"hscan" : { "minimum" : 82.3529, "maximum" : 88.2353 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 45,
|
||||
"hscan" : { "minimum" : 76.4706, "maximum" : 82.3529 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 46,
|
||||
"hscan" : { "minimum" : 70.5882, "maximum" : 76.4706 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 47,
|
||||
"hscan" : { "minimum" : 64.7059, "maximum" : 70.5882 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 48,
|
||||
"hscan" : { "minimum" : 58.8235, "maximum" : 64.7059 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
},
|
||||
{
|
||||
"index" : 49,
|
||||
"hscan" : { "minimum" : 52.9412, "maximum" : 58.8235 },
|
||||
"vscan" : { "minimum" : 0, "maximum" : 10 }
|
||||
}
|
||||
]
|
||||
}
|
134
config/Hyperion.schema.json
Normal file
134
config/Hyperion.schema.json
Normal file
@ -0,0 +1,134 @@
|
||||
{
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"device": {
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"name": {
|
||||
"type":"string",
|
||||
"required":true
|
||||
},
|
||||
"type": {
|
||||
"type":"string",
|
||||
"required":true
|
||||
},
|
||||
"output": {
|
||||
"type":"string",
|
||||
"required":true
|
||||
},
|
||||
"interval": {
|
||||
"type":"integer",
|
||||
"required":true
|
||||
},
|
||||
"rate": {
|
||||
"type":"integer",
|
||||
"required":true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"color": {
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties": {
|
||||
"red": {
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"gamma": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
},
|
||||
"adjust": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
},
|
||||
"blacklevel": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
}
|
||||
}
|
||||
},
|
||||
"green": {
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"gamma": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
},
|
||||
"adjust": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
},
|
||||
"blacklevel": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
}
|
||||
}
|
||||
},
|
||||
"blue": {
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties":{
|
||||
"gamma": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
},
|
||||
"adjust": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
},
|
||||
"blacklevel": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"leds": {
|
||||
"type":"array",
|
||||
"required":true,
|
||||
"items": {
|
||||
"type":"object",
|
||||
"properties": {
|
||||
"index": {
|
||||
"type":"integer",
|
||||
"required":true
|
||||
},
|
||||
"hscan": {
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties": {
|
||||
"minimum": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
},
|
||||
"maximum": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
}
|
||||
}
|
||||
},
|
||||
"vscan": {
|
||||
"type":"object",
|
||||
"required":true,
|
||||
"properties": {
|
||||
"minimum": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
},
|
||||
"maximum": {
|
||||
"type":"number",
|
||||
"required":true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
dependencies/CMakeLists.txt
vendored
Normal file
9
dependencies/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2012 TNO, The Netherlands.
|
||||
#
|
||||
# This file contains information proprietary to TNO.
|
||||
#
|
||||
# Any disclosure or use of this information or any reproduction of this document or any part thereof for
|
||||
# other than the specified purpose for which it is intended is expressly prohibited except as TNO may
|
||||
# otherwise agree to in writing.
|
||||
|
||||
add_subdirectory(build)
|
9
dependencies/build/CMakeLists.txt
vendored
Normal file
9
dependencies/build/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2012 TNO, The Netherlands.
|
||||
#
|
||||
# This file contains information proprietary to TNO.
|
||||
#
|
||||
# Any disclosure or use of this information or any reproduction of this document or any part thereof for
|
||||
# other than the specified purpose for which it is intended is expressly prohibited except as TNO may
|
||||
# otherwise agree to in writing.
|
||||
|
||||
add_subdirectory(jsoncpp)
|
1
dependencies/build/jsoncpp/AUTHORS
vendored
Normal file
1
dependencies/build/jsoncpp/AUTHORS
vendored
Normal file
@ -0,0 +1 @@
|
||||
Baptiste Lepilleur <blep@users.sourceforge.net>
|
32
dependencies/build/jsoncpp/CMakeLists.txt
vendored
Normal file
32
dependencies/build/jsoncpp/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2012 TNO, The Netherlands.
|
||||
#
|
||||
# This file contains information proprietary to TNO.
|
||||
#
|
||||
# Any disclosure or use of this information or any reproduction of this document or any part thereof for
|
||||
# other than the specified purpose for which it is intended is expressly prohibited except as TNO may
|
||||
# otherwise agree to in writing.
|
||||
|
||||
project(jsoncpp)
|
||||
|
||||
# define the current source/header path
|
||||
set(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/dependencies/include/json)
|
||||
set(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/dependencies/build/jsoncpp)
|
||||
|
||||
add_library(jsoncpp
|
||||
${CURRENT_HEADER_DIR}/autolink.h
|
||||
${CURRENT_HEADER_DIR}/config.h
|
||||
${CURRENT_HEADER_DIR}/features.h
|
||||
${CURRENT_HEADER_DIR}/forwards.h
|
||||
${CURRENT_HEADER_DIR}/json.h
|
||||
${CURRENT_HEADER_DIR}/reader.h
|
||||
${CURRENT_HEADER_DIR}/value.h
|
||||
${CURRENT_HEADER_DIR}/writer.h
|
||||
|
||||
${CURRENT_SOURCE_DIR}/json_batchallocator.h
|
||||
${CURRENT_SOURCE_DIR}/json_internalarray.inl
|
||||
${CURRENT_SOURCE_DIR}/json_internalmap.inl
|
||||
${CURRENT_SOURCE_DIR}/json_reader.cpp
|
||||
${CURRENT_SOURCE_DIR}/json_tool.h
|
||||
${CURRENT_SOURCE_DIR}/json_value.cpp
|
||||
${CURRENT_SOURCE_DIR}/json_valueiterator.inl
|
||||
${CURRENT_SOURCE_DIR}/json_writer.cpp)
|
55
dependencies/build/jsoncpp/LICENSE
vendored
Normal file
55
dependencies/build/jsoncpp/LICENSE
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
The JsonCpp library's source code, including accompanying documentation,
|
||||
tests and demonstration applications, are licensed under the following
|
||||
conditions...
|
||||
|
||||
The author (Baptiste Lepilleur) explicitly disclaims copyright in all
|
||||
jurisdictions which recognize such a disclaimer. In such jurisdictions,
|
||||
this software is released into the Public Domain.
|
||||
|
||||
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
|
||||
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
|
||||
released under the terms of the MIT License (see below).
|
||||
|
||||
In jurisdictions which recognize Public Domain property, the user of this
|
||||
software may choose to accept it either as 1) Public Domain, 2) under the
|
||||
conditions of the MIT License (see below), or 3) under the terms of dual
|
||||
Public Domain/MIT License conditions described here, as they choose.
|
||||
|
||||
The MIT License is about as close to Public Domain as a license can get, and is
|
||||
described in clear, concise terms at:
|
||||
|
||||
http://en.wikipedia.org/wiki/MIT_License
|
||||
|
||||
The full text of the MIT License follows:
|
||||
|
||||
========================================================================
|
||||
Copyright (c) 2007-2010 Baptiste Lepilleur
|
||||
|
||||
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.
|
||||
========================================================================
|
||||
(END LICENSE TEXT)
|
||||
|
||||
The MIT license is compatible with both the GPL and commercial
|
||||
software, affording one all of the rights of Public Domain with the
|
||||
minor nuisance of being required to keep the above copyright notice
|
||||
and license text in the source code. Note also that by accepting the
|
||||
Public Domain "license" you can re-license your copy using whatever
|
||||
license you like.
|
130
dependencies/build/jsoncpp/json_batchallocator.h
vendored
Normal file
130
dependencies/build/jsoncpp/json_batchallocator.h
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||
|
||||
namespace Json {
|
||||
|
||||
/* Fast memory allocator.
|
||||
*
|
||||
* This memory allocator allocates memory for a batch of object (specified by
|
||||
* the page size, the number of object in each page).
|
||||
*
|
||||
* It does not allow the destruction of a single object. All the allocated objects
|
||||
* can be destroyed at once. The memory can be either released or reused for future
|
||||
* allocation.
|
||||
*
|
||||
* The in-place new operator must be used to construct the object using the pointer
|
||||
* returned by allocate.
|
||||
*/
|
||||
template<typename AllocatedType
|
||||
,const unsigned int objectPerAllocation>
|
||||
class BatchAllocator
|
||||
{
|
||||
public:
|
||||
typedef AllocatedType Type;
|
||||
|
||||
BatchAllocator( unsigned int objectsPerPage = 255 )
|
||||
: freeHead_( 0 )
|
||||
, objectsPerPage_( objectsPerPage )
|
||||
{
|
||||
// printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
|
||||
assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
|
||||
assert( objectsPerPage >= 16 );
|
||||
batches_ = allocateBatch( 0 ); // allocated a dummy page
|
||||
currentBatch_ = batches_;
|
||||
}
|
||||
|
||||
~BatchAllocator()
|
||||
{
|
||||
for ( BatchInfo *batch = batches_; batch; )
|
||||
{
|
||||
BatchInfo *nextBatch = batch->next_;
|
||||
free( batch );
|
||||
batch = nextBatch;
|
||||
}
|
||||
}
|
||||
|
||||
/// allocate space for an array of objectPerAllocation object.
|
||||
/// @warning it is the responsability of the caller to call objects constructors.
|
||||
AllocatedType *allocate()
|
||||
{
|
||||
if ( freeHead_ ) // returns node from free list.
|
||||
{
|
||||
AllocatedType *object = freeHead_;
|
||||
freeHead_ = *(AllocatedType **)object;
|
||||
return object;
|
||||
}
|
||||
if ( currentBatch_->used_ == currentBatch_->end_ )
|
||||
{
|
||||
currentBatch_ = currentBatch_->next_;
|
||||
while ( currentBatch_ && currentBatch_->used_ == currentBatch_->end_ )
|
||||
currentBatch_ = currentBatch_->next_;
|
||||
|
||||
if ( !currentBatch_ ) // no free batch found, allocate a new one
|
||||
{
|
||||
currentBatch_ = allocateBatch( objectsPerPage_ );
|
||||
currentBatch_->next_ = batches_; // insert at the head of the list
|
||||
batches_ = currentBatch_;
|
||||
}
|
||||
}
|
||||
AllocatedType *allocated = currentBatch_->used_;
|
||||
currentBatch_->used_ += objectPerAllocation;
|
||||
return allocated;
|
||||
}
|
||||
|
||||
/// Release the object.
|
||||
/// @warning it is the responsability of the caller to actually destruct the object.
|
||||
void release( AllocatedType *object )
|
||||
{
|
||||
assert( object != 0 );
|
||||
*(AllocatedType **)object = freeHead_;
|
||||
freeHead_ = object;
|
||||
}
|
||||
|
||||
private:
|
||||
struct BatchInfo
|
||||
{
|
||||
BatchInfo *next_;
|
||||
AllocatedType *used_;
|
||||
AllocatedType *end_;
|
||||
AllocatedType buffer_[objectPerAllocation];
|
||||
};
|
||||
|
||||
// disabled copy constructor and assignement operator.
|
||||
BatchAllocator( const BatchAllocator & );
|
||||
void operator =( const BatchAllocator &);
|
||||
|
||||
static BatchInfo *allocateBatch( unsigned int objectsPerPage )
|
||||
{
|
||||
const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
|
||||
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
|
||||
BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
|
||||
batch->next_ = 0;
|
||||
batch->used_ = batch->buffer_;
|
||||
batch->end_ = batch->buffer_ + objectsPerPage;
|
||||
return batch;
|
||||
}
|
||||
|
||||
BatchInfo *batches_;
|
||||
BatchInfo *currentBatch_;
|
||||
/// Head of a single linked list within the allocated space of freeed object
|
||||
AllocatedType *freeHead_;
|
||||
unsigned int objectsPerPage_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Json
|
||||
|
||||
# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
|
||||
|
||||
#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
|
||||
|
456
dependencies/build/jsoncpp/json_internalarray.inl
vendored
Normal file
456
dependencies/build/jsoncpp/json_internalarray.inl
vendored
Normal file
@ -0,0 +1,456 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
// included by json_value.cpp
|
||||
|
||||
namespace Json {
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueInternalArray
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueArrayAllocator::~ValueArrayAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class DefaultValueArrayAllocator
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||
{
|
||||
public: // overridden from ValueArrayAllocator
|
||||
virtual ~DefaultValueArrayAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ValueInternalArray *newArray()
|
||||
{
|
||||
return new ValueInternalArray();
|
||||
}
|
||||
|
||||
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||
{
|
||||
return new ValueInternalArray( other );
|
||||
}
|
||||
|
||||
virtual void destructArray( ValueInternalArray *array )
|
||||
{
|
||||
delete array;
|
||||
}
|
||||
|
||||
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||
ValueInternalArray::PageIndex &indexCount,
|
||||
ValueInternalArray::PageIndex minNewIndexCount )
|
||||
{
|
||||
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
||||
if ( minNewIndexCount > newIndexCount )
|
||||
newIndexCount = minNewIndexCount;
|
||||
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
||||
if ( !newIndexes )
|
||||
throw std::bad_alloc();
|
||||
indexCount = newIndexCount;
|
||||
indexes = static_cast<Value **>( newIndexes );
|
||||
}
|
||||
virtual void releaseArrayPageIndex( Value **indexes,
|
||||
ValueInternalArray::PageIndex indexCount )
|
||||
{
|
||||
if ( indexes )
|
||||
free( indexes );
|
||||
}
|
||||
|
||||
virtual Value *allocateArrayPage()
|
||||
{
|
||||
return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
|
||||
}
|
||||
|
||||
virtual void releaseArrayPage( Value *value )
|
||||
{
|
||||
if ( value )
|
||||
free( value );
|
||||
}
|
||||
};
|
||||
|
||||
#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||
class DefaultValueArrayAllocator : public ValueArrayAllocator
|
||||
{
|
||||
public: // overridden from ValueArrayAllocator
|
||||
virtual ~DefaultValueArrayAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ValueInternalArray *newArray()
|
||||
{
|
||||
ValueInternalArray *array = arraysAllocator_.allocate();
|
||||
new (array) ValueInternalArray(); // placement new
|
||||
return array;
|
||||
}
|
||||
|
||||
virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
|
||||
{
|
||||
ValueInternalArray *array = arraysAllocator_.allocate();
|
||||
new (array) ValueInternalArray( other ); // placement new
|
||||
return array;
|
||||
}
|
||||
|
||||
virtual void destructArray( ValueInternalArray *array )
|
||||
{
|
||||
if ( array )
|
||||
{
|
||||
array->~ValueInternalArray();
|
||||
arraysAllocator_.release( array );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void reallocateArrayPageIndex( Value **&indexes,
|
||||
ValueInternalArray::PageIndex &indexCount,
|
||||
ValueInternalArray::PageIndex minNewIndexCount )
|
||||
{
|
||||
ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
|
||||
if ( minNewIndexCount > newIndexCount )
|
||||
newIndexCount = minNewIndexCount;
|
||||
void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
|
||||
if ( !newIndexes )
|
||||
throw std::bad_alloc();
|
||||
indexCount = newIndexCount;
|
||||
indexes = static_cast<Value **>( newIndexes );
|
||||
}
|
||||
virtual void releaseArrayPageIndex( Value **indexes,
|
||||
ValueInternalArray::PageIndex indexCount )
|
||||
{
|
||||
if ( indexes )
|
||||
free( indexes );
|
||||
}
|
||||
|
||||
virtual Value *allocateArrayPage()
|
||||
{
|
||||
return static_cast<Value *>( pagesAllocator_.allocate() );
|
||||
}
|
||||
|
||||
virtual void releaseArrayPage( Value *value )
|
||||
{
|
||||
if ( value )
|
||||
pagesAllocator_.release( value );
|
||||
}
|
||||
private:
|
||||
BatchAllocator<ValueInternalArray,1> arraysAllocator_;
|
||||
BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
|
||||
};
|
||||
#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
|
||||
static ValueArrayAllocator *&arrayAllocator()
|
||||
{
|
||||
static DefaultValueArrayAllocator defaultAllocator;
|
||||
static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
|
||||
return arrayAllocator;
|
||||
}
|
||||
|
||||
static struct DummyArrayAllocatorInitializer {
|
||||
DummyArrayAllocatorInitializer()
|
||||
{
|
||||
arrayAllocator(); // ensure arrayAllocator() statics are initialized before main().
|
||||
}
|
||||
} dummyArrayAllocatorInitializer;
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueInternalArray
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
ValueInternalArray::equals( const IteratorState &x,
|
||||
const IteratorState &other )
|
||||
{
|
||||
return x.array_ == other.array_
|
||||
&& x.currentItemIndex_ == other.currentItemIndex_
|
||||
&& x.currentPageIndex_ == other.currentPageIndex_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::increment( IteratorState &it )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( it.array_ &&
|
||||
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
|
||||
!= it.array_->size_,
|
||||
"ValueInternalArray::increment(): moving iterator beyond end" );
|
||||
++(it.currentItemIndex_);
|
||||
if ( it.currentItemIndex_ == itemsPerPage )
|
||||
{
|
||||
it.currentItemIndex_ = 0;
|
||||
++(it.currentPageIndex_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::decrement( IteratorState &it )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( it.array_ && it.currentPageIndex_ == it.array_->pages_
|
||||
&& it.currentItemIndex_ == 0,
|
||||
"ValueInternalArray::decrement(): moving iterator beyond end" );
|
||||
if ( it.currentItemIndex_ == 0 )
|
||||
{
|
||||
it.currentItemIndex_ = itemsPerPage-1;
|
||||
--(it.currentPageIndex_);
|
||||
}
|
||||
else
|
||||
{
|
||||
--(it.currentItemIndex_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalArray::unsafeDereference( const IteratorState &it )
|
||||
{
|
||||
return (*(it.currentPageIndex_))[it.currentItemIndex_];
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalArray::dereference( const IteratorState &it )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( it.array_ &&
|
||||
(it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
|
||||
< it.array_->size_,
|
||||
"ValueInternalArray::dereference(): dereferencing invalid iterator" );
|
||||
return unsafeDereference( it );
|
||||
}
|
||||
|
||||
void
|
||||
ValueInternalArray::makeBeginIterator( IteratorState &it ) const
|
||||
{
|
||||
it.array_ = const_cast<ValueInternalArray *>( this );
|
||||
it.currentItemIndex_ = 0;
|
||||
it.currentPageIndex_ = pages_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
|
||||
{
|
||||
it.array_ = const_cast<ValueInternalArray *>( this );
|
||||
it.currentItemIndex_ = index % itemsPerPage;
|
||||
it.currentPageIndex_ = pages_ + index / itemsPerPage;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::makeEndIterator( IteratorState &it ) const
|
||||
{
|
||||
makeIterator( it, size_ );
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray::ValueInternalArray()
|
||||
: pages_( 0 )
|
||||
, size_( 0 )
|
||||
, pageCount_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
|
||||
: pages_( 0 )
|
||||
, pageCount_( 0 )
|
||||
, size_( other.size_ )
|
||||
{
|
||||
PageIndex minNewPages = other.size_ / itemsPerPage;
|
||||
arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
|
||||
JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages,
|
||||
"ValueInternalArray::reserve(): bad reallocation" );
|
||||
IteratorState itOther;
|
||||
other.makeBeginIterator( itOther );
|
||||
Value *value;
|
||||
for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
|
||||
{
|
||||
if ( index % itemsPerPage == 0 )
|
||||
{
|
||||
PageIndex pageIndex = index / itemsPerPage;
|
||||
value = arrayAllocator()->allocateArrayPage();
|
||||
pages_[pageIndex] = value;
|
||||
}
|
||||
new (value) Value( dereference( itOther ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray &
|
||||
ValueInternalArray::operator =( const ValueInternalArray &other )
|
||||
{
|
||||
ValueInternalArray temp( other );
|
||||
swap( temp );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray::~ValueInternalArray()
|
||||
{
|
||||
// destroy all constructed items
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
makeBeginIterator( it);
|
||||
makeEndIterator( itEnd );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
Value *value = &dereference(it);
|
||||
value->~Value();
|
||||
}
|
||||
// release all pages
|
||||
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||
for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
|
||||
arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
|
||||
// release pages index
|
||||
arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::swap( ValueInternalArray &other )
|
||||
{
|
||||
Value **tempPages = pages_;
|
||||
pages_ = other.pages_;
|
||||
other.pages_ = tempPages;
|
||||
ArrayIndex tempSize = size_;
|
||||
size_ = other.size_;
|
||||
other.size_ = tempSize;
|
||||
PageIndex tempPageCount = pageCount_;
|
||||
pageCount_ = other.pageCount_;
|
||||
other.pageCount_ = tempPageCount;
|
||||
}
|
||||
|
||||
void
|
||||
ValueInternalArray::clear()
|
||||
{
|
||||
ValueInternalArray dummy;
|
||||
swap( dummy );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::resize( ArrayIndex newSize )
|
||||
{
|
||||
if ( newSize == 0 )
|
||||
clear();
|
||||
else if ( newSize < size_ )
|
||||
{
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
makeIterator( it, newSize );
|
||||
makeIterator( itEnd, size_ );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
Value *value = &dereference(it);
|
||||
value->~Value();
|
||||
}
|
||||
PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
|
||||
PageIndex lastPageIndex = size_ / itemsPerPage;
|
||||
for ( ; pageIndex < lastPageIndex; ++pageIndex )
|
||||
arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
|
||||
size_ = newSize;
|
||||
}
|
||||
else if ( newSize > size_ )
|
||||
resolveReference( newSize );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalArray::makeIndexValid( ArrayIndex index )
|
||||
{
|
||||
// Need to enlarge page index ?
|
||||
if ( index >= pageCount_ * itemsPerPage )
|
||||
{
|
||||
PageIndex minNewPages = (index + 1) / itemsPerPage;
|
||||
arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
|
||||
JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
|
||||
}
|
||||
|
||||
// Need to allocate new pages ?
|
||||
ArrayIndex nextPageIndex =
|
||||
(size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
|
||||
: size_;
|
||||
if ( nextPageIndex <= index )
|
||||
{
|
||||
PageIndex pageIndex = nextPageIndex / itemsPerPage;
|
||||
PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
|
||||
for ( ; pageToAllocate-- > 0; ++pageIndex )
|
||||
pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
|
||||
}
|
||||
|
||||
// Initialize all new entries
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
makeIterator( it, size_ );
|
||||
size_ = index + 1;
|
||||
makeIterator( itEnd, size_ );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
Value *value = &dereference(it);
|
||||
new (value) Value(); // Construct a default value using placement new
|
||||
}
|
||||
}
|
||||
|
||||
Value &
|
||||
ValueInternalArray::resolveReference( ArrayIndex index )
|
||||
{
|
||||
if ( index >= size_ )
|
||||
makeIndexValid( index );
|
||||
return pages_[index/itemsPerPage][index%itemsPerPage];
|
||||
}
|
||||
|
||||
Value *
|
||||
ValueInternalArray::find( ArrayIndex index ) const
|
||||
{
|
||||
if ( index >= size_ )
|
||||
return 0;
|
||||
return &(pages_[index/itemsPerPage][index%itemsPerPage]);
|
||||
}
|
||||
|
||||
ValueInternalArray::ArrayIndex
|
||||
ValueInternalArray::size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
int
|
||||
ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
|
||||
{
|
||||
return indexOf(y) - indexOf(x);
|
||||
}
|
||||
|
||||
|
||||
ValueInternalArray::ArrayIndex
|
||||
ValueInternalArray::indexOf( const IteratorState &iterator )
|
||||
{
|
||||
if ( !iterator.array_ )
|
||||
return ArrayIndex(-1);
|
||||
return ArrayIndex(
|
||||
(iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage
|
||||
+ iterator.currentItemIndex_ );
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ValueInternalArray::compare( const ValueInternalArray &other ) const
|
||||
{
|
||||
int sizeDiff( size_ - other.size_ );
|
||||
if ( sizeDiff != 0 )
|
||||
return sizeDiff;
|
||||
|
||||
for ( ArrayIndex index =0; index < size_; ++index )
|
||||
{
|
||||
int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare(
|
||||
other.pages_[index/itemsPerPage][index%itemsPerPage] );
|
||||
if ( diff != 0 )
|
||||
return diff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Json
|
615
dependencies/build/jsoncpp/json_internalmap.inl
vendored
Normal file
615
dependencies/build/jsoncpp/json_internalmap.inl
vendored
Normal file
@ -0,0 +1,615 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
// included by json_value.cpp
|
||||
|
||||
namespace Json {
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueInternalMap
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
|
||||
* This optimization is used by the fast allocator.
|
||||
*/
|
||||
ValueInternalLink::ValueInternalLink()
|
||||
: previous_( 0 )
|
||||
, next_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
ValueInternalLink::~ValueInternalLink()
|
||||
{
|
||||
for ( int index =0; index < itemPerLink; ++index )
|
||||
{
|
||||
if ( !items_[index].isItemAvailable() )
|
||||
{
|
||||
if ( !items_[index].isMemberNameStatic() )
|
||||
free( keys_[index] );
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ValueMapAllocator::~ValueMapAllocator()
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
|
||||
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||
{
|
||||
public: // overridden from ValueMapAllocator
|
||||
virtual ValueInternalMap *newMap()
|
||||
{
|
||||
return new ValueInternalMap();
|
||||
}
|
||||
|
||||
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||
{
|
||||
return new ValueInternalMap( other );
|
||||
}
|
||||
|
||||
virtual void destructMap( ValueInternalMap *map )
|
||||
{
|
||||
delete map;
|
||||
}
|
||||
|
||||
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||
{
|
||||
return new ValueInternalLink[size];
|
||||
}
|
||||
|
||||
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||
{
|
||||
delete [] links;
|
||||
}
|
||||
|
||||
virtual ValueInternalLink *allocateMapLink()
|
||||
{
|
||||
return new ValueInternalLink();
|
||||
}
|
||||
|
||||
virtual void releaseMapLink( ValueInternalLink *link )
|
||||
{
|
||||
delete link;
|
||||
}
|
||||
};
|
||||
#else
|
||||
/// @todo make this thread-safe (lock when accessign batch allocator)
|
||||
class DefaultValueMapAllocator : public ValueMapAllocator
|
||||
{
|
||||
public: // overridden from ValueMapAllocator
|
||||
virtual ValueInternalMap *newMap()
|
||||
{
|
||||
ValueInternalMap *map = mapsAllocator_.allocate();
|
||||
new (map) ValueInternalMap(); // placement new
|
||||
return map;
|
||||
}
|
||||
|
||||
virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
|
||||
{
|
||||
ValueInternalMap *map = mapsAllocator_.allocate();
|
||||
new (map) ValueInternalMap( other ); // placement new
|
||||
return map;
|
||||
}
|
||||
|
||||
virtual void destructMap( ValueInternalMap *map )
|
||||
{
|
||||
if ( map )
|
||||
{
|
||||
map->~ValueInternalMap();
|
||||
mapsAllocator_.release( map );
|
||||
}
|
||||
}
|
||||
|
||||
virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
|
||||
{
|
||||
return new ValueInternalLink[size];
|
||||
}
|
||||
|
||||
virtual void releaseMapBuckets( ValueInternalLink *links )
|
||||
{
|
||||
delete [] links;
|
||||
}
|
||||
|
||||
virtual ValueInternalLink *allocateMapLink()
|
||||
{
|
||||
ValueInternalLink *link = linksAllocator_.allocate();
|
||||
memset( link, 0, sizeof(ValueInternalLink) );
|
||||
return link;
|
||||
}
|
||||
|
||||
virtual void releaseMapLink( ValueInternalLink *link )
|
||||
{
|
||||
link->~ValueInternalLink();
|
||||
linksAllocator_.release( link );
|
||||
}
|
||||
private:
|
||||
BatchAllocator<ValueInternalMap,1> mapsAllocator_;
|
||||
BatchAllocator<ValueInternalLink,1> linksAllocator_;
|
||||
};
|
||||
#endif
|
||||
|
||||
static ValueMapAllocator *&mapAllocator()
|
||||
{
|
||||
static DefaultValueMapAllocator defaultAllocator;
|
||||
static ValueMapAllocator *mapAllocator = &defaultAllocator;
|
||||
return mapAllocator;
|
||||
}
|
||||
|
||||
static struct DummyMapAllocatorInitializer {
|
||||
DummyMapAllocatorInitializer()
|
||||
{
|
||||
mapAllocator(); // ensure mapAllocator() statics are initialized before main().
|
||||
}
|
||||
} dummyMapAllocatorInitializer;
|
||||
|
||||
|
||||
|
||||
// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
|
||||
|
||||
/*
|
||||
use linked list hash map.
|
||||
buckets array is a container.
|
||||
linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
|
||||
value have extra state: valid, available, deleted
|
||||
*/
|
||||
|
||||
|
||||
ValueInternalMap::ValueInternalMap()
|
||||
: buckets_( 0 )
|
||||
, tailLink_( 0 )
|
||||
, bucketsSize_( 0 )
|
||||
, itemCount_( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
|
||||
: buckets_( 0 )
|
||||
, tailLink_( 0 )
|
||||
, bucketsSize_( 0 )
|
||||
, itemCount_( 0 )
|
||||
{
|
||||
reserve( other.itemCount_ );
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
other.makeBeginIterator( it );
|
||||
other.makeEndIterator( itEnd );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
bool isStatic;
|
||||
const char *memberName = key( it, isStatic );
|
||||
const Value &aValue = value( it );
|
||||
resolveReference(memberName, isStatic) = aValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap &
|
||||
ValueInternalMap::operator =( const ValueInternalMap &other )
|
||||
{
|
||||
ValueInternalMap dummy( other );
|
||||
swap( dummy );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap::~ValueInternalMap()
|
||||
{
|
||||
if ( buckets_ )
|
||||
{
|
||||
for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
|
||||
{
|
||||
ValueInternalLink *link = buckets_[bucketIndex].next_;
|
||||
while ( link )
|
||||
{
|
||||
ValueInternalLink *linkToRelease = link;
|
||||
link = link->next_;
|
||||
mapAllocator()->releaseMapLink( linkToRelease );
|
||||
}
|
||||
}
|
||||
mapAllocator()->releaseMapBuckets( buckets_ );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::swap( ValueInternalMap &other )
|
||||
{
|
||||
ValueInternalLink *tempBuckets = buckets_;
|
||||
buckets_ = other.buckets_;
|
||||
other.buckets_ = tempBuckets;
|
||||
ValueInternalLink *tempTailLink = tailLink_;
|
||||
tailLink_ = other.tailLink_;
|
||||
other.tailLink_ = tempTailLink;
|
||||
BucketIndex tempBucketsSize = bucketsSize_;
|
||||
bucketsSize_ = other.bucketsSize_;
|
||||
other.bucketsSize_ = tempBucketsSize;
|
||||
BucketIndex tempItemCount = itemCount_;
|
||||
itemCount_ = other.itemCount_;
|
||||
other.itemCount_ = tempItemCount;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::clear()
|
||||
{
|
||||
ValueInternalMap dummy;
|
||||
swap( dummy );
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap::BucketIndex
|
||||
ValueInternalMap::size() const
|
||||
{
|
||||
return itemCount_;
|
||||
}
|
||||
|
||||
bool
|
||||
ValueInternalMap::reserveDelta( BucketIndex growth )
|
||||
{
|
||||
return reserve( itemCount_ + growth );
|
||||
}
|
||||
|
||||
bool
|
||||
ValueInternalMap::reserve( BucketIndex newItemCount )
|
||||
{
|
||||
if ( !buckets_ && newItemCount > 0 )
|
||||
{
|
||||
buckets_ = mapAllocator()->allocateMapBuckets( 1 );
|
||||
bucketsSize_ = 1;
|
||||
tailLink_ = &buckets_[0];
|
||||
}
|
||||
// BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const Value *
|
||||
ValueInternalMap::find( const char *key ) const
|
||||
{
|
||||
if ( !bucketsSize_ )
|
||||
return 0;
|
||||
HashKey hashedKey = hash( key );
|
||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||
for ( const ValueInternalLink *current = &buckets_[bucketIndex];
|
||||
current != 0;
|
||||
current = current->next_ )
|
||||
{
|
||||
for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
|
||||
{
|
||||
if ( current->items_[index].isItemAvailable() )
|
||||
return 0;
|
||||
if ( strcmp( key, current->keys_[index] ) == 0 )
|
||||
return ¤t->items_[index];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Value *
|
||||
ValueInternalMap::find( const char *key )
|
||||
{
|
||||
const ValueInternalMap *constThis = this;
|
||||
return const_cast<Value *>( constThis->find( key ) );
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalMap::resolveReference( const char *key,
|
||||
bool isStatic )
|
||||
{
|
||||
HashKey hashedKey = hash( key );
|
||||
if ( bucketsSize_ )
|
||||
{
|
||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||
ValueInternalLink **previous = 0;
|
||||
BucketIndex index;
|
||||
for ( ValueInternalLink *current = &buckets_[bucketIndex];
|
||||
current != 0;
|
||||
previous = ¤t->next_, current = current->next_ )
|
||||
{
|
||||
for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
|
||||
{
|
||||
if ( current->items_[index].isItemAvailable() )
|
||||
return setNewItem( key, isStatic, current, index );
|
||||
if ( strcmp( key, current->keys_[index] ) == 0 )
|
||||
return current->items_[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reserveDelta( 1 );
|
||||
return unsafeAdd( key, isStatic, hashedKey );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::remove( const char *key )
|
||||
{
|
||||
HashKey hashedKey = hash( key );
|
||||
if ( !bucketsSize_ )
|
||||
return;
|
||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||
for ( ValueInternalLink *link = &buckets_[bucketIndex];
|
||||
link != 0;
|
||||
link = link->next_ )
|
||||
{
|
||||
BucketIndex index;
|
||||
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
||||
{
|
||||
if ( link->items_[index].isItemAvailable() )
|
||||
return;
|
||||
if ( strcmp( key, link->keys_[index] ) == 0 )
|
||||
{
|
||||
doActualRemove( link, index, bucketIndex );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ValueInternalMap::doActualRemove( ValueInternalLink *link,
|
||||
BucketIndex index,
|
||||
BucketIndex bucketIndex )
|
||||
{
|
||||
// find last item of the bucket and swap it with the 'removed' one.
|
||||
// set removed items flags to 'available'.
|
||||
// if last page only contains 'available' items, then desallocate it (it's empty)
|
||||
ValueInternalLink *&lastLink = getLastLinkInBucket( index );
|
||||
BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
|
||||
for ( ;
|
||||
lastItemIndex < ValueInternalLink::itemPerLink;
|
||||
++lastItemIndex ) // may be optimized with dicotomic search
|
||||
{
|
||||
if ( lastLink->items_[lastItemIndex].isItemAvailable() )
|
||||
break;
|
||||
}
|
||||
|
||||
BucketIndex lastUsedIndex = lastItemIndex - 1;
|
||||
Value *valueToDelete = &link->items_[index];
|
||||
Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
|
||||
if ( valueToDelete != valueToPreserve )
|
||||
valueToDelete->swap( *valueToPreserve );
|
||||
if ( lastUsedIndex == 0 ) // page is now empty
|
||||
{ // remove it from bucket linked list and delete it.
|
||||
ValueInternalLink *linkPreviousToLast = lastLink->previous_;
|
||||
if ( linkPreviousToLast != 0 ) // can not deleted bucket link.
|
||||
{
|
||||
mapAllocator()->releaseMapLink( lastLink );
|
||||
linkPreviousToLast->next_ = 0;
|
||||
lastLink = linkPreviousToLast;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Value dummy;
|
||||
valueToPreserve->swap( dummy ); // restore deleted to default Value.
|
||||
valueToPreserve->setItemUsed( false );
|
||||
}
|
||||
--itemCount_;
|
||||
}
|
||||
|
||||
|
||||
ValueInternalLink *&
|
||||
ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
|
||||
{
|
||||
if ( bucketIndex == bucketsSize_ - 1 )
|
||||
return tailLink_;
|
||||
ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
|
||||
if ( !previous )
|
||||
previous = &buckets_[bucketIndex];
|
||||
return previous;
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalMap::setNewItem( const char *key,
|
||||
bool isStatic,
|
||||
ValueInternalLink *link,
|
||||
BucketIndex index )
|
||||
{
|
||||
char *duplicatedKey = makeMemberName( key );
|
||||
++itemCount_;
|
||||
link->keys_[index] = duplicatedKey;
|
||||
link->items_[index].setItemUsed();
|
||||
link->items_[index].setMemberNameIsStatic( isStatic );
|
||||
return link->items_[index]; // items already default constructed.
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalMap::unsafeAdd( const char *key,
|
||||
bool isStatic,
|
||||
HashKey hashedKey )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
|
||||
BucketIndex bucketIndex = hashedKey % bucketsSize_;
|
||||
ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
|
||||
ValueInternalLink *link = previousLink;
|
||||
BucketIndex index;
|
||||
for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
|
||||
{
|
||||
if ( link->items_[index].isItemAvailable() )
|
||||
break;
|
||||
}
|
||||
if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
|
||||
{
|
||||
ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
|
||||
index = 0;
|
||||
link->next_ = newLink;
|
||||
previousLink = newLink;
|
||||
link = newLink;
|
||||
}
|
||||
return setNewItem( key, isStatic, link, index );
|
||||
}
|
||||
|
||||
|
||||
ValueInternalMap::HashKey
|
||||
ValueInternalMap::hash( const char *key ) const
|
||||
{
|
||||
HashKey hash = 0;
|
||||
while ( *key )
|
||||
hash += *key++ * 37;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ValueInternalMap::compare( const ValueInternalMap &other ) const
|
||||
{
|
||||
int sizeDiff( itemCount_ - other.itemCount_ );
|
||||
if ( sizeDiff != 0 )
|
||||
return sizeDiff;
|
||||
// Strict order guaranty is required. Compare all keys FIRST, then compare values.
|
||||
IteratorState it;
|
||||
IteratorState itEnd;
|
||||
makeBeginIterator( it );
|
||||
makeEndIterator( itEnd );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
if ( !other.find( key( it ) ) )
|
||||
return 1;
|
||||
}
|
||||
|
||||
// All keys are equals, let's compare values
|
||||
makeBeginIterator( it );
|
||||
for ( ; !equals(it,itEnd); increment(it) )
|
||||
{
|
||||
const Value *otherValue = other.find( key( it ) );
|
||||
int valueDiff = value(it).compare( *otherValue );
|
||||
if ( valueDiff != 0 )
|
||||
return valueDiff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::makeBeginIterator( IteratorState &it ) const
|
||||
{
|
||||
it.map_ = const_cast<ValueInternalMap *>( this );
|
||||
it.bucketIndex_ = 0;
|
||||
it.itemIndex_ = 0;
|
||||
it.link_ = buckets_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::makeEndIterator( IteratorState &it ) const
|
||||
{
|
||||
it.map_ = const_cast<ValueInternalMap *>( this );
|
||||
it.bucketIndex_ = bucketsSize_;
|
||||
it.itemIndex_ = 0;
|
||||
it.link_ = 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
|
||||
{
|
||||
return x.map_ == other.map_
|
||||
&& x.bucketIndex_ == other.bucketIndex_
|
||||
&& x.link_ == other.link_
|
||||
&& x.itemIndex_ == other.itemIndex_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::incrementBucket( IteratorState &iterator )
|
||||
{
|
||||
++iterator.bucketIndex_;
|
||||
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
|
||||
"ValueInternalMap::increment(): attempting to iterate beyond end." );
|
||||
if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
|
||||
iterator.link_ = 0;
|
||||
else
|
||||
iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
|
||||
iterator.itemIndex_ = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::increment( IteratorState &iterator )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
|
||||
++iterator.itemIndex_;
|
||||
if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.link_ != 0,
|
||||
"ValueInternalMap::increment(): attempting to iterate beyond end." );
|
||||
iterator.link_ = iterator.link_->next_;
|
||||
if ( iterator.link_ == 0 )
|
||||
incrementBucket( iterator );
|
||||
}
|
||||
else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
|
||||
{
|
||||
incrementBucket( iterator );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueInternalMap::decrement( IteratorState &iterator )
|
||||
{
|
||||
if ( iterator.itemIndex_ == 0 )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
|
||||
if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
|
||||
--(iterator.bucketIndex_);
|
||||
}
|
||||
iterator.link_ = iterator.link_->previous_;
|
||||
iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ValueInternalMap::key( const IteratorState &iterator )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||
return iterator.link_->keys_[iterator.itemIndex_];
|
||||
}
|
||||
|
||||
const char *
|
||||
ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||
isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
|
||||
return iterator.link_->keys_[iterator.itemIndex_];
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
ValueInternalMap::value( const IteratorState &iterator )
|
||||
{
|
||||
JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
|
||||
return iterator.link_->items_[iterator.itemIndex_];
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
|
||||
{
|
||||
int offset = 0;
|
||||
IteratorState it = x;
|
||||
while ( !equals( it, y ) )
|
||||
increment( it );
|
||||
return offset;
|
||||
}
|
||||
|
||||
} // namespace Json
|
880
dependencies/build/jsoncpp/json_reader.cpp
vendored
Normal file
880
dependencies/build/jsoncpp/json_reader.cpp
vendored
Normal file
@ -0,0 +1,880 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include <json/reader.h>
|
||||
# include <json/value.h>
|
||||
# include "json_tool.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
#include <utility>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#if _MSC_VER >= 1400 // VC++ 8.0
|
||||
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
|
||||
#endif
|
||||
|
||||
namespace Json {
|
||||
|
||||
// Implementation of class Features
|
||||
// ////////////////////////////////
|
||||
|
||||
Features::Features()
|
||||
: allowComments_( true )
|
||||
, strictRoot_( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Features
|
||||
Features::all()
|
||||
{
|
||||
return Features();
|
||||
}
|
||||
|
||||
|
||||
Features
|
||||
Features::strictMode()
|
||||
{
|
||||
Features features;
|
||||
features.allowComments_ = false;
|
||||
features.strictRoot_ = true;
|
||||
return features;
|
||||
}
|
||||
|
||||
// Implementation of class Reader
|
||||
// ////////////////////////////////
|
||||
|
||||
|
||||
static inline bool
|
||||
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
|
||||
{
|
||||
return c == c1 || c == c2 || c == c3 || c == c4;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
|
||||
{
|
||||
return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
containsNewLine( Reader::Location begin,
|
||||
Reader::Location end )
|
||||
{
|
||||
for ( ;begin < end; ++begin )
|
||||
if ( *begin == '\n' || *begin == '\r' )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Class Reader
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
Reader::Reader()
|
||||
: features_( Features::all() )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Reader::Reader( const Features &features )
|
||||
: features_( features )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::parse( const std::string &document,
|
||||
Value &root,
|
||||
bool collectComments )
|
||||
{
|
||||
document_ = document;
|
||||
const char *begin = document_.c_str();
|
||||
const char *end = begin + document_.length();
|
||||
return parse( begin, end, root, collectComments );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::parse( std::istream& sin,
|
||||
Value &root,
|
||||
bool collectComments )
|
||||
{
|
||||
//std::istream_iterator<char> begin(sin);
|
||||
//std::istream_iterator<char> end;
|
||||
// Those would allow streamed input from a file, if parse() were a
|
||||
// template function.
|
||||
|
||||
// Since std::string is reference-counted, this at least does not
|
||||
// create an extra copy.
|
||||
std::string doc;
|
||||
std::getline(sin, doc, (char)EOF);
|
||||
return parse( doc, root, collectComments );
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::parse( const char *beginDoc, const char *endDoc,
|
||||
Value &root,
|
||||
bool collectComments )
|
||||
{
|
||||
if ( !features_.allowComments_ )
|
||||
{
|
||||
collectComments = false;
|
||||
}
|
||||
|
||||
begin_ = beginDoc;
|
||||
end_ = endDoc;
|
||||
collectComments_ = collectComments;
|
||||
current_ = begin_;
|
||||
lastValueEnd_ = 0;
|
||||
lastValue_ = 0;
|
||||
commentsBefore_ = "";
|
||||
errors_.clear();
|
||||
while ( !nodes_.empty() )
|
||||
nodes_.pop();
|
||||
nodes_.push( &root );
|
||||
|
||||
bool successful = readValue();
|
||||
Token token;
|
||||
skipCommentTokens( token );
|
||||
if ( collectComments_ && !commentsBefore_.empty() )
|
||||
root.setComment( commentsBefore_, commentAfter );
|
||||
if ( features_.strictRoot_ )
|
||||
{
|
||||
if ( !root.isArray() && !root.isObject() )
|
||||
{
|
||||
// Set error location to start of doc, ideally should be first token found in doc
|
||||
token.type_ = tokenError;
|
||||
token.start_ = beginDoc;
|
||||
token.end_ = endDoc;
|
||||
addError( "A valid JSON document must be either an array or an object value.",
|
||||
token );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return successful;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readValue()
|
||||
{
|
||||
Token token;
|
||||
skipCommentTokens( token );
|
||||
bool successful = true;
|
||||
|
||||
if ( collectComments_ && !commentsBefore_.empty() )
|
||||
{
|
||||
currentValue().setComment( commentsBefore_, commentBefore );
|
||||
commentsBefore_ = "";
|
||||
}
|
||||
|
||||
|
||||
switch ( token.type_ )
|
||||
{
|
||||
case tokenObjectBegin:
|
||||
successful = readObject( token );
|
||||
break;
|
||||
case tokenArrayBegin:
|
||||
successful = readArray( token );
|
||||
break;
|
||||
case tokenNumber:
|
||||
successful = decodeNumber( token );
|
||||
break;
|
||||
case tokenString:
|
||||
successful = decodeString( token );
|
||||
break;
|
||||
case tokenTrue:
|
||||
currentValue() = true;
|
||||
break;
|
||||
case tokenFalse:
|
||||
currentValue() = false;
|
||||
break;
|
||||
case tokenNull:
|
||||
currentValue() = Value();
|
||||
break;
|
||||
default:
|
||||
return addError( "Syntax error: value, object or array expected.", token );
|
||||
}
|
||||
|
||||
if ( collectComments_ )
|
||||
{
|
||||
lastValueEnd_ = current_;
|
||||
lastValue_ = ¤tValue();
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::skipCommentTokens( Token &token )
|
||||
{
|
||||
if ( features_.allowComments_ )
|
||||
{
|
||||
do
|
||||
{
|
||||
readToken( token );
|
||||
}
|
||||
while ( token.type_ == tokenComment );
|
||||
}
|
||||
else
|
||||
{
|
||||
readToken( token );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::expectToken( TokenType type, Token &token, const char *message )
|
||||
{
|
||||
readToken( token );
|
||||
if ( token.type_ != type )
|
||||
return addError( message, token );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readToken( Token &token )
|
||||
{
|
||||
skipSpaces();
|
||||
token.start_ = current_;
|
||||
Char c = getNextChar();
|
||||
bool ok = true;
|
||||
switch ( c )
|
||||
{
|
||||
case '{':
|
||||
token.type_ = tokenObjectBegin;
|
||||
break;
|
||||
case '}':
|
||||
token.type_ = tokenObjectEnd;
|
||||
break;
|
||||
case '[':
|
||||
token.type_ = tokenArrayBegin;
|
||||
break;
|
||||
case ']':
|
||||
token.type_ = tokenArrayEnd;
|
||||
break;
|
||||
case '"':
|
||||
token.type_ = tokenString;
|
||||
ok = readString();
|
||||
break;
|
||||
case '/':
|
||||
token.type_ = tokenComment;
|
||||
ok = readComment();
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '-':
|
||||
token.type_ = tokenNumber;
|
||||
readNumber();
|
||||
break;
|
||||
case 't':
|
||||
token.type_ = tokenTrue;
|
||||
ok = match( "rue", 3 );
|
||||
break;
|
||||
case 'f':
|
||||
token.type_ = tokenFalse;
|
||||
ok = match( "alse", 4 );
|
||||
break;
|
||||
case 'n':
|
||||
token.type_ = tokenNull;
|
||||
ok = match( "ull", 3 );
|
||||
break;
|
||||
case ',':
|
||||
token.type_ = tokenArraySeparator;
|
||||
break;
|
||||
case ':':
|
||||
token.type_ = tokenMemberSeparator;
|
||||
break;
|
||||
case 0:
|
||||
token.type_ = tokenEndOfStream;
|
||||
break;
|
||||
default:
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if ( !ok )
|
||||
token.type_ = tokenError;
|
||||
token.end_ = current_;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::skipSpaces()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
Char c = *current_;
|
||||
if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' )
|
||||
++current_;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::match( Location pattern,
|
||||
int patternLength )
|
||||
{
|
||||
if ( end_ - current_ < patternLength )
|
||||
return false;
|
||||
int index = patternLength;
|
||||
while ( index-- )
|
||||
if ( current_[index] != pattern[index] )
|
||||
return false;
|
||||
current_ += patternLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readComment()
|
||||
{
|
||||
Location commentBegin = current_ - 1;
|
||||
Char c = getNextChar();
|
||||
bool successful = false;
|
||||
if ( c == '*' )
|
||||
successful = readCStyleComment();
|
||||
else if ( c == '/' )
|
||||
successful = readCppStyleComment();
|
||||
if ( !successful )
|
||||
return false;
|
||||
|
||||
if ( collectComments_ )
|
||||
{
|
||||
CommentPlacement placement = commentBefore;
|
||||
if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) )
|
||||
{
|
||||
if ( c != '*' || !containsNewLine( commentBegin, current_ ) )
|
||||
placement = commentAfterOnSameLine;
|
||||
}
|
||||
|
||||
addComment( commentBegin, current_, placement );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::addComment( Location begin,
|
||||
Location end,
|
||||
CommentPlacement placement )
|
||||
{
|
||||
assert( collectComments_ );
|
||||
if ( placement == commentAfterOnSameLine )
|
||||
{
|
||||
assert( lastValue_ != 0 );
|
||||
lastValue_->setComment( std::string( begin, end ), placement );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !commentsBefore_.empty() )
|
||||
commentsBefore_ += "\n";
|
||||
commentsBefore_ += std::string( begin, end );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readCStyleComment()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
Char c = getNextChar();
|
||||
if ( c == '*' && *current_ == '/' )
|
||||
break;
|
||||
}
|
||||
return getNextChar() == '/';
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readCppStyleComment()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
Char c = getNextChar();
|
||||
if ( c == '\r' || c == '\n' )
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::readNumber()
|
||||
{
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
if ( !(*current_ >= '0' && *current_ <= '9') &&
|
||||
!in( *current_, '.', 'e', 'E', '+', '-' ) )
|
||||
break;
|
||||
++current_;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::readString()
|
||||
{
|
||||
Char c = 0;
|
||||
while ( current_ != end_ )
|
||||
{
|
||||
c = getNextChar();
|
||||
if ( c == '\\' )
|
||||
getNextChar();
|
||||
else if ( c == '"' )
|
||||
break;
|
||||
}
|
||||
return c == '"';
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readObject( Token &/*tokenStart*/ )
|
||||
{
|
||||
Token tokenName;
|
||||
std::string name;
|
||||
currentValue() = Value( objectValue );
|
||||
while ( readToken( tokenName ) )
|
||||
{
|
||||
bool initialTokenOk = true;
|
||||
while ( tokenName.type_ == tokenComment && initialTokenOk )
|
||||
initialTokenOk = readToken( tokenName );
|
||||
if ( !initialTokenOk )
|
||||
break;
|
||||
if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object
|
||||
return true;
|
||||
if ( tokenName.type_ != tokenString )
|
||||
break;
|
||||
|
||||
name = "";
|
||||
if ( !decodeString( tokenName, name ) )
|
||||
return recoverFromError( tokenObjectEnd );
|
||||
|
||||
Token colon;
|
||||
if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
|
||||
{
|
||||
return addErrorAndRecover( "Missing ':' after object member name",
|
||||
colon,
|
||||
tokenObjectEnd );
|
||||
}
|
||||
Value &value = currentValue()[ name ];
|
||||
nodes_.push( &value );
|
||||
bool ok = readValue();
|
||||
nodes_.pop();
|
||||
if ( !ok ) // error already set
|
||||
return recoverFromError( tokenObjectEnd );
|
||||
|
||||
Token comma;
|
||||
if ( !readToken( comma )
|
||||
|| ( comma.type_ != tokenObjectEnd &&
|
||||
comma.type_ != tokenArraySeparator &&
|
||||
comma.type_ != tokenComment ) )
|
||||
{
|
||||
return addErrorAndRecover( "Missing ',' or '}' in object declaration",
|
||||
comma,
|
||||
tokenObjectEnd );
|
||||
}
|
||||
bool finalizeTokenOk = true;
|
||||
while ( comma.type_ == tokenComment &&
|
||||
finalizeTokenOk )
|
||||
finalizeTokenOk = readToken( comma );
|
||||
if ( comma.type_ == tokenObjectEnd )
|
||||
return true;
|
||||
}
|
||||
return addErrorAndRecover( "Missing '}' or object member name",
|
||||
tokenName,
|
||||
tokenObjectEnd );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::readArray( Token &/*tokenStart*/ )
|
||||
{
|
||||
currentValue() = Value( arrayValue );
|
||||
skipSpaces();
|
||||
if ( *current_ == ']' ) // empty array
|
||||
{
|
||||
Token endArray;
|
||||
readToken( endArray );
|
||||
return true;
|
||||
}
|
||||
int index = 0;
|
||||
for (;;)
|
||||
{
|
||||
Value &value = currentValue()[ index++ ];
|
||||
nodes_.push( &value );
|
||||
bool ok = readValue();
|
||||
nodes_.pop();
|
||||
if ( !ok ) // error already set
|
||||
return recoverFromError( tokenArrayEnd );
|
||||
|
||||
Token token;
|
||||
// Accept Comment after last item in the array.
|
||||
ok = readToken( token );
|
||||
while ( token.type_ == tokenComment && ok )
|
||||
{
|
||||
ok = readToken( token );
|
||||
}
|
||||
bool badTokenType = ( token.type_ != tokenArraySeparator &&
|
||||
token.type_ != tokenArrayEnd );
|
||||
if ( !ok || badTokenType )
|
||||
{
|
||||
return addErrorAndRecover( "Missing ',' or ']' in array declaration",
|
||||
token,
|
||||
tokenArrayEnd );
|
||||
}
|
||||
if ( token.type_ == tokenArrayEnd )
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeNumber( Token &token )
|
||||
{
|
||||
bool isDouble = false;
|
||||
for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
|
||||
{
|
||||
isDouble = isDouble
|
||||
|| in( *inspect, '.', 'e', 'E', '+' )
|
||||
|| ( *inspect == '-' && inspect != token.start_ );
|
||||
}
|
||||
if ( isDouble )
|
||||
return decodeDouble( token );
|
||||
// Attempts to parse the number as an integer. If the number is
|
||||
// larger than the maximum supported value of an integer then
|
||||
// we decode the number as a double.
|
||||
Location current = token.start_;
|
||||
bool isNegative = *current == '-';
|
||||
if ( isNegative )
|
||||
++current;
|
||||
Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt)
|
||||
: Value::maxLargestUInt;
|
||||
Value::LargestUInt threshold = maxIntegerValue / 10;
|
||||
Value::UInt lastDigitThreshold = Value::UInt( maxIntegerValue % 10 );
|
||||
assert( lastDigitThreshold >=0 && lastDigitThreshold <= 9 );
|
||||
Value::LargestUInt value = 0;
|
||||
while ( current < token.end_ )
|
||||
{
|
||||
Char c = *current++;
|
||||
if ( c < '0' || c > '9' )
|
||||
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||
Value::UInt digit(c - '0');
|
||||
if ( value >= threshold )
|
||||
{
|
||||
// If the current digit is not the last one, or if it is
|
||||
// greater than the last digit of the maximum integer value,
|
||||
// the parse the number as a double.
|
||||
if ( current != token.end_ || digit > lastDigitThreshold )
|
||||
{
|
||||
return decodeDouble( token );
|
||||
}
|
||||
}
|
||||
value = value * 10 + digit;
|
||||
}
|
||||
if ( isNegative )
|
||||
currentValue() = -Value::LargestInt( value );
|
||||
else if ( value <= Value::LargestUInt(Value::maxInt) )
|
||||
currentValue() = Value::LargestInt( value );
|
||||
else
|
||||
currentValue() = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeDouble( Token &token )
|
||||
{
|
||||
double value = 0;
|
||||
const int bufferSize = 32;
|
||||
int count;
|
||||
int length = int(token.end_ - token.start_);
|
||||
if ( length <= bufferSize )
|
||||
{
|
||||
Char buffer[bufferSize+1];
|
||||
memcpy( buffer, token.start_, length );
|
||||
buffer[length] = 0;
|
||||
count = sscanf( buffer, "%lf", &value );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string buffer( token.start_, token.end_ );
|
||||
count = sscanf( buffer.c_str(), "%lf", &value );
|
||||
}
|
||||
|
||||
if ( count != 1 )
|
||||
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||
currentValue() = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeString( Token &token )
|
||||
{
|
||||
std::string decoded;
|
||||
if ( !decodeString( token, decoded ) )
|
||||
return false;
|
||||
currentValue() = decoded;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::decodeString( Token &token, std::string &decoded )
|
||||
{
|
||||
decoded.reserve( token.end_ - token.start_ - 2 );
|
||||
Location current = token.start_ + 1; // skip '"'
|
||||
Location end = token.end_ - 1; // do not include '"'
|
||||
while ( current != end )
|
||||
{
|
||||
Char c = *current++;
|
||||
if ( c == '"' )
|
||||
break;
|
||||
else if ( c == '\\' )
|
||||
{
|
||||
if ( current == end )
|
||||
return addError( "Empty escape sequence in string", token, current );
|
||||
Char escape = *current++;
|
||||
switch ( escape )
|
||||
{
|
||||
case '"': decoded += '"'; break;
|
||||
case '/': decoded += '/'; break;
|
||||
case '\\': decoded += '\\'; break;
|
||||
case 'b': decoded += '\b'; break;
|
||||
case 'f': decoded += '\f'; break;
|
||||
case 'n': decoded += '\n'; break;
|
||||
case 'r': decoded += '\r'; break;
|
||||
case 't': decoded += '\t'; break;
|
||||
case 'u':
|
||||
{
|
||||
unsigned int unicode;
|
||||
if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
|
||||
return false;
|
||||
decoded += codePointToUTF8(unicode);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return addError( "Bad escape sequence in string", token, current );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
decoded += c;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::decodeUnicodeCodePoint( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode )
|
||||
{
|
||||
|
||||
if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
|
||||
return false;
|
||||
if (unicode >= 0xD800 && unicode <= 0xDBFF)
|
||||
{
|
||||
// surrogate pairs
|
||||
if (end - current < 6)
|
||||
return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
|
||||
unsigned int surrogatePair;
|
||||
if (*(current++) == '\\' && *(current++)== 'u')
|
||||
{
|
||||
if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
|
||||
{
|
||||
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::decodeUnicodeEscapeSequence( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode )
|
||||
{
|
||||
if ( end - current < 4 )
|
||||
return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
|
||||
unicode = 0;
|
||||
for ( int index =0; index < 4; ++index )
|
||||
{
|
||||
Char c = *current++;
|
||||
unicode *= 16;
|
||||
if ( c >= '0' && c <= '9' )
|
||||
unicode += c - '0';
|
||||
else if ( c >= 'a' && c <= 'f' )
|
||||
unicode += c - 'a' + 10;
|
||||
else if ( c >= 'A' && c <= 'F' )
|
||||
unicode += c - 'A' + 10;
|
||||
else
|
||||
return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::addError( const std::string &message,
|
||||
Token &token,
|
||||
Location extra )
|
||||
{
|
||||
ErrorInfo info;
|
||||
info.token_ = token;
|
||||
info.message_ = message;
|
||||
info.extra_ = extra;
|
||||
errors_.push_back( info );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::recoverFromError( TokenType skipUntilToken )
|
||||
{
|
||||
int errorCount = int(errors_.size());
|
||||
Token skip;
|
||||
for (;;)
|
||||
{
|
||||
if ( !readToken(skip) )
|
||||
errors_.resize( errorCount ); // discard errors caused by recovery
|
||||
if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
|
||||
break;
|
||||
}
|
||||
errors_.resize( errorCount );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Reader::addErrorAndRecover( const std::string &message,
|
||||
Token &token,
|
||||
TokenType skipUntilToken )
|
||||
{
|
||||
addError( message, token );
|
||||
return recoverFromError( skipUntilToken );
|
||||
}
|
||||
|
||||
|
||||
Value &
|
||||
Reader::currentValue()
|
||||
{
|
||||
return *(nodes_.top());
|
||||
}
|
||||
|
||||
|
||||
Reader::Char
|
||||
Reader::getNextChar()
|
||||
{
|
||||
if ( current_ == end_ )
|
||||
return 0;
|
||||
return *current_++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Reader::getLocationLineAndColumn( Location location,
|
||||
int &line,
|
||||
int &column ) const
|
||||
{
|
||||
Location current = begin_;
|
||||
Location lastLineStart = current;
|
||||
line = 0;
|
||||
while ( current < location && current != end_ )
|
||||
{
|
||||
Char c = *current++;
|
||||
if ( c == '\r' )
|
||||
{
|
||||
if ( *current == '\n' )
|
||||
++current;
|
||||
lastLineStart = current;
|
||||
++line;
|
||||
}
|
||||
else if ( c == '\n' )
|
||||
{
|
||||
lastLineStart = current;
|
||||
++line;
|
||||
}
|
||||
}
|
||||
// column & line start at 1
|
||||
column = int(location - lastLineStart) + 1;
|
||||
++line;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Reader::getLocationLineAndColumn( Location location ) const
|
||||
{
|
||||
int line, column;
|
||||
getLocationLineAndColumn( location, line, column );
|
||||
char buffer[18+16+16+1];
|
||||
sprintf( buffer, "Line %d, Column %d", line, column );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
// Deprecated. Preserved for backward compatibility
|
||||
std::string
|
||||
Reader::getFormatedErrorMessages() const
|
||||
{
|
||||
return getFormattedErrorMessages();
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
Reader::getFormattedErrorMessages() const
|
||||
{
|
||||
std::string formattedMessage;
|
||||
for ( Errors::const_iterator itError = errors_.begin();
|
||||
itError != errors_.end();
|
||||
++itError )
|
||||
{
|
||||
const ErrorInfo &error = *itError;
|
||||
formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
|
||||
formattedMessage += " " + error.message_ + "\n";
|
||||
if ( error.extra_ )
|
||||
formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
|
||||
}
|
||||
return formattedMessage;
|
||||
}
|
||||
|
||||
|
||||
std::istream& operator>>( std::istream &sin, Value &root )
|
||||
{
|
||||
Json::Reader reader;
|
||||
bool ok = reader.parse(sin, root, true);
|
||||
//JSON_ASSERT( ok );
|
||||
if (!ok) throw std::runtime_error(reader.getFormattedErrorMessages());
|
||||
return sin;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Json
|
93
dependencies/build/jsoncpp/json_tool.h
vendored
Normal file
93
dependencies/build/jsoncpp/json_tool.h
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||
# define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
||||
|
||||
/* This header provides common string manipulation support, such as UTF-8,
|
||||
* portable conversion from/to string...
|
||||
*
|
||||
* It is an internal header that must not be exposed.
|
||||
*/
|
||||
|
||||
namespace Json {
|
||||
|
||||
/// Converts a unicode code-point to UTF-8.
|
||||
static inline std::string
|
||||
codePointToUTF8(unsigned int cp)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||
|
||||
if (cp <= 0x7f)
|
||||
{
|
||||
result.resize(1);
|
||||
result[0] = static_cast<char>(cp);
|
||||
}
|
||||
else if (cp <= 0x7FF)
|
||||
{
|
||||
result.resize(2);
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||
}
|
||||
else if (cp <= 0xFFFF)
|
||||
{
|
||||
result.resize(3);
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
|
||||
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
|
||||
}
|
||||
else if (cp <= 0x10FFFF)
|
||||
{
|
||||
result.resize(4);
|
||||
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
|
||||
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// Returns true if ch is a control character (in range [0,32[).
|
||||
static inline bool
|
||||
isControlCharacter(char ch)
|
||||
{
|
||||
return ch > 0 && ch <= 0x1F;
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
/// Constant that specify the size of the buffer that must be passed to uintToString.
|
||||
uintToStringBufferSize = 3*sizeof(LargestUInt)+1
|
||||
};
|
||||
|
||||
// Defines a char buffer for use with uintToString().
|
||||
typedef char UIntToStringBuffer[uintToStringBufferSize];
|
||||
|
||||
|
||||
/** Converts an unsigned integer to string.
|
||||
* @param value Unsigned interger to convert to string
|
||||
* @param current Input/Output string buffer.
|
||||
* Must have at least uintToStringBufferSize chars free.
|
||||
*/
|
||||
static inline void
|
||||
uintToString( LargestUInt value,
|
||||
char *¤t )
|
||||
{
|
||||
*--current = 0;
|
||||
do
|
||||
{
|
||||
*--current = char(value % 10) + '0';
|
||||
value /= 10;
|
||||
}
|
||||
while ( value != 0 );
|
||||
}
|
||||
|
||||
} // namespace Json {
|
||||
|
||||
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
|
1829
dependencies/build/jsoncpp/json_value.cpp
vendored
Normal file
1829
dependencies/build/jsoncpp/json_value.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
299
dependencies/build/jsoncpp/json_valueiterator.inl
vendored
Normal file
299
dependencies/build/jsoncpp/json_valueiterator.inl
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
// included by json_value.cpp
|
||||
|
||||
namespace Json {
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueIteratorBase
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase()
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
: current_()
|
||||
, isNull_( true )
|
||||
{
|
||||
}
|
||||
#else
|
||||
: isArray_( true )
|
||||
, isNull_( true )
|
||||
{
|
||||
iterator_.array_ = ValueInternalArray::IteratorState();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator ¤t )
|
||||
: current_( current )
|
||||
, isNull_( false )
|
||||
{
|
||||
}
|
||||
#else
|
||||
ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
|
||||
: isArray_( true )
|
||||
{
|
||||
iterator_.array_ = state;
|
||||
}
|
||||
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
|
||||
: isArray_( false )
|
||||
{
|
||||
iterator_.map_ = state;
|
||||
}
|
||||
#endif
|
||||
|
||||
Value &
|
||||
ValueIteratorBase::deref() const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
return current_->second;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return ValueInternalArray::dereference( iterator_.array_ );
|
||||
return ValueInternalMap::value( iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueIteratorBase::increment()
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
++current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
ValueInternalArray::increment( iterator_.array_ );
|
||||
ValueInternalMap::increment( iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueIteratorBase::decrement()
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
--current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
ValueInternalArray::decrement( iterator_.array_ );
|
||||
ValueInternalMap::decrement( iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ValueIteratorBase::difference_type
|
||||
ValueIteratorBase::computeDistance( const SelfType &other ) const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
# ifdef JSON_USE_CPPTL_SMALLMAP
|
||||
return current_ - other.current_;
|
||||
# else
|
||||
// Iterator for null value are initialized using the default
|
||||
// constructor, which initialize current_ to the default
|
||||
// std::map::iterator. As begin() and end() are two instance
|
||||
// of the default std::map::iterator, they can not be compared.
|
||||
// To allow this, we handle this comparison specifically.
|
||||
if ( isNull_ && other.isNull_ )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
|
||||
// which is the one used by default).
|
||||
// Using a portable hand-made version for non random iterator instead:
|
||||
// return difference_type( std::distance( current_, other.current_ ) );
|
||||
difference_type myDistance = 0;
|
||||
for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
|
||||
{
|
||||
++myDistance;
|
||||
}
|
||||
return myDistance;
|
||||
# endif
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
|
||||
return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ValueIteratorBase::isEqual( const SelfType &other ) const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
if ( isNull_ )
|
||||
{
|
||||
return other.isNull_;
|
||||
}
|
||||
return current_ == other.current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
|
||||
return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ValueIteratorBase::copy( const SelfType &other )
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
current_ = other.current_;
|
||||
#else
|
||||
if ( isArray_ )
|
||||
iterator_.array_ = other.iterator_.array_;
|
||||
iterator_.map_ = other.iterator_.map_;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Value
|
||||
ValueIteratorBase::key() const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
if ( czstring.c_str() )
|
||||
{
|
||||
if ( czstring.isStaticString() )
|
||||
return Value( StaticString( czstring.c_str() ) );
|
||||
return Value( czstring.c_str() );
|
||||
}
|
||||
return Value( czstring.index() );
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return Value( ValueInternalArray::indexOf( iterator_.array_ ) );
|
||||
bool isStatic;
|
||||
const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );
|
||||
if ( isStatic )
|
||||
return Value( StaticString( memberName ) );
|
||||
return Value( memberName );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
UInt
|
||||
ValueIteratorBase::index() const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
if ( !czstring.c_str() )
|
||||
return czstring.index();
|
||||
return Value::UInt( -1 );
|
||||
#else
|
||||
if ( isArray_ )
|
||||
return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
|
||||
return Value::UInt( -1 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ValueIteratorBase::memberName() const
|
||||
{
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
const char *name = (*current_).first.c_str();
|
||||
return name ? name : "";
|
||||
#else
|
||||
if ( !isArray_ )
|
||||
return ValueInternalMap::key( iterator_.map_ );
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueConstIterator
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueConstIterator::ValueConstIterator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator ¤t )
|
||||
: ValueIteratorBase( current )
|
||||
{
|
||||
}
|
||||
#else
|
||||
ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
|
||||
ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
ValueConstIterator &
|
||||
ValueConstIterator::operator =( const ValueIteratorBase &other )
|
||||
{
|
||||
copy( other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// class ValueIterator
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIterator::ValueIterator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#ifndef JSON_VALUE_USE_INTERNAL_MAP
|
||||
ValueIterator::ValueIterator( const Value::ObjectValues::iterator ¤t )
|
||||
: ValueIteratorBase( current )
|
||||
{
|
||||
}
|
||||
#else
|
||||
ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
|
||||
: ValueIteratorBase( state )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
ValueIterator::ValueIterator( const ValueConstIterator &other )
|
||||
: ValueIteratorBase( other )
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator::ValueIterator( const ValueIterator &other )
|
||||
: ValueIteratorBase( other )
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator &
|
||||
ValueIterator::operator =( const SelfType &other )
|
||||
{
|
||||
copy( other );
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace Json
|
838
dependencies/build/jsoncpp/json_writer.cpp
vendored
Normal file
838
dependencies/build/jsoncpp/json_writer.cpp
vendored
Normal file
@ -0,0 +1,838 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include <json/writer.h>
|
||||
# include "json_tool.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
#include <utility>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#if _MSC_VER >= 1400 // VC++ 8.0
|
||||
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
|
||||
#endif
|
||||
|
||||
namespace Json {
|
||||
|
||||
static bool containsControlCharacter( const char* str )
|
||||
{
|
||||
while ( *str )
|
||||
{
|
||||
if ( isControlCharacter( *(str++) ) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::string valueToString( LargestInt value )
|
||||
{
|
||||
UIntToStringBuffer buffer;
|
||||
char *current = buffer + sizeof(buffer);
|
||||
bool isNegative = value < 0;
|
||||
if ( isNegative )
|
||||
value = -value;
|
||||
uintToString( LargestUInt(value), current );
|
||||
if ( isNegative )
|
||||
*--current = '-';
|
||||
assert( current >= buffer );
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
std::string valueToString( LargestUInt value )
|
||||
{
|
||||
UIntToStringBuffer buffer;
|
||||
char *current = buffer + sizeof(buffer);
|
||||
uintToString( value, current );
|
||||
assert( current >= buffer );
|
||||
return current;
|
||||
}
|
||||
|
||||
#if defined(JSON_HAS_INT64)
|
||||
|
||||
std::string valueToString( Int value )
|
||||
{
|
||||
return valueToString( LargestInt(value) );
|
||||
}
|
||||
|
||||
|
||||
std::string valueToString( UInt value )
|
||||
{
|
||||
return valueToString( LargestUInt(value) );
|
||||
}
|
||||
|
||||
#endif // # if defined(JSON_HAS_INT64)
|
||||
|
||||
|
||||
std::string valueToString( double value )
|
||||
{
|
||||
char buffer[32];
|
||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
|
||||
sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
|
||||
#else
|
||||
sprintf(buffer, "%#.16g", value);
|
||||
#endif
|
||||
char* ch = buffer + strlen(buffer) - 1;
|
||||
if (*ch != '0') return buffer; // nothing to truncate, so save time
|
||||
while(ch > buffer && *ch == '0'){
|
||||
--ch;
|
||||
}
|
||||
char* last_nonzero = ch;
|
||||
while(ch >= buffer){
|
||||
switch(*ch){
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
--ch;
|
||||
continue;
|
||||
case '.':
|
||||
// Truncate zeroes to save bytes in output, but keep one.
|
||||
*(last_nonzero+2) = '\0';
|
||||
return buffer;
|
||||
default:
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
std::string valueToString( bool value )
|
||||
{
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
std::string valueToQuotedString( const char *value )
|
||||
{
|
||||
// Not sure how to handle unicode...
|
||||
if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
|
||||
return std::string("\"") + value + "\"";
|
||||
// We have to walk value and escape any special characters.
|
||||
// Appending to std::string is not efficient, but this should be rare.
|
||||
// (Note: forward slashes are *not* rare, but I am not escaping them.)
|
||||
std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
|
||||
std::string result;
|
||||
result.reserve(maxsize); // to avoid lots of mallocs
|
||||
result += "\"";
|
||||
for (const char* c=value; *c != 0; ++c)
|
||||
{
|
||||
switch(*c)
|
||||
{
|
||||
case '\"':
|
||||
result += "\\\"";
|
||||
break;
|
||||
case '\\':
|
||||
result += "\\\\";
|
||||
break;
|
||||
case '\b':
|
||||
result += "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
result += "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
result += "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
result += "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
result += "\\t";
|
||||
break;
|
||||
//case '/':
|
||||
// Even though \/ is considered a legal escape in JSON, a bare
|
||||
// slash is also legal, so I see no reason to escape it.
|
||||
// (I hope I am not misunderstanding something.
|
||||
// blep notes: actually escaping \/ may be useful in javascript to avoid </
|
||||
// sequence.
|
||||
// Should add a flag to allow this compatibility mode and prevent this
|
||||
// sequence from occurring.
|
||||
default:
|
||||
if ( isControlCharacter( *c ) )
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
|
||||
result += oss.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
result += *c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
result += "\"";
|
||||
return result;
|
||||
}
|
||||
|
||||
// Class Writer
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
Writer::~Writer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Class FastWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
FastWriter::FastWriter()
|
||||
: yamlCompatiblityEnabled_( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FastWriter::enableYAMLCompatibility()
|
||||
{
|
||||
yamlCompatiblityEnabled_ = true;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
FastWriter::write( const Value &root )
|
||||
{
|
||||
document_ = "";
|
||||
writeValue( root );
|
||||
document_ += "\n";
|
||||
return document_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FastWriter::writeValue( const Value &value )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
case nullValue:
|
||||
document_ += "null";
|
||||
break;
|
||||
case intValue:
|
||||
document_ += valueToString( value.asLargestInt() );
|
||||
break;
|
||||
case uintValue:
|
||||
document_ += valueToString( value.asLargestUInt() );
|
||||
break;
|
||||
case realValue:
|
||||
document_ += valueToString( value.asDouble() );
|
||||
break;
|
||||
case stringValue:
|
||||
document_ += valueToQuotedString( value.asCString() );
|
||||
break;
|
||||
case booleanValue:
|
||||
document_ += valueToString( value.asBool() );
|
||||
break;
|
||||
case arrayValue:
|
||||
{
|
||||
document_ += "[";
|
||||
int size = value.size();
|
||||
for ( int index =0; index < size; ++index )
|
||||
{
|
||||
if ( index > 0 )
|
||||
document_ += ",";
|
||||
writeValue( value[index] );
|
||||
}
|
||||
document_ += "]";
|
||||
}
|
||||
break;
|
||||
case objectValue:
|
||||
{
|
||||
Value::Members members( value.getMemberNames() );
|
||||
document_ += "{";
|
||||
for ( Value::Members::iterator it = members.begin();
|
||||
it != members.end();
|
||||
++it )
|
||||
{
|
||||
const std::string &name = *it;
|
||||
if ( it != members.begin() )
|
||||
document_ += ",";
|
||||
document_ += valueToQuotedString( name.c_str() );
|
||||
document_ += yamlCompatiblityEnabled_ ? ": "
|
||||
: ":";
|
||||
writeValue( value[name] );
|
||||
}
|
||||
document_ += "}";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Class StyledWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
StyledWriter::StyledWriter()
|
||||
: rightMargin_( 74 )
|
||||
, indentSize_( 3 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StyledWriter::write( const Value &root )
|
||||
{
|
||||
document_ = "";
|
||||
addChildValues_ = false;
|
||||
indentString_ = "";
|
||||
writeCommentBeforeValue( root );
|
||||
writeValue( root );
|
||||
writeCommentAfterValueOnSameLine( root );
|
||||
document_ += "\n";
|
||||
return document_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeValue( const Value &value )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
case nullValue:
|
||||
pushValue( "null" );
|
||||
break;
|
||||
case intValue:
|
||||
pushValue( valueToString( value.asLargestInt() ) );
|
||||
break;
|
||||
case uintValue:
|
||||
pushValue( valueToString( value.asLargestUInt() ) );
|
||||
break;
|
||||
case realValue:
|
||||
pushValue( valueToString( value.asDouble() ) );
|
||||
break;
|
||||
case stringValue:
|
||||
pushValue( valueToQuotedString( value.asCString() ) );
|
||||
break;
|
||||
case booleanValue:
|
||||
pushValue( valueToString( value.asBool() ) );
|
||||
break;
|
||||
case arrayValue:
|
||||
writeArrayValue( value);
|
||||
break;
|
||||
case objectValue:
|
||||
{
|
||||
Value::Members members( value.getMemberNames() );
|
||||
if ( members.empty() )
|
||||
pushValue( "{}" );
|
||||
else
|
||||
{
|
||||
writeWithIndent( "{" );
|
||||
indent();
|
||||
Value::Members::iterator it = members.begin();
|
||||
for (;;)
|
||||
{
|
||||
const std::string &name = *it;
|
||||
const Value &childValue = value[name];
|
||||
writeCommentBeforeValue( childValue );
|
||||
writeWithIndent( valueToQuotedString( name.c_str() ) );
|
||||
document_ += " : ";
|
||||
writeValue( childValue );
|
||||
if ( ++it == members.end() )
|
||||
{
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
break;
|
||||
}
|
||||
document_ += ",";
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent( "}" );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeArrayValue( const Value &value )
|
||||
{
|
||||
unsigned size = value.size();
|
||||
if ( size == 0 )
|
||||
pushValue( "[]" );
|
||||
else
|
||||
{
|
||||
bool isArrayMultiLine = isMultineArray( value );
|
||||
if ( isArrayMultiLine )
|
||||
{
|
||||
writeWithIndent( "[" );
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
unsigned index =0;
|
||||
for (;;)
|
||||
{
|
||||
const Value &childValue = value[index];
|
||||
writeCommentBeforeValue( childValue );
|
||||
if ( hasChildValue )
|
||||
writeWithIndent( childValues_[index] );
|
||||
else
|
||||
{
|
||||
writeIndent();
|
||||
writeValue( childValue );
|
||||
}
|
||||
if ( ++index == size )
|
||||
{
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
break;
|
||||
}
|
||||
document_ += ",";
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent( "]" );
|
||||
}
|
||||
else // output on a single line
|
||||
{
|
||||
assert( childValues_.size() == size );
|
||||
document_ += "[ ";
|
||||
for ( unsigned index =0; index < size; ++index )
|
||||
{
|
||||
if ( index > 0 )
|
||||
document_ += ", ";
|
||||
document_ += childValues_[index];
|
||||
}
|
||||
document_ += " ]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledWriter::isMultineArray( const Value &value )
|
||||
{
|
||||
int size = value.size();
|
||||
bool isMultiLine = size*3 >= rightMargin_ ;
|
||||
childValues_.clear();
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
const Value &childValue = value[index];
|
||||
isMultiLine = isMultiLine ||
|
||||
( (childValue.isArray() || childValue.isObject()) &&
|
||||
childValue.size() > 0 );
|
||||
}
|
||||
if ( !isMultiLine ) // check if line length > max line length
|
||||
{
|
||||
childValues_.reserve( size );
|
||||
addChildValues_ = true;
|
||||
int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
writeValue( value[index] );
|
||||
lineLength += int( childValues_[index].length() );
|
||||
isMultiLine = isMultiLine && hasCommentForValue( value[index] );
|
||||
}
|
||||
addChildValues_ = false;
|
||||
isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
||||
}
|
||||
return isMultiLine;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::pushValue( const std::string &value )
|
||||
{
|
||||
if ( addChildValues_ )
|
||||
childValues_.push_back( value );
|
||||
else
|
||||
document_ += value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeIndent()
|
||||
{
|
||||
if ( !document_.empty() )
|
||||
{
|
||||
char last = document_[document_.length()-1];
|
||||
if ( last == ' ' ) // already indented
|
||||
return;
|
||||
if ( last != '\n' ) // Comments may add new-line
|
||||
document_ += '\n';
|
||||
}
|
||||
document_ += indentString_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeWithIndent( const std::string &value )
|
||||
{
|
||||
writeIndent();
|
||||
document_ += value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::indent()
|
||||
{
|
||||
indentString_ += std::string( indentSize_, ' ' );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::unindent()
|
||||
{
|
||||
assert( int(indentString_.size()) >= indentSize_ );
|
||||
indentString_.resize( indentString_.size() - indentSize_ );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeCommentBeforeValue( const Value &root )
|
||||
{
|
||||
if ( !root.hasComment( commentBefore ) )
|
||||
return;
|
||||
document_ += normalizeEOL( root.getComment( commentBefore ) );
|
||||
document_ += "\n";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
|
||||
{
|
||||
if ( root.hasComment( commentAfterOnSameLine ) )
|
||||
document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
|
||||
|
||||
if ( root.hasComment( commentAfter ) )
|
||||
{
|
||||
document_ += "\n";
|
||||
document_ += normalizeEOL( root.getComment( commentAfter ) );
|
||||
document_ += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledWriter::hasCommentForValue( const Value &value )
|
||||
{
|
||||
return value.hasComment( commentBefore )
|
||||
|| value.hasComment( commentAfterOnSameLine )
|
||||
|| value.hasComment( commentAfter );
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StyledWriter::normalizeEOL( const std::string &text )
|
||||
{
|
||||
std::string normalized;
|
||||
normalized.reserve( text.length() );
|
||||
const char *begin = text.c_str();
|
||||
const char *end = begin + text.length();
|
||||
const char *current = begin;
|
||||
while ( current != end )
|
||||
{
|
||||
char c = *current++;
|
||||
if ( c == '\r' ) // mac or dos EOL
|
||||
{
|
||||
if ( *current == '\n' ) // convert dos EOL
|
||||
++current;
|
||||
normalized += '\n';
|
||||
}
|
||||
else // handle unix EOL & other char
|
||||
normalized += c;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
// Class StyledStreamWriter
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
StyledStreamWriter::StyledStreamWriter( std::string indentation )
|
||||
: document_(NULL)
|
||||
, rightMargin_( 74 )
|
||||
, indentation_( indentation )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::write( std::ostream &out, const Value &root )
|
||||
{
|
||||
document_ = &out;
|
||||
addChildValues_ = false;
|
||||
indentString_ = "";
|
||||
writeCommentBeforeValue( root );
|
||||
writeValue( root );
|
||||
writeCommentAfterValueOnSameLine( root );
|
||||
*document_ << "\n";
|
||||
document_ = NULL; // Forget the stream, for safety.
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeValue( const Value &value )
|
||||
{
|
||||
switch ( value.type() )
|
||||
{
|
||||
case nullValue:
|
||||
pushValue( "null" );
|
||||
break;
|
||||
case intValue:
|
||||
pushValue( valueToString( value.asLargestInt() ) );
|
||||
break;
|
||||
case uintValue:
|
||||
pushValue( valueToString( value.asLargestUInt() ) );
|
||||
break;
|
||||
case realValue:
|
||||
pushValue( valueToString( value.asDouble() ) );
|
||||
break;
|
||||
case stringValue:
|
||||
pushValue( valueToQuotedString( value.asCString() ) );
|
||||
break;
|
||||
case booleanValue:
|
||||
pushValue( valueToString( value.asBool() ) );
|
||||
break;
|
||||
case arrayValue:
|
||||
writeArrayValue( value);
|
||||
break;
|
||||
case objectValue:
|
||||
{
|
||||
Value::Members members( value.getMemberNames() );
|
||||
if ( members.empty() )
|
||||
pushValue( "{}" );
|
||||
else
|
||||
{
|
||||
writeWithIndent( "{" );
|
||||
indent();
|
||||
Value::Members::iterator it = members.begin();
|
||||
for (;;)
|
||||
{
|
||||
const std::string &name = *it;
|
||||
const Value &childValue = value[name];
|
||||
writeCommentBeforeValue( childValue );
|
||||
writeWithIndent( valueToQuotedString( name.c_str() ) );
|
||||
*document_ << " : ";
|
||||
writeValue( childValue );
|
||||
if ( ++it == members.end() )
|
||||
{
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
break;
|
||||
}
|
||||
*document_ << ",";
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent( "}" );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeArrayValue( const Value &value )
|
||||
{
|
||||
unsigned size = value.size();
|
||||
if ( size == 0 )
|
||||
pushValue( "[]" );
|
||||
else
|
||||
{
|
||||
bool isArrayMultiLine = isMultineArray( value );
|
||||
if ( isArrayMultiLine )
|
||||
{
|
||||
writeWithIndent( "[" );
|
||||
indent();
|
||||
bool hasChildValue = !childValues_.empty();
|
||||
unsigned index =0;
|
||||
for (;;)
|
||||
{
|
||||
const Value &childValue = value[index];
|
||||
writeCommentBeforeValue( childValue );
|
||||
if ( hasChildValue )
|
||||
writeWithIndent( childValues_[index] );
|
||||
else
|
||||
{
|
||||
writeIndent();
|
||||
writeValue( childValue );
|
||||
}
|
||||
if ( ++index == size )
|
||||
{
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
break;
|
||||
}
|
||||
*document_ << ",";
|
||||
writeCommentAfterValueOnSameLine( childValue );
|
||||
}
|
||||
unindent();
|
||||
writeWithIndent( "]" );
|
||||
}
|
||||
else // output on a single line
|
||||
{
|
||||
assert( childValues_.size() == size );
|
||||
*document_ << "[ ";
|
||||
for ( unsigned index =0; index < size; ++index )
|
||||
{
|
||||
if ( index > 0 )
|
||||
*document_ << ", ";
|
||||
*document_ << childValues_[index];
|
||||
}
|
||||
*document_ << " ]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledStreamWriter::isMultineArray( const Value &value )
|
||||
{
|
||||
int size = value.size();
|
||||
bool isMultiLine = size*3 >= rightMargin_ ;
|
||||
childValues_.clear();
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
const Value &childValue = value[index];
|
||||
isMultiLine = isMultiLine ||
|
||||
( (childValue.isArray() || childValue.isObject()) &&
|
||||
childValue.size() > 0 );
|
||||
}
|
||||
if ( !isMultiLine ) // check if line length > max line length
|
||||
{
|
||||
childValues_.reserve( size );
|
||||
addChildValues_ = true;
|
||||
int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
|
||||
for ( int index =0; index < size && !isMultiLine; ++index )
|
||||
{
|
||||
writeValue( value[index] );
|
||||
lineLength += int( childValues_[index].length() );
|
||||
isMultiLine = isMultiLine && hasCommentForValue( value[index] );
|
||||
}
|
||||
addChildValues_ = false;
|
||||
isMultiLine = isMultiLine || lineLength >= rightMargin_;
|
||||
}
|
||||
return isMultiLine;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::pushValue( const std::string &value )
|
||||
{
|
||||
if ( addChildValues_ )
|
||||
childValues_.push_back( value );
|
||||
else
|
||||
*document_ << value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeIndent()
|
||||
{
|
||||
/*
|
||||
Some comments in this method would have been nice. ;-)
|
||||
|
||||
if ( !document_.empty() )
|
||||
{
|
||||
char last = document_[document_.length()-1];
|
||||
if ( last == ' ' ) // already indented
|
||||
return;
|
||||
if ( last != '\n' ) // Comments may add new-line
|
||||
*document_ << '\n';
|
||||
}
|
||||
*/
|
||||
*document_ << '\n' << indentString_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeWithIndent( const std::string &value )
|
||||
{
|
||||
writeIndent();
|
||||
*document_ << value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::indent()
|
||||
{
|
||||
indentString_ += indentation_;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::unindent()
|
||||
{
|
||||
assert( indentString_.size() >= indentation_.size() );
|
||||
indentString_.resize( indentString_.size() - indentation_.size() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeCommentBeforeValue( const Value &root )
|
||||
{
|
||||
if ( !root.hasComment( commentBefore ) )
|
||||
return;
|
||||
*document_ << normalizeEOL( root.getComment( commentBefore ) );
|
||||
*document_ << "\n";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
|
||||
{
|
||||
if ( root.hasComment( commentAfterOnSameLine ) )
|
||||
*document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
|
||||
|
||||
if ( root.hasComment( commentAfter ) )
|
||||
{
|
||||
*document_ << "\n";
|
||||
*document_ << normalizeEOL( root.getComment( commentAfter ) );
|
||||
*document_ << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StyledStreamWriter::hasCommentForValue( const Value &value )
|
||||
{
|
||||
return value.hasComment( commentBefore )
|
||||
|| value.hasComment( commentAfterOnSameLine )
|
||||
|| value.hasComment( commentAfter );
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StyledStreamWriter::normalizeEOL( const std::string &text )
|
||||
{
|
||||
std::string normalized;
|
||||
normalized.reserve( text.length() );
|
||||
const char *begin = text.c_str();
|
||||
const char *end = begin + text.length();
|
||||
const char *current = begin;
|
||||
while ( current != end )
|
||||
{
|
||||
char c = *current++;
|
||||
if ( c == '\r' ) // mac or dos EOL
|
||||
{
|
||||
if ( *current == '\n' ) // convert dos EOL
|
||||
++current;
|
||||
normalized += '\n';
|
||||
}
|
||||
else // handle unix EOL & other char
|
||||
normalized += c;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<( std::ostream &sout, const Value &root )
|
||||
{
|
||||
Json::StyledStreamWriter writer;
|
||||
writer.write(sout, root);
|
||||
return sout;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Json
|
8
dependencies/build/jsoncpp/sconscript
vendored
Normal file
8
dependencies/build/jsoncpp/sconscript
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
Import( 'env buildLibrary' )
|
||||
|
||||
buildLibrary( env, Split( """
|
||||
json_reader.cpp
|
||||
json_value.cpp
|
||||
json_writer.cpp
|
||||
""" ),
|
||||
'json' )
|
24
dependencies/include/json/autolink.h
vendored
Normal file
24
dependencies/include/json/autolink.h
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_AUTOLINK_H_INCLUDED
|
||||
# define JSON_AUTOLINK_H_INCLUDED
|
||||
|
||||
# include "config.h"
|
||||
|
||||
# ifdef JSON_IN_CPPTL
|
||||
# include <cpptl/cpptl_autolink.h>
|
||||
# endif
|
||||
|
||||
# if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && !defined(JSON_IN_CPPTL)
|
||||
# define CPPTL_AUTOLINK_NAME "json"
|
||||
# undef CPPTL_AUTOLINK_DLL
|
||||
# ifdef JSON_DLL
|
||||
# define CPPTL_AUTOLINK_DLL
|
||||
# endif
|
||||
# include "autolink.h"
|
||||
# endif
|
||||
|
||||
#endif // JSON_AUTOLINK_H_INCLUDED
|
96
dependencies/include/json/config.h
vendored
Normal file
96
dependencies/include/json/config.h
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_CONFIG_H_INCLUDED
|
||||
# define JSON_CONFIG_H_INCLUDED
|
||||
|
||||
/// If defined, indicates that json library is embedded in CppTL library.
|
||||
//# define JSON_IN_CPPTL 1
|
||||
|
||||
/// If defined, indicates that json may leverage CppTL library
|
||||
//# define JSON_USE_CPPTL 1
|
||||
/// If defined, indicates that cpptl vector based map should be used instead of std::map
|
||||
/// as Value container.
|
||||
//# define JSON_USE_CPPTL_SMALLMAP 1
|
||||
/// If defined, indicates that Json specific container should be used
|
||||
/// (hash table & simple deque container with customizable allocator).
|
||||
/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
|
||||
//# define JSON_VALUE_USE_INTERNAL_MAP 1
|
||||
/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
|
||||
/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
|
||||
/// as if it was a POD) that may cause some validation tool to report errors.
|
||||
/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
|
||||
//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
|
||||
|
||||
/// If defined, indicates that Json use exception to report invalid type manipulation
|
||||
/// instead of C assert macro.
|
||||
# define JSON_USE_EXCEPTION 1
|
||||
|
||||
/// If defined, indicates that the source file is amalgated
|
||||
/// to prevent private header inclusion.
|
||||
/// Remarks: it is automatically defined in the generated amalgated header.
|
||||
// #define JSON_IS_AMALGAMATION
|
||||
|
||||
|
||||
# ifdef JSON_IN_CPPTL
|
||||
# include <cpptl/config.h>
|
||||
# ifndef JSON_USE_CPPTL
|
||||
# define JSON_USE_CPPTL 1
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef JSON_IN_CPPTL
|
||||
# define JSON_API CPPTL_API
|
||||
# elif defined(JSON_DLL_BUILD)
|
||||
# define JSON_API __declspec(dllexport)
|
||||
# elif defined(JSON_DLL)
|
||||
# define JSON_API __declspec(dllimport)
|
||||
# else
|
||||
# define JSON_API
|
||||
# endif
|
||||
|
||||
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer
|
||||
// Storages, and 64 bits integer support is disabled.
|
||||
// #define JSON_NO_INT64 1
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
|
||||
// Microsoft Visual Studio 6 only support conversion from __int64 to double
|
||||
// (no conversion from unsigned __int64).
|
||||
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
|
||||
#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
|
||||
/// Indicates that the following function is deprecated.
|
||||
# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
|
||||
#endif
|
||||
|
||||
#if !defined(JSONCPP_DEPRECATED)
|
||||
# define JSONCPP_DEPRECATED(message)
|
||||
#endif // if !defined(JSONCPP_DEPRECATED)
|
||||
|
||||
namespace Json {
|
||||
typedef int Int;
|
||||
typedef unsigned int UInt;
|
||||
# if defined(JSON_NO_INT64)
|
||||
typedef int LargestInt;
|
||||
typedef unsigned int LargestUInt;
|
||||
# undef JSON_HAS_INT64
|
||||
# else // if defined(JSON_NO_INT64)
|
||||
// For Microsoft Visual use specific types as long long is not supported
|
||||
# if defined(_MSC_VER) // Microsoft Visual Studio
|
||||
typedef __int64 Int64;
|
||||
typedef unsigned __int64 UInt64;
|
||||
# else // if defined(_MSC_VER) // Other platforms, use long long
|
||||
typedef long long int Int64;
|
||||
typedef unsigned long long int UInt64;
|
||||
# endif // if defined(_MSC_VER)
|
||||
typedef Int64 LargestInt;
|
||||
typedef UInt64 LargestUInt;
|
||||
# define JSON_HAS_INT64
|
||||
# endif // if defined(JSON_NO_INT64)
|
||||
} // end namespace Json
|
||||
|
||||
|
||||
#endif // JSON_CONFIG_H_INCLUDED
|
49
dependencies/include/json/features.h
vendored
Normal file
49
dependencies/include/json/features.h
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
|
||||
# define CPPTL_JSON_FEATURES_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include "forwards.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
namespace Json {
|
||||
|
||||
/** \brief Configuration passed to reader and writer.
|
||||
* This configuration object can be used to force the Reader or Writer
|
||||
* to behave in a standard conforming way.
|
||||
*/
|
||||
class JSON_API Features
|
||||
{
|
||||
public:
|
||||
/** \brief A configuration that allows all features and assumes all strings are UTF-8.
|
||||
* - C & C++ comments are allowed
|
||||
* - Root object can be any JSON value
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features all();
|
||||
|
||||
/** \brief A configuration that is strictly compatible with the JSON specification.
|
||||
* - Comments are forbidden.
|
||||
* - Root object must be either an array or an object value.
|
||||
* - Assumes Value strings are encoded in UTF-8
|
||||
*/
|
||||
static Features strictMode();
|
||||
|
||||
/** \brief Initialize the configuration like JsonConfig::allFeatures;
|
||||
*/
|
||||
Features();
|
||||
|
||||
/// \c true if comments are allowed. Default: \c true.
|
||||
bool allowComments_;
|
||||
|
||||
/// \c true if root must be either an array or an object value. Default: \c false.
|
||||
bool strictRoot_;
|
||||
};
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // CPPTL_JSON_FEATURES_H_INCLUDED
|
44
dependencies/include/json/forwards.h
vendored
Normal file
44
dependencies/include/json/forwards.h
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_FORWARDS_H_INCLUDED
|
||||
# define JSON_FORWARDS_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include "config.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
|
||||
namespace Json {
|
||||
|
||||
// writer.h
|
||||
class FastWriter;
|
||||
class StyledWriter;
|
||||
|
||||
// reader.h
|
||||
class Reader;
|
||||
|
||||
// features.h
|
||||
class Features;
|
||||
|
||||
// value.h
|
||||
typedef unsigned int ArrayIndex;
|
||||
class StaticString;
|
||||
class Path;
|
||||
class PathArgument;
|
||||
class Value;
|
||||
class ValueIteratorBase;
|
||||
class ValueIterator;
|
||||
class ValueConstIterator;
|
||||
#ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
class ValueMapAllocator;
|
||||
class ValueInternalLink;
|
||||
class ValueInternalArray;
|
||||
class ValueInternalMap;
|
||||
#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
#endif // JSON_FORWARDS_H_INCLUDED
|
15
dependencies/include/json/json.h
vendored
Normal file
15
dependencies/include/json/json.h
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_JSON_H_INCLUDED
|
||||
# define JSON_JSON_H_INCLUDED
|
||||
|
||||
# include "autolink.h"
|
||||
# include "value.h"
|
||||
# include "reader.h"
|
||||
# include "writer.h"
|
||||
# include "features.h"
|
||||
|
||||
#endif // JSON_JSON_H_INCLUDED
|
214
dependencies/include/json/reader.h
vendored
Normal file
214
dependencies/include/json/reader.h
vendored
Normal file
@ -0,0 +1,214 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef CPPTL_JSON_READER_H_INCLUDED
|
||||
# define CPPTL_JSON_READER_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include "features.h"
|
||||
# include "value.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
# include <deque>
|
||||
# include <stack>
|
||||
# include <string>
|
||||
# include <iostream>
|
||||
|
||||
namespace Json {
|
||||
|
||||
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
|
||||
*
|
||||
*/
|
||||
class JSON_API Reader
|
||||
{
|
||||
public:
|
||||
typedef char Char;
|
||||
typedef const Char *Location;
|
||||
|
||||
/** \brief Constructs a Reader allowing all features
|
||||
* for parsing.
|
||||
*/
|
||||
Reader();
|
||||
|
||||
/** \brief Constructs a Reader allowing the specified feature set
|
||||
* for parsing.
|
||||
*/
|
||||
Reader( const Features &features );
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||
* \param document UTF-8 encoded string containing the document to read.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
*/
|
||||
bool parse( const std::string &document,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
|
||||
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
|
||||
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read.
|
||||
* \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read.
|
||||
\ Must be >= beginDoc.
|
||||
* \param root [out] Contains the root value of the document if it was
|
||||
* successfully parsed.
|
||||
* \param collectComments \c true to collect comment and allow writing them back during
|
||||
* serialization, \c false to discard comments.
|
||||
* This parameter is ignored if Features::allowComments_
|
||||
* is \c false.
|
||||
* \return \c true if the document was successfully parsed, \c false if an error occurred.
|
||||
*/
|
||||
bool parse( const char *beginDoc, const char *endDoc,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
|
||||
/// \brief Parse from input stream.
|
||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||
bool parse( std::istream &is,
|
||||
Value &root,
|
||||
bool collectComments = true );
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||
* \return Formatted error message with the list of errors with their location in
|
||||
* the parsed document. An empty string is returned if no error occurred
|
||||
* during parsing.
|
||||
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
|
||||
*/
|
||||
JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead")
|
||||
std::string getFormatedErrorMessages() const;
|
||||
|
||||
/** \brief Returns a user friendly string that list errors in the parsed document.
|
||||
* \return Formatted error message with the list of errors with their location in
|
||||
* the parsed document. An empty string is returned if no error occurred
|
||||
* during parsing.
|
||||
*/
|
||||
std::string getFormattedErrorMessages() const;
|
||||
|
||||
private:
|
||||
enum TokenType
|
||||
{
|
||||
tokenEndOfStream = 0,
|
||||
tokenObjectBegin,
|
||||
tokenObjectEnd,
|
||||
tokenArrayBegin,
|
||||
tokenArrayEnd,
|
||||
tokenString,
|
||||
tokenNumber,
|
||||
tokenTrue,
|
||||
tokenFalse,
|
||||
tokenNull,
|
||||
tokenArraySeparator,
|
||||
tokenMemberSeparator,
|
||||
tokenComment,
|
||||
tokenError
|
||||
};
|
||||
|
||||
class Token
|
||||
{
|
||||
public:
|
||||
TokenType type_;
|
||||
Location start_;
|
||||
Location end_;
|
||||
};
|
||||
|
||||
class ErrorInfo
|
||||
{
|
||||
public:
|
||||
Token token_;
|
||||
std::string message_;
|
||||
Location extra_;
|
||||
};
|
||||
|
||||
typedef std::deque<ErrorInfo> Errors;
|
||||
|
||||
bool expectToken( TokenType type, Token &token, const char *message );
|
||||
bool readToken( Token &token );
|
||||
void skipSpaces();
|
||||
bool match( Location pattern,
|
||||
int patternLength );
|
||||
bool readComment();
|
||||
bool readCStyleComment();
|
||||
bool readCppStyleComment();
|
||||
bool readString();
|
||||
void readNumber();
|
||||
bool readValue();
|
||||
bool readObject( Token &token );
|
||||
bool readArray( Token &token );
|
||||
bool decodeNumber( Token &token );
|
||||
bool decodeString( Token &token );
|
||||
bool decodeString( Token &token, std::string &decoded );
|
||||
bool decodeDouble( Token &token );
|
||||
bool decodeUnicodeCodePoint( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode );
|
||||
bool decodeUnicodeEscapeSequence( Token &token,
|
||||
Location ¤t,
|
||||
Location end,
|
||||
unsigned int &unicode );
|
||||
bool addError( const std::string &message,
|
||||
Token &token,
|
||||
Location extra = 0 );
|
||||
bool recoverFromError( TokenType skipUntilToken );
|
||||
bool addErrorAndRecover( const std::string &message,
|
||||
Token &token,
|
||||
TokenType skipUntilToken );
|
||||
void skipUntilSpace();
|
||||
Value ¤tValue();
|
||||
Char getNextChar();
|
||||
void getLocationLineAndColumn( Location location,
|
||||
int &line,
|
||||
int &column ) const;
|
||||
std::string getLocationLineAndColumn( Location location ) const;
|
||||
void addComment( Location begin,
|
||||
Location end,
|
||||
CommentPlacement placement );
|
||||
void skipCommentTokens( Token &token );
|
||||
|
||||
typedef std::stack<Value *> Nodes;
|
||||
Nodes nodes_;
|
||||
Errors errors_;
|
||||
std::string document_;
|
||||
Location begin_;
|
||||
Location end_;
|
||||
Location current_;
|
||||
Location lastValueEnd_;
|
||||
Value *lastValue_;
|
||||
std::string commentsBefore_;
|
||||
Features features_;
|
||||
bool collectComments_;
|
||||
};
|
||||
|
||||
/** \brief Read from 'sin' into 'root'.
|
||||
|
||||
Always keep comments from the input JSON.
|
||||
|
||||
This can be used to read a file into a particular sub-object.
|
||||
For example:
|
||||
\code
|
||||
Json::Value root;
|
||||
cin >> root["dir"]["file"];
|
||||
cout << root;
|
||||
\endcode
|
||||
Result:
|
||||
\verbatim
|
||||
{
|
||||
"dir": {
|
||||
"file": {
|
||||
// The input stream JSON would be nested here.
|
||||
}
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
\throw std::exception on parse error.
|
||||
\see Json::operator<<()
|
||||
*/
|
||||
std::istream& operator>>( std::istream&, Value& );
|
||||
|
||||
} // namespace Json
|
||||
|
||||
#endif // CPPTL_JSON_READER_H_INCLUDED
|
1103
dependencies/include/json/value.h
vendored
Normal file
1103
dependencies/include/json/value.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
185
dependencies/include/json/writer.h
vendored
Normal file
185
dependencies/include/json/writer.h
vendored
Normal file
@ -0,0 +1,185 @@
|
||||
// Copyright 2007-2010 Baptiste Lepilleur
|
||||
// Distributed under MIT license, or public domain if desired and
|
||||
// recognized in your jurisdiction.
|
||||
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
|
||||
|
||||
#ifndef JSON_WRITER_H_INCLUDED
|
||||
# define JSON_WRITER_H_INCLUDED
|
||||
|
||||
#if !defined(JSON_IS_AMALGAMATION)
|
||||
# include "value.h"
|
||||
#endif // if !defined(JSON_IS_AMALGAMATION)
|
||||
# include <vector>
|
||||
# include <string>
|
||||
# include <iostream>
|
||||
|
||||
namespace Json {
|
||||
|
||||
class Value;
|
||||
|
||||
/** \brief Abstract class for writers.
|
||||
*/
|
||||
class JSON_API Writer
|
||||
{
|
||||
public:
|
||||
virtual ~Writer();
|
||||
|
||||
virtual std::string write( const Value &root ) = 0;
|
||||
};
|
||||
|
||||
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
|
||||
*
|
||||
* The JSON document is written in a single line. It is not intended for 'human' consumption,
|
||||
* but may be usefull to support feature such as RPC where bandwith is limited.
|
||||
* \sa Reader, Value
|
||||
*/
|
||||
class JSON_API FastWriter : public Writer
|
||||
{
|
||||
public:
|
||||
FastWriter();
|
||||
virtual ~FastWriter(){}
|
||||
|
||||
void enableYAMLCompatibility();
|
||||
|
||||
public: // overridden from Writer
|
||||
virtual std::string write( const Value &root );
|
||||
|
||||
private:
|
||||
void writeValue( const Value &value );
|
||||
|
||||
std::string document_;
|
||||
bool yamlCompatiblityEnabled_;
|
||||
};
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value types,
|
||||
* and all the values fit on one lines, then print the array on a single line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||
*
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledWriter: public Writer
|
||||
{
|
||||
public:
|
||||
StyledWriter();
|
||||
virtual ~StyledWriter(){}
|
||||
|
||||
public: // overridden from Writer
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param root Value to serialize.
|
||||
* \return String containing the JSON document that represents the root value.
|
||||
*/
|
||||
virtual std::string write( const Value &root );
|
||||
|
||||
private:
|
||||
void writeValue( const Value &value );
|
||||
void writeArrayValue( const Value &value );
|
||||
bool isMultineArray( const Value &value );
|
||||
void pushValue( const std::string &value );
|
||||
void writeIndent();
|
||||
void writeWithIndent( const std::string &value );
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue( const Value &root );
|
||||
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||
bool hasCommentForValue( const Value &value );
|
||||
static std::string normalizeEOL( const std::string &text );
|
||||
|
||||
typedef std::vector<std::string> ChildValues;
|
||||
|
||||
ChildValues childValues_;
|
||||
std::string document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
int indentSize_;
|
||||
bool addChildValues_;
|
||||
};
|
||||
|
||||
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
|
||||
to a stream rather than to a string.
|
||||
*
|
||||
* The rules for line break and indent are as follow:
|
||||
* - Object value:
|
||||
* - if empty then print {} without indent and line break
|
||||
* - if not empty the print '{', line break & indent, print one value per line
|
||||
* and then unindent and line break and print '}'.
|
||||
* - Array value:
|
||||
* - if empty then print [] without indent and line break
|
||||
* - if the array contains no object value, empty array or some other value types,
|
||||
* and all the values fit on one lines, then print the array on a single line.
|
||||
* - otherwise, it the values do not fit on one line, or the array contains
|
||||
* object or non empty array, then print one value per line.
|
||||
*
|
||||
* If the Value have comments then they are outputed according to their #CommentPlacement.
|
||||
*
|
||||
* \param indentation Each level will be indented by this amount extra.
|
||||
* \sa Reader, Value, Value::setComment()
|
||||
*/
|
||||
class JSON_API StyledStreamWriter
|
||||
{
|
||||
public:
|
||||
StyledStreamWriter( std::string indentation="\t" );
|
||||
~StyledStreamWriter(){}
|
||||
|
||||
public:
|
||||
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
|
||||
* \param out Stream to write to. (Can be ostringstream, e.g.)
|
||||
* \param root Value to serialize.
|
||||
* \note There is no point in deriving from Writer, since write() should not return a value.
|
||||
*/
|
||||
void write( std::ostream &out, const Value &root );
|
||||
|
||||
private:
|
||||
void writeValue( const Value &value );
|
||||
void writeArrayValue( const Value &value );
|
||||
bool isMultineArray( const Value &value );
|
||||
void pushValue( const std::string &value );
|
||||
void writeIndent();
|
||||
void writeWithIndent( const std::string &value );
|
||||
void indent();
|
||||
void unindent();
|
||||
void writeCommentBeforeValue( const Value &root );
|
||||
void writeCommentAfterValueOnSameLine( const Value &root );
|
||||
bool hasCommentForValue( const Value &value );
|
||||
static std::string normalizeEOL( const std::string &text );
|
||||
|
||||
typedef std::vector<std::string> ChildValues;
|
||||
|
||||
ChildValues childValues_;
|
||||
std::ostream* document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_;
|
||||
std::string indentation_;
|
||||
bool addChildValues_;
|
||||
};
|
||||
|
||||
# if defined(JSON_HAS_INT64)
|
||||
std::string JSON_API valueToString( Int value );
|
||||
std::string JSON_API valueToString( UInt value );
|
||||
# endif // if defined(JSON_HAS_INT64)
|
||||
std::string JSON_API valueToString( LargestInt value );
|
||||
std::string JSON_API valueToString( LargestUInt value );
|
||||
std::string JSON_API valueToString( double value );
|
||||
std::string JSON_API valueToString( bool value );
|
||||
std::string JSON_API valueToQuotedString( const char *value );
|
||||
|
||||
/// \brief Output using the StyledStreamWriter.
|
||||
/// \see Json::operator>>()
|
||||
std::ostream& operator<<( std::ostream&, const Value &root );
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
|
||||
#endif // JSON_WRITER_H_INCLUDED
|
41
include/boblight-functions.h
Normal file
41
include/boblight-functions.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* boblight
|
||||
* Copyright (C) Bob 2009
|
||||
*
|
||||
* boblight is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* boblight is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//these definitions can be expanded to make normal prototypes, or functionpointers and dlsym lines
|
||||
|
||||
BOBLIGHT_FUNCTION(void*, boblight_init, ());
|
||||
BOBLIGHT_FUNCTION(void, boblight_destroy, (void* vpboblight));
|
||||
|
||||
BOBLIGHT_FUNCTION(int, boblight_connect, (void* vpboblight, const char* address, int port, int usectimeout));
|
||||
BOBLIGHT_FUNCTION(int, boblight_setpriority, (void* vpboblight, int priority));
|
||||
BOBLIGHT_FUNCTION(const char*, boblight_geterror, (void* vpboblight));
|
||||
BOBLIGHT_FUNCTION(int, boblight_getnrlights, (void* vpboblight));
|
||||
BOBLIGHT_FUNCTION(const char*, boblight_getlightname, (void* vpboblight, int lightnr));
|
||||
|
||||
BOBLIGHT_FUNCTION(int, boblight_getnroptions, (void* vpboblight));
|
||||
BOBLIGHT_FUNCTION(const char*, boblight_getoptiondescript,(void* vpboblight, int option));
|
||||
BOBLIGHT_FUNCTION(int, boblight_setoption, (void* vpboblight, int lightnr, const char* option));
|
||||
BOBLIGHT_FUNCTION(int, boblight_getoption, (void* vpboblight, int lightnr, const char* option, const char** output));
|
||||
|
||||
BOBLIGHT_FUNCTION(void, boblight_setscanrange, (void* vpboblight, int width, int height));
|
||||
|
||||
BOBLIGHT_FUNCTION(int, boblight_addpixel, (void* vpboblight, int lightnr, int* rgb));
|
||||
BOBLIGHT_FUNCTION(void, boblight_addpixelxy, (void* vpboblight, int x, int y, int* rgb));
|
||||
|
||||
BOBLIGHT_FUNCTION(int, boblight_sendrgb, (void* vpboblight, int sync, int* outputused));
|
||||
BOBLIGHT_FUNCTION(int, boblight_ping, (void* vpboblight, int* outputused));
|
103
include/boblight.h
Normal file
103
include/boblight.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* boblight
|
||||
* Copyright (C) Bob 2009
|
||||
*
|
||||
* boblight is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* boblight is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//if you define BOBLIGHT_DLOPEN, all boblight functions are defined as pointers
|
||||
//you can then call boblight_loadlibrary to load libboblight with dlopen and the function pointers with dlsym
|
||||
//if you pass NULL to boblight_loadlibrary's first argument, the default filename for libboblight is used
|
||||
//if boblight_loadlibrary returns NULL, dlopen and dlsym went ok, if not it returns a char* from dlerror
|
||||
|
||||
//if you want to use the boblight functions from multiple files, you can define BOBLIGHT_DLOPEN in one file,
|
||||
//and define BOBLIGHT_DLOPEN_EXTERN in the other file, the functionpointers are then defined as extern
|
||||
|
||||
#ifndef LIBBOBLIGHT
|
||||
#define LIBBOBLIGHT
|
||||
|
||||
#if !defined(BOBLIGHT_DLOPEN) && !defined(BOBLIGHT_DLOPEN_EXTERN)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//generate normal prototypes
|
||||
#define BOBLIGHT_FUNCTION(returnvalue, name, arguments) returnvalue name arguments
|
||||
#include "boblight-functions.h"
|
||||
#undef BOBLIGHT_FUNCTION
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(BOBLIGHT_DLOPEN)
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stddef.h>
|
||||
|
||||
//generate function pointers
|
||||
#define BOBLIGHT_FUNCTION(returnvalue, name, arguments) returnvalue (* name ) arguments = NULL
|
||||
#include "boblight-functions.h"
|
||||
#undef BOBLIGHT_FUNCTION
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define BOBLIGHT_CAST(value) reinterpret_cast<value>
|
||||
#else
|
||||
#define BOBLIGHT_CAST(value) (value)
|
||||
#endif
|
||||
|
||||
//gets a functionpointer from dlsym, and returns char* from dlerror if it didn't work
|
||||
#define BOBLIGHT_FUNCTION(returnvalue, name, arguments) \
|
||||
name = BOBLIGHT_CAST(returnvalue (*) arguments)(dlsym(p_boblight, #name)); \
|
||||
{ char* error = dlerror(); if (error) return error; }
|
||||
|
||||
void* p_boblight = NULL; //where we put the lib
|
||||
|
||||
//load function pointers
|
||||
char* boblight_loadlibrary(const char* filename)
|
||||
{
|
||||
if (filename == NULL)
|
||||
filename = "libboblight.so";
|
||||
|
||||
if (p_boblight != NULL)
|
||||
{
|
||||
dlclose(p_boblight);
|
||||
p_boblight = NULL;
|
||||
}
|
||||
|
||||
p_boblight = dlopen(filename, RTLD_NOW);
|
||||
if (p_boblight == NULL)
|
||||
return dlerror();
|
||||
|
||||
//generate dlsym lines
|
||||
#include "boblight-functions.h"
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#undef BOBLIGHT_FUNCTION
|
||||
#undef BOBLIGHT_CAST
|
||||
|
||||
//you can define BOBLIGHT_DLOPEN_EXTERN when you load the library in another file
|
||||
#elif defined(BOBLIGHT_DLOPEN_EXTERN)
|
||||
|
||||
extern char* boblight_loadlibrary(const char* filename);
|
||||
extern void* p_boblight;
|
||||
#define BOBLIGHT_FUNCTION(returnvalue, name, arguments) extern returnvalue (* name ) arguments
|
||||
#include "boblight-functions.h"
|
||||
#undef BOBLIGHT_FUNCTION
|
||||
|
||||
#endif //BOBLIGHT_DLOPEN_EXTERN
|
||||
#endif //LIBBOBLIGHT
|
||||
|
41
include/hyperion/Hyperion.h
Normal file
41
include/hyperion/Hyperion.h
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// hyperion-utils includes
|
||||
#include <utils/RgbImage.h>
|
||||
|
||||
#include <hyperion/LedString.h>
|
||||
#include <hyperion/ImageToLedsMap.h>
|
||||
#include <hyperion/LedDevice.h>
|
||||
|
||||
class Hyperion
|
||||
{
|
||||
public:
|
||||
Hyperion(const Json::Value& jsonConfig);
|
||||
|
||||
~Hyperion();
|
||||
|
||||
void setInputSize(const unsigned width, const unsigned height);
|
||||
|
||||
RgbImage& image()
|
||||
{
|
||||
return *mImage;
|
||||
}
|
||||
|
||||
void commit();
|
||||
|
||||
void operator() (const RgbImage& inputImage);
|
||||
|
||||
void setColor(const RgbColor& color);
|
||||
|
||||
private:
|
||||
void applyTransform(std::vector<RgbColor>& colors) const;
|
||||
|
||||
LedString mLedString;
|
||||
|
||||
RgbImage* mImage;
|
||||
|
||||
ImageToLedsMap mLedsMap;
|
||||
|
||||
LedDevice* mDevice;
|
||||
};
|
27
include/hyperion/ImageToLedsMap.h
Normal file
27
include/hyperion/ImageToLedsMap.h
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// hyperion-utils includes
|
||||
#include <utils/RgbImage.h>
|
||||
|
||||
// hyperion includes
|
||||
#include <hyperion/LedString.h>
|
||||
|
||||
class ImageToLedsMap
|
||||
{
|
||||
public:
|
||||
|
||||
ImageToLedsMap();
|
||||
|
||||
void createMapping(const RgbImage& image, const std::vector<Led>& leds);
|
||||
|
||||
std::vector<RgbColor> getMeanLedColor();
|
||||
|
||||
RgbColor findMeanColor(const std::vector<const RgbColor*>& colors);
|
||||
|
||||
std::vector<RgbColor> getMedianLedColor();
|
||||
|
||||
RgbColor findMedianColor(std::vector<const RgbColor*>& colors);
|
||||
private:
|
||||
std::vector<std::vector<const RgbColor*> > mColorsMap;
|
||||
};
|
27
include/hyperion/LedDevice.h
Normal file
27
include/hyperion/LedDevice.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
// STL incldues
|
||||
#include <vector>
|
||||
|
||||
// Utility includes
|
||||
#include <utils/RgbColor.h>
|
||||
|
||||
class LedDevice
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Empty virtual destructor for pure virtual base class
|
||||
*/
|
||||
virtual ~LedDevice()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the RGB-Color values to the leds.
|
||||
*
|
||||
* @param[in] ledValues The RGB-color per led
|
||||
*/
|
||||
virtual int write(const std::vector<RgbColor>& ledValues) = 0;
|
||||
};
|
72
include/hyperion/LedString.h
Normal file
72
include/hyperion/LedString.h
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// STL includes
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Local includes
|
||||
#include <utils/RgbColor.h>
|
||||
|
||||
// Forward class declarations
|
||||
namespace Json { class Value; }
|
||||
|
||||
/**
|
||||
* The Led structure contains the definition of the image portion used to determine a single led's
|
||||
* color.
|
||||
* <pre>
|
||||
* |--------------------image--|
|
||||
* | minX maxX |
|
||||
* | |-----|maxY |
|
||||
* | | | |
|
||||
* | |-----|minY |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* |---------------------------|
|
||||
* <endpre>
|
||||
*/
|
||||
struct Led
|
||||
{
|
||||
/** The index of the led */
|
||||
unsigned index;
|
||||
|
||||
/** The minimum vertical scan line included for this leds color */
|
||||
double minX_frac;
|
||||
/** The maximum vertical scan line included for this leds color */
|
||||
double maxX_frac;
|
||||
/** The minimum horizontal scan line included for this leds color */
|
||||
double minY_frac;
|
||||
/** The maximum horizontal scan line included for this leds color */
|
||||
double maxY_frac;
|
||||
};
|
||||
|
||||
class LedString
|
||||
{
|
||||
public:
|
||||
static LedString construct(const Json::Value& ledConfig, const Json::Value& colorConfig);
|
||||
|
||||
LedString();
|
||||
|
||||
~LedString();
|
||||
|
||||
const std::vector<Led>& leds() const;
|
||||
|
||||
private:
|
||||
std::vector<Led> mLeds;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Color adjustements per color
|
||||
*/
|
||||
struct
|
||||
{
|
||||
/** The color gradient */
|
||||
double gamma;
|
||||
/** The color offset */
|
||||
double adjust;
|
||||
/** The minimum required level for the led to turn on */
|
||||
double blacklevel;
|
||||
} red, green, blue;
|
||||
};
|
31
include/utils/RgbColor.h
Normal file
31
include/utils/RgbColor.h
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// STL includes
|
||||
#include <stdint.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// Forward class declaration
|
||||
struct RgbColor;
|
||||
|
||||
struct RgbColor
|
||||
{
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
|
||||
static RgbColor BLACK;
|
||||
static RgbColor RED;
|
||||
static RgbColor GREEN;
|
||||
static RgbColor BLUE;
|
||||
static RgbColor YELLOW;
|
||||
static RgbColor WHITE;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const RgbColor& color)
|
||||
{
|
||||
os << "{" << unsigned(color.red) << "," << unsigned(color.green) << "," << unsigned(color.blue) << "}";
|
||||
return os;
|
||||
}
|
||||
|
56
include/utils/RgbImage.h
Normal file
56
include/utils/RgbImage.h
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
// Local includes
|
||||
#include "RgbColor.h"
|
||||
|
||||
class RgbImage
|
||||
{
|
||||
public:
|
||||
|
||||
RgbImage(const unsigned width, const unsigned height, const RgbColor background = RgbColor::BLACK);
|
||||
|
||||
~RgbImage();
|
||||
|
||||
inline unsigned width() const
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
inline unsigned height() const
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
void setPixel(const unsigned x, const unsigned y, const RgbColor color);
|
||||
|
||||
const RgbColor& operator()(const unsigned x, const unsigned y) const;
|
||||
|
||||
RgbColor& operator()(const unsigned x, const unsigned y);
|
||||
|
||||
inline void copy(const RgbImage& other)
|
||||
{
|
||||
std::cout << "This image size: [" << width() << "x" << height() << "]. Other image size: [" << other.width() << "x" << other.height() << "]" << std::endl;
|
||||
assert(other.mWidth == mWidth);
|
||||
assert(other.mHeight == mHeight);
|
||||
|
||||
memcpy(mColors, other.mColors, mWidth*mHeight*sizeof(RgbColor));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline unsigned toIndex(const unsigned x, const unsigned y) const
|
||||
{
|
||||
return y*mWidth + x;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned mWidth;
|
||||
unsigned mHeight;
|
||||
|
||||
/** The colors of the image */
|
||||
RgbColor* mColors;
|
||||
};
|
66
include/utils/jsonschema/JsonFactory.h
Normal file
66
include/utils/jsonschema/JsonFactory.h
Normal file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
// JSON-Schema includes
|
||||
#include <utils/jsonschema/JsonSchemaChecker.h>
|
||||
|
||||
class JsonFactory
|
||||
{
|
||||
public:
|
||||
|
||||
static int load(const std::string& schema, const std::istream& config, Json::Value json);
|
||||
|
||||
static int load(const std::string& schema, const std::string& config, Json::Value& json)
|
||||
{
|
||||
// Load the schema and the config trees
|
||||
Json::Value schemaTree = readJson(schema);
|
||||
Json::Value configTree = readJson(config);
|
||||
|
||||
// create the validator
|
||||
JsonSchemaChecker schemaChecker;
|
||||
schemaChecker.setSchema(schemaTree);
|
||||
|
||||
bool valid = schemaChecker.validate(configTree);
|
||||
for (const std::string& message : schemaChecker.getMessages())
|
||||
{
|
||||
std::cout << message << std::endl;
|
||||
}
|
||||
if (!valid)
|
||||
{
|
||||
std::cerr << "Validation failed for configuration file: " << config.c_str() << std::endl;
|
||||
return -3;
|
||||
}
|
||||
|
||||
json = configTree;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Json::Value readJson(const std::string& filename)
|
||||
{
|
||||
// Open the file input stream
|
||||
std::ifstream ifs(filename.c_str());
|
||||
return readJson(ifs);
|
||||
}
|
||||
|
||||
static Json::Value readJson(std::istream& stream)
|
||||
{
|
||||
// will contains the root value after parsing.
|
||||
Json::Value jsonTree;
|
||||
|
||||
Json::Reader reader;
|
||||
if (! reader.parse(stream, jsonTree, false))
|
||||
{
|
||||
// report to the user the failure and their locations in the document.
|
||||
std::stringstream sstream;
|
||||
sstream << "Failed to parse configuration: " << reader.getFormattedErrorMessages().c_str();
|
||||
|
||||
throw std::runtime_error(sstream.str());
|
||||
}
|
||||
return jsonTree;
|
||||
}
|
||||
};
|
75
include/utils/jsonschema/JsonSchemaChecker.h
Normal file
75
include/utils/jsonschema/JsonSchemaChecker.h
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2012 TNO, The Netherlands.
|
||||
//
|
||||
// This file contains information proprietary to TNO.
|
||||
//
|
||||
// Any disclosure or use of this information or any reproduction of this document or any part thereof for
|
||||
// other than the specified purpose for which it is intended is expressly prohibited except as TNO may
|
||||
// otherwise agree to in writing.
|
||||
|
||||
#pragma once
|
||||
|
||||
// stl includes
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
// jsoncpp includes
|
||||
#include <json/json.h>
|
||||
|
||||
/**
|
||||
* JsonSchemaChecker is a very basic implementation of json schema.
|
||||
* The json schema definition draft can be found at
|
||||
* http://tools.ietf.org/html/draft-zyp-json-schema-03
|
||||
*
|
||||
* The following keywords are supported:
|
||||
* - type
|
||||
* - required
|
||||
* - properties
|
||||
* - items
|
||||
* - enum
|
||||
* - minimum
|
||||
* - maximum
|
||||
*/
|
||||
class JsonSchemaChecker
|
||||
{
|
||||
public:
|
||||
JsonSchemaChecker();
|
||||
virtual ~JsonSchemaChecker();
|
||||
|
||||
bool setSchema(const Json::Value & schema);
|
||||
|
||||
bool validate(const Json::Value & value);
|
||||
|
||||
const std::list<std::string> & getMessages() const;
|
||||
|
||||
private:
|
||||
void collectReferences(const Json::Value & schema);
|
||||
|
||||
void validate(const Json::Value &value, const Json::Value & schema);
|
||||
|
||||
void setMessage(const std::string & message);
|
||||
|
||||
void collectDependencies(const Json::Value & value, const Json::Value &schema);
|
||||
|
||||
private:
|
||||
// attribute check functions
|
||||
void checkType(const Json::Value & value, const Json::Value & schema);
|
||||
void checkProperties(const Json::Value & value, const Json::Value & schema);
|
||||
void checkAdditionalProperties(const Json::Value & value, const Json::Value & schema, const Json::Value::Members & ignoredProperties);
|
||||
void checkDependencies(const Json::Value & value, const Json::Value & schemaLink);
|
||||
void checkMinimum(const Json::Value & value, const Json::Value & schema);
|
||||
void checkMaximum(const Json::Value & value, const Json::Value & schema);
|
||||
void checkItems(const Json::Value & value, const Json::Value & schema);
|
||||
void checkMinItems(const Json::Value & value, const Json::Value & schema);
|
||||
void checkMaxItems(const Json::Value & value, const Json::Value & schema);
|
||||
void checkUniqueItems(const Json::Value & value, const Json::Value & schema);
|
||||
void checkEnum(const Json::Value & value, const Json::Value & schema);
|
||||
|
||||
private:
|
||||
Json::Value _schema;
|
||||
|
||||
std::list<std::string> _currentPath;
|
||||
std::list<std::string> _messages;
|
||||
bool _error;
|
||||
|
||||
std::map<std::string, const Json::Value *> _references; // ref 2 value
|
||||
};
|
15
libsrc/CMakeLists.txt
Normal file
15
libsrc/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
# Define the current source locations
|
||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include)
|
||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc)
|
||||
|
||||
add_library(bob2hyperion SHARED
|
||||
bob2hyperion.cpp)
|
||||
|
||||
target_link_libraries(bob2hyperion
|
||||
hyperion
|
||||
hyperion-utils)
|
||||
|
||||
add_subdirectory(hyperion)
|
||||
add_subdirectory(hyperionpng)
|
||||
add_subdirectory(utils)
|
138
libsrc/bob2hyperion.cpp
Normal file
138
libsrc/bob2hyperion.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
// SysLog includes
|
||||
#include <syslog.h>
|
||||
|
||||
// Boblight includes
|
||||
#include "boblight.h"
|
||||
|
||||
// JsonSchema includes
|
||||
#include <utils/jsonschema/JsonFactory.h>
|
||||
|
||||
// Raspilight includes
|
||||
#include <hyperion/Hyperion.h>
|
||||
|
||||
static std::ofstream sDebugStream;
|
||||
|
||||
inline Hyperion* rasp_cast(void* hyperion_ptr)
|
||||
{
|
||||
return reinterpret_cast<Hyperion*>(hyperion_ptr);
|
||||
}
|
||||
|
||||
void* boblight_init()
|
||||
{
|
||||
syslog(LOG_INFO, __PRETTY_FUNCTION__);
|
||||
|
||||
const char* homeDir = getenv("RASPILIGHT_HOME");
|
||||
if (!homeDir)
|
||||
{
|
||||
homeDir = "/etc";
|
||||
}
|
||||
syslog(LOG_INFO, "RASPILIGHT HOME DIR: %s", homeDir);
|
||||
|
||||
const std::string schemaFile = std::string(homeDir) + "/hyperion.schema.json";
|
||||
const std::string configFile = std::string(homeDir) + "/hyperion.config.json";
|
||||
|
||||
Json::Value raspiConfig;
|
||||
if (JsonFactory::load(schemaFile, configFile, raspiConfig) < 0)
|
||||
{
|
||||
syslog(LOG_WARNING, "UNABLE TO LOAD CONFIGURATION");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Hyperion* raspiLight = new Hyperion(raspiConfig);
|
||||
return reinterpret_cast<void*>(raspiLight);
|
||||
}
|
||||
|
||||
void boblight_destroy(void* hyperion_ptr)
|
||||
{
|
||||
syslog(LOG_INFO, __PRETTY_FUNCTION__);
|
||||
|
||||
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
||||
|
||||
// Switch all leds to black (off)
|
||||
raspiLight->setColor(RgbColor::BLACK);
|
||||
|
||||
delete raspiLight;
|
||||
|
||||
sDebugStream.close();
|
||||
}
|
||||
|
||||
void boblight_setscanrange(void* hyperion_ptr, int width, int height)
|
||||
{
|
||||
syslog(LOG_INFO, __PRETTY_FUNCTION__);
|
||||
syslog(LOG_INFO, "Configuring scan range [%dx%d]", width, height);
|
||||
|
||||
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
||||
raspiLight->setInputSize(width, height);
|
||||
}
|
||||
|
||||
void boblight_addpixelxy(void* hyperion_ptr, int x, int y, int* rgb)
|
||||
{
|
||||
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
||||
const RgbColor color = {uint8_t(rgb[0]), uint8_t(rgb[1]), uint8_t(rgb[2])};
|
||||
raspiLight->image().setPixel(x, y, color);
|
||||
}
|
||||
|
||||
int boblight_sendrgb(void* hyperion_ptr, int sync, int* outputused)
|
||||
{
|
||||
Hyperion* raspiLight = rasp_cast(hyperion_ptr);
|
||||
raspiLight->commit();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int boblight_connect(void* hyperion_ptr, const char* address, int port, int usectimeout)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* boblight_geterror(void* hyperion_ptr)
|
||||
{
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
int boblight_setpriority(void* hyperion_ptr, int priority)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int boblight_getnrlights(void* hyperion_ptr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* boblight_getlightname(void* hyperion_ptr, int lightnr)
|
||||
{
|
||||
return "LIGHT_NAME";
|
||||
}
|
||||
|
||||
int boblight_getnroptions(void* hyperion_ptr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* boblight_getoptiondescript(void* hyperion_ptr, int option)
|
||||
{
|
||||
return "OPTION-DESCRIPTION";
|
||||
}
|
||||
|
||||
int boblight_setoption(void* hyperion_ptr, int lightnr, const char* option)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int boblight_getoption(void* hyperion_ptr, int lightnr, const char* option, const char** output)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int boblight_addpixel(void* hyperion_ptr, int lightnr, int* rgb)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int boblight_ping(void* hyperion_ptr, int* outputused)
|
||||
{
|
||||
return 1;
|
||||
}
|
17
libsrc/hyperion/CMakeLists.txt
Normal file
17
libsrc/hyperion/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
# Define the current source locations
|
||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion)
|
||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion)
|
||||
|
||||
add_library(hyperion
|
||||
${CURRENT_HEADER_DIR}/Hyperion.h
|
||||
${CURRENT_HEADER_DIR}/LedDevice.h
|
||||
${CURRENT_HEADER_DIR}/LedString.h
|
||||
${CURRENT_HEADER_DIR}/ImageToLedsMap.h
|
||||
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
|
||||
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
|
||||
${CURRENT_SOURCE_DIR}/LedString.cpp
|
||||
${CURRENT_SOURCE_DIR}/Hyperion.cpp
|
||||
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
|
||||
)
|
101
libsrc/hyperion/Hyperion.cpp
Normal file
101
libsrc/hyperion/Hyperion.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
|
||||
// Syslog include
|
||||
#include <syslog.h>
|
||||
|
||||
// JsonSchema include
|
||||
#include <utils/jsonschema/JsonFactory.h>
|
||||
|
||||
// hyperion include
|
||||
#include <hyperion/Hyperion.h>
|
||||
#include <hyperion/LedDevice.h>
|
||||
|
||||
#include "LedDeviceWs2801.h"
|
||||
|
||||
LedDevice* constructDevice(const Json::Value& deviceConfig)
|
||||
{
|
||||
std::cout << "Device configuration: " << deviceConfig << std::endl;
|
||||
LedDevice* device = nullptr;
|
||||
if (deviceConfig["type"].asString() == "ws2801")
|
||||
{
|
||||
const std::string name = "WS-2801";
|
||||
const std::string output = deviceConfig["output"].asString();
|
||||
const unsigned interval = deviceConfig["interval"].asInt();
|
||||
const unsigned rate = deviceConfig["rate"].asInt();
|
||||
|
||||
LedDeviceWs2801* deviceWs2801 = new LedDeviceWs2801(name, output, interval, rate);
|
||||
deviceWs2801->open();
|
||||
|
||||
device = deviceWs2801;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown / Unimplemented device
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
Hyperion::Hyperion(const Json::Value &jsonConfig) :
|
||||
mLedString(LedString::construct(jsonConfig["leds"], jsonConfig["color"])),
|
||||
mImage(nullptr),
|
||||
mDevice(constructDevice(jsonConfig["device"]))
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
Hyperion::~Hyperion()
|
||||
{
|
||||
// Delete the existing image (or delete nullptr)
|
||||
delete mImage;
|
||||
|
||||
// Delete the Led-String
|
||||
delete mDevice;
|
||||
}
|
||||
|
||||
void Hyperion::setInputSize(const unsigned width, const unsigned height)
|
||||
{
|
||||
// Delete the existing image (or delete nullptr)
|
||||
delete mImage;
|
||||
|
||||
// Create the new image with the mapping to the leds
|
||||
mImage = new RgbImage(width, height);
|
||||
mLedsMap.createMapping(*mImage, mLedString.leds());
|
||||
}
|
||||
|
||||
void Hyperion::commit()
|
||||
{
|
||||
// Derive the color per led
|
||||
const std::vector<RgbColor> ledColors = mLedsMap.getMedianLedColor();
|
||||
// Write the Led colors to the led-string
|
||||
mDevice->write(ledColors);
|
||||
}
|
||||
|
||||
void Hyperion::operator() (const RgbImage& inputImage)
|
||||
{
|
||||
std::cout << "Cached image size: [" << mImage->width() << "x" << mImage->height() << "]. Input image size: [" << inputImage.width() << "x" << inputImage.height() << "]" << std::endl;
|
||||
// Copy the input-image into the buffer
|
||||
mImage->copy(inputImage);
|
||||
|
||||
// Derive the color per led
|
||||
// std::vector<RgbColor> ledColors = mLedsMap.getMeanLedColor();
|
||||
std::vector<RgbColor> ledColors = mLedsMap.getMedianLedColor();
|
||||
applyTransform(ledColors);
|
||||
|
||||
// Write the Led colors to the led-string
|
||||
mDevice->write(ledColors);
|
||||
}
|
||||
|
||||
void Hyperion::setColor(const RgbColor& color)
|
||||
{
|
||||
mDevice->write(std::vector<RgbColor>(mLedString.leds().size(), color));
|
||||
}
|
||||
|
||||
void Hyperion::applyTransform(std::vector<RgbColor>& colors) const
|
||||
{
|
||||
for (RgbColor& color : colors)
|
||||
{
|
||||
color.red = (color.red < mLedString.red.blacklevel)? 0 : mLedString.red.adjust + mLedString.red.gamma * color.red;
|
||||
color.green = (color.green < mLedString.green.blacklevel)? 0 : mLedString.green.adjust + mLedString.green.gamma * color.green;
|
||||
color.blue = (color.blue < mLedString.blue.blacklevel)? 0 : mLedString.blue.adjust + mLedString.blue.gamma * color.blue;
|
||||
}
|
||||
}
|
90
libsrc/hyperion/ImageToLedsMap.cpp
Normal file
90
libsrc/hyperion/ImageToLedsMap.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
|
||||
// STL includes
|
||||
#include <algorithm>
|
||||
|
||||
// hyperion includes
|
||||
#include <hyperion/ImageToLedsMap.h>
|
||||
|
||||
ImageToLedsMap::ImageToLedsMap()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
void ImageToLedsMap::createMapping(const RgbImage& image, const std::vector<Led>& leds)
|
||||
{
|
||||
mColorsMap.resize(leds.size(), std::vector<const RgbColor*>());
|
||||
|
||||
auto ledColors = mColorsMap.begin();
|
||||
for (auto led = leds.begin(); ledColors != mColorsMap.end() && led != leds.end(); ++ledColors, ++led)
|
||||
{
|
||||
ledColors->clear();
|
||||
|
||||
const unsigned minX_idx = unsigned(image.width() * led->minX_frac);
|
||||
const unsigned maxX_idx = unsigned(image.width() * led->maxX_frac);
|
||||
const unsigned minY_idx = unsigned(image.height() * led->minY_frac);
|
||||
const unsigned maxY_idx = unsigned(image.height() * led->maxY_frac);
|
||||
|
||||
for (unsigned y = minY_idx; y<=maxY_idx && y<image.height(); ++y)
|
||||
{
|
||||
for (unsigned x = minX_idx; x<=maxX_idx && x<image.width(); ++x)
|
||||
{
|
||||
ledColors->push_back(&image(x,y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<RgbColor> ImageToLedsMap::getMeanLedColor()
|
||||
{
|
||||
std::vector<RgbColor> colors;
|
||||
for (auto ledColors = mColorsMap.begin(); ledColors != mColorsMap.end(); ++ledColors)
|
||||
{
|
||||
const RgbColor color = findMeanColor(*ledColors);
|
||||
colors.push_back(color);
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
RgbColor ImageToLedsMap::findMeanColor(const std::vector<const RgbColor*>& colors)
|
||||
{
|
||||
uint_fast16_t cummRed = 0;
|
||||
uint_fast16_t cummGreen = 0;
|
||||
uint_fast16_t cummBlue = 0;
|
||||
for (const RgbColor* color : colors)
|
||||
{
|
||||
cummRed += color->red;
|
||||
cummGreen += color->green;
|
||||
cummBlue += color->blue;
|
||||
}
|
||||
|
||||
const uint8_t avgRed = uint8_t(cummRed/colors.size());
|
||||
const uint8_t avgGreen = uint8_t(cummGreen/colors.size());
|
||||
const uint8_t avgBlue = uint8_t(cummBlue/colors.size());
|
||||
|
||||
return {avgRed, avgGreen, avgBlue};
|
||||
}
|
||||
|
||||
std::vector<RgbColor> ImageToLedsMap::getMedianLedColor()
|
||||
{
|
||||
std::vector<RgbColor> ledColors;
|
||||
for (std::vector<const RgbColor*>& colors : mColorsMap)
|
||||
{
|
||||
const RgbColor color = findMedianColor(colors);
|
||||
ledColors.push_back(color);
|
||||
}
|
||||
|
||||
return ledColors;
|
||||
}
|
||||
|
||||
RgbColor ImageToLedsMap::findMedianColor(std::vector<const RgbColor*>& colors)
|
||||
{
|
||||
std::sort(colors.begin(), colors.end(), [](const RgbColor* lhs, const RgbColor* rhs){ return lhs->red < rhs->red; });
|
||||
const uint8_t red = colors.at(colors.size()/2)->red;
|
||||
std::sort(colors.begin(), colors.end(), [](const RgbColor* lhs, const RgbColor* rhs){ return lhs->green < rhs->green; });
|
||||
const uint8_t green = colors.at(colors.size()/2)->green;
|
||||
std::sort(colors.begin(), colors.end(), [](const RgbColor* lhs, const RgbColor* rhs){ return lhs->blue < rhs->blue; });
|
||||
const uint8_t blue = colors.at(colors.size()/2)->blue;
|
||||
|
||||
return {red, green, blue};
|
||||
}
|
85
libsrc/hyperion/LedDeviceWs2801.cpp
Normal file
85
libsrc/hyperion/LedDeviceWs2801.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
|
||||
// STL includes
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
// Linux includes
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
// hyperion local includes
|
||||
#include "LedDeviceWs2801.h"
|
||||
|
||||
LedDeviceWs2801::LedDeviceWs2801(const std::string& name,
|
||||
const std::string& outputDevice,
|
||||
const unsigned interval,
|
||||
const unsigned baudrate) :
|
||||
mDeviceName(outputDevice),
|
||||
mBaudRate_Hz(baudrate),
|
||||
mFid(-1)
|
||||
{
|
||||
memset(&spi, 0, sizeof(spi));
|
||||
|
||||
latchTime.tv_sec = 0;
|
||||
latchTime.tv_nsec = 500000;
|
||||
|
||||
}
|
||||
|
||||
LedDeviceWs2801::~LedDeviceWs2801()
|
||||
{
|
||||
// close(mFid);
|
||||
}
|
||||
|
||||
int LedDeviceWs2801::open()
|
||||
{
|
||||
const int bitsPerWord = 8;
|
||||
|
||||
mFid = ::open(mDeviceName.c_str(), O_RDWR);
|
||||
|
||||
if (mFid < 0)
|
||||
{
|
||||
std::cerr << "Failed to open device('" << mDeviceName << "') " << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mode = SPI_MODE_0;
|
||||
if (ioctl(mFid, SPI_IOC_WR_MODE, &mode) == -1 || ioctl(mFid, SPI_IOC_RD_MODE, &mode) == -1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (ioctl(mFid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(mFid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (ioctl(mFid, SPI_IOC_WR_MAX_SPEED_HZ, &mBaudRate_Hz) == -1 || ioctl(mFid, SPI_IOC_RD_MAX_SPEED_HZ, &mBaudRate_Hz) == -1)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LedDeviceWs2801::write(const std::vector<RgbColor> &ledValues)
|
||||
{
|
||||
if (mFid < 0)
|
||||
{
|
||||
std::cerr << "Can not write to device which is open." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
spi.tx_buf = (__u64)ledValues.data();
|
||||
spi.len = ledValues.size() * sizeof(RgbColor);
|
||||
|
||||
int retVal = ioctl(mFid, SPI_IOC_MESSAGE(1), &spi);
|
||||
|
||||
if (retVal == 0)
|
||||
{
|
||||
// Sleep to latch the leds (only if write succesfull)
|
||||
nanosleep(&latchTime, NULL);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
33
libsrc/hyperion/LedDeviceWs2801.h
Normal file
33
libsrc/hyperion/LedDeviceWs2801.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
// STL includes
|
||||
#include <string>
|
||||
|
||||
// Linux-SPI includes
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
// hyperion incluse
|
||||
#include <hyperion/LedDevice.h>
|
||||
|
||||
class LedDeviceWs2801 : public LedDevice
|
||||
{
|
||||
public:
|
||||
LedDeviceWs2801(const std::string& name,
|
||||
const std::string& outputDevice,
|
||||
const unsigned interval,
|
||||
const unsigned baudrate);
|
||||
|
||||
virtual ~LedDeviceWs2801();
|
||||
|
||||
int open();
|
||||
|
||||
virtual int write(const std::vector<RgbColor> &ledValues);
|
||||
|
||||
private:
|
||||
const std::string mDeviceName;
|
||||
const int mBaudRate_Hz;
|
||||
|
||||
int mFid;
|
||||
spi_ioc_transfer spi;
|
||||
timespec latchTime;
|
||||
};
|
60
libsrc/hyperion/LedString.cpp
Normal file
60
libsrc/hyperion/LedString.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
// STL includes
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
// Json includes
|
||||
#include <json/json.h>
|
||||
|
||||
// hyperion includes
|
||||
#include <hyperion/LedString.h>
|
||||
|
||||
LedString LedString::construct(const Json::Value& ledsConfig, const Json::Value& colorConfig)
|
||||
{
|
||||
LedString ledString;
|
||||
|
||||
const Json::Value& redConfig = colorConfig["red"];
|
||||
const Json::Value& greenConfig = colorConfig["greem"];
|
||||
const Json::Value& blueConfig = colorConfig["blue"];
|
||||
|
||||
ledString.red.gamma = redConfig["gamma"].asDouble();
|
||||
ledString.red.adjust = redConfig["adjust"].asDouble();
|
||||
ledString.red.blacklevel = redConfig["blacklevel"].asDouble();
|
||||
|
||||
ledString.green.gamma = greenConfig["gamma"].asDouble();
|
||||
ledString.green.adjust = colorConfig["adjust"].asDouble();
|
||||
ledString.green.blacklevel = colorConfig["blacklevel"].asDouble();
|
||||
|
||||
ledString.blue.gamma = blueConfig["gamma"].asDouble();
|
||||
ledString.blue.adjust = blueConfig["adjust"].asDouble();
|
||||
ledString.blue.blacklevel = blueConfig["blacklevel"].asDouble();
|
||||
|
||||
for (const Json::Value& ledConfig : ledsConfig)
|
||||
{
|
||||
Led led;
|
||||
led.index = ledConfig["index"].asInt();
|
||||
const Json::Value& hscanConfig = ledConfig["hscan"];
|
||||
const Json::Value& vscanConfig = ledConfig["vscan"];
|
||||
led.minX_frac = std::max(0.0, std::min(100.0, hscanConfig["minimum"].asDouble()))/100.0;
|
||||
led.maxX_frac = std::max(0.0, std::min(100.0, hscanConfig["maximum"].asDouble()))/100.0;
|
||||
led.minY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["maximum"].asDouble()))/100.0;
|
||||
led.maxY_frac = 1.0 - std::max(0.0, std::min(100.0, vscanConfig["minimum"].asDouble()))/100.0;
|
||||
|
||||
ledString.mLeds.push_back(led);
|
||||
}
|
||||
return ledString;
|
||||
}
|
||||
|
||||
LedString::LedString()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
LedString::~LedString()
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<Led>& LedString::leds() const
|
||||
{
|
||||
return mLeds;
|
||||
}
|
19
libsrc/hyperionpng/CMakeLists.txt
Normal file
19
libsrc/hyperionpng/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
# Find the libPNG
|
||||
find_package(PNG REQUIRED QUIET)
|
||||
|
||||
# Add additional includes dirs
|
||||
include_directories(${PNG_INCLUDE_DIR})
|
||||
|
||||
# Define the current source locations
|
||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperionpng)
|
||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperionpng)
|
||||
|
||||
# Create the 'rasplight-png' library
|
||||
add_library(hyperion-png SHARED
|
||||
${CURRENT_SOURCE_DIR}/hyperion-png.cpp
|
||||
${CURRENT_SOURCE_DIR}/pngwriter.h
|
||||
${CURRENT_SOURCE_DIR}/pngwriter.cc)
|
||||
|
||||
target_link_libraries(hyperion-png
|
||||
${PNG_LIBRARIES})
|
174
libsrc/hyperionpng/hyperion-png.cpp
Normal file
174
libsrc/hyperionpng/hyperion-png.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
|
||||
// STL includes
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
// Boblight includes
|
||||
#include <boblight.h>
|
||||
|
||||
// PNGWriter includes
|
||||
#define NO_FREETYPE
|
||||
#include "pngwriter.h"
|
||||
|
||||
struct RaspiPng
|
||||
{
|
||||
pngwriter writer;
|
||||
unsigned long fileIndex;
|
||||
|
||||
unsigned frameCnt;
|
||||
|
||||
std::ofstream logFile;
|
||||
};
|
||||
|
||||
void* boblight_init()
|
||||
{
|
||||
RaspiPng* raspiPng = new RaspiPng();
|
||||
|
||||
raspiPng->writer.pngwriter_rename("/home/pi/RASPI_0000.png");
|
||||
raspiPng->fileIndex = 0;
|
||||
raspiPng->frameCnt = 0;
|
||||
raspiPng->logFile.open("/home/pi/raspipng.log");
|
||||
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return reinterpret_cast<void*>(raspiPng);
|
||||
}
|
||||
|
||||
void boblight_destroy(void* vpboblight)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
raspiPng->logFile.close();
|
||||
delete raspiPng;
|
||||
}
|
||||
|
||||
void boblight_setscanrange(void* vpboblight, int width, int height)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << "(" << width << ", " << height << ")" << std::endl;
|
||||
|
||||
raspiPng->writer.resize(width, height);
|
||||
}
|
||||
|
||||
void boblight_addpixelxy(void* vpboblight, int x, int y, int* rgb)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
|
||||
if (raspiPng->frameCnt%50 == 0)
|
||||
{
|
||||
// NB libpngwriter uses a one-based indexing scheme
|
||||
raspiPng->writer.plot(x+1,y+1, rgb[0]/255.0, rgb[1]/255.0, rgb[2]/255.0);
|
||||
}
|
||||
}
|
||||
|
||||
int boblight_sendrgb(void* vpboblight, int sync, int* outputused)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << "(" << sync << ", outputused) FRAME " << raspiPng->frameCnt++ << std::endl;
|
||||
|
||||
if (raspiPng->frameCnt%50 == 0)
|
||||
{
|
||||
// Write-out the current frame and prepare for the next
|
||||
raspiPng->writer.write_png();
|
||||
|
||||
++raspiPng->fileIndex;
|
||||
char filename[64];
|
||||
|
||||
sprintf(filename, "/home/pi/RASPI_%04ld.png", raspiPng->fileIndex);
|
||||
|
||||
raspiPng->writer.pngwriter_rename(filename);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int boblight_connect(void* vpboblight, const char* address, int port, int usectimeout)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int boblight_setpriority(void* vpboblight, int priority)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* boblight_geterror(void* vpboblight)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
int boblight_getnrlights(void* vpboblight)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return 50;
|
||||
}
|
||||
|
||||
const char* boblight_getlightname(void* vpboblight, int lightnr)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return "LIGHT";
|
||||
}
|
||||
|
||||
int boblight_getnroptions(void* vpboblight)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* boblight_getoptiondescript(void* vpboblight, int option)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
int boblight_setoption(void* vpboblight, int lightnr, const char* option)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int boblight_getoption(void* vpboblight, int lightnr, const char* option, const char** output)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int boblight_addpixel(void* vpboblight, int lightnr, int* rgb)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int boblight_ping(void* vpboblight, int* outputused)
|
||||
{
|
||||
RaspiPng* raspiPng = reinterpret_cast<RaspiPng*>(vpboblight);
|
||||
raspiPng->logFile << __PRETTY_FUNCTION__ << std::endl;
|
||||
|
||||
return 1;
|
||||
}
|
4722
libsrc/hyperionpng/pngwriter.cc
Normal file
4722
libsrc/hyperionpng/pngwriter.cc
Normal file
File diff suppressed because it is too large
Load Diff
745
libsrc/hyperionpng/pngwriter.h
Normal file
745
libsrc/hyperionpng/pngwriter.h
Normal file
@ -0,0 +1,745 @@
|
||||
//********** pngwriter.h **********************************************
|
||||
// Author: Paul Blackburn
|
||||
//
|
||||
// Email: individual61@users.sourceforge.net
|
||||
//
|
||||
// Version: 0.5.4 (19 / II / 2009)
|
||||
//
|
||||
// Description: Library that allows plotting a 48 bit
|
||||
// PNG image pixel by pixel, which can
|
||||
// then be opened with a graphics program.
|
||||
//
|
||||
// License: GNU General Public License
|
||||
// Copyright 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
// 2008, 2009 Paul Blackburn
|
||||
//
|
||||
// Website: Main: http://pngwriter.sourceforge.net/
|
||||
// Sourceforge.net: http://sourceforge.net/projects/pngwriter/
|
||||
// Freshmeat.net: http://freshmeat.net/projects/pngwriter/
|
||||
//
|
||||
// Documentation: This header file is commented, but for a
|
||||
// quick reference document, and support,
|
||||
// take a look at the website.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* */
|
||||
|
||||
#ifndef PNGWRITER_H
|
||||
#define PNGWRITER_H 1
|
||||
|
||||
#define PNGWRITER_VERSION 0.54
|
||||
|
||||
#include <png.h>
|
||||
|
||||
// REMEMBER TO ADD -DNO_FREETYPE TO YOUR COMPILATION FLAGS IF PNGwriter WAS
|
||||
// COMPILED WITHOUT FREETYPE SUPPORT!!!
|
||||
//
|
||||
// RECUERDA AGREGAR -DNO_FREETYPE A TUS OPCIONES DE COMPILACION SI PNGwriter
|
||||
// FUE COMPILADO SIN SOPORTE PARA FREETYPE!!!
|
||||
//
|
||||
#ifndef NO_FREETYPE
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef OLD_CPP // For compatibility with older compilers.
|
||||
#include <iostream.h>
|
||||
#include <math.h>
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
using namespace std;
|
||||
#endif // from ifdef OLD_CPP
|
||||
|
||||
#ifndef OLD_CPP // Default situation.
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <cwchar>
|
||||
#include <string>
|
||||
#endif // from ifndef OLD_CPP
|
||||
|
||||
|
||||
//png.h must be included before FreeType headers.
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#define PNG_BYTES_TO_CHECK (4)
|
||||
#define PNGWRITER_DEFAULT_COMPRESSION (6)
|
||||
|
||||
class pngwriter
|
||||
{
|
||||
private:
|
||||
|
||||
char * filename_;
|
||||
char * textauthor_;
|
||||
char * textdescription_;
|
||||
char * texttitle_;
|
||||
char * textsoftware_;
|
||||
|
||||
|
||||
|
||||
int height_;
|
||||
int width_;
|
||||
int backgroundcolour_;
|
||||
int bit_depth_;
|
||||
int rowbytes_;
|
||||
int colortype_;
|
||||
int compressionlevel_;
|
||||
bool transformation_; // Required by Mikkel's patch
|
||||
|
||||
unsigned char * * graph_;
|
||||
double filegamma_;
|
||||
double screengamma_;
|
||||
void circle_aux(int xcentre, int ycentre, int x, int y, int red, int green, int blue);
|
||||
void circle_aux_blend(int xcentre, int ycentre, int x, int y, double opacity, int red, int green, int blue);
|
||||
int check_if_png(char *file_name, FILE **fp);
|
||||
int read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr);
|
||||
int read_png_image(FILE *fp, png_structp png_ptr, png_infop info_ptr,
|
||||
png_bytepp *image, png_uint_32 *width, png_uint_32 *height);
|
||||
void flood_fill_internal( int xstart, int ystart, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue);
|
||||
void flood_fill_internal_blend( int xstart, int ystart, double opacity, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue);
|
||||
|
||||
#ifndef NO_FREETYPE
|
||||
void my_draw_bitmap( FT_Bitmap * bitmap, int x, int y, double red, double green, double blue);
|
||||
void my_draw_bitmap_blend( FT_Bitmap * bitmap, int x, int y,double opacity, double red, double green, double blue);
|
||||
#endif
|
||||
|
||||
/* The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/
|
||||
* which is a page that belongs to Nan C. Schaller, though
|
||||
* these algorithms appear to be the work of Eugene Vishnevsky.
|
||||
* */
|
||||
void HSVtoRGB( double *r, double *g, double *b, double h, double s, double v );
|
||||
void RGBtoHSV( float r, float g, float b, float *h, float *s, float *v );
|
||||
|
||||
/* drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun
|
||||
* ( <gurkan@linuks.mine.nu>, http://www.linuks.mine.nu/ )
|
||||
* */
|
||||
void drawtop(long x1,long y1,long x2,long y2,long x3, int red, int green, int blue);
|
||||
void drawbottom(long x1,long y1,long x2,long x3,long y3, int red, int green, int blue);
|
||||
void drawbottom_blend(long x1,long y1,long x2,long x3,long y3, double opacity, int red, int green, int blue);
|
||||
void drawtop_blend(long x1,long y1,long x2,long y2,long x3, double opacity, int red, int green, int blue);
|
||||
|
||||
public:
|
||||
|
||||
/* General Notes
|
||||
* It is important to remember that all functions that accept an argument of type "const char *" will also
|
||||
* accept "char *", this is done so you can have a changing filename (to make many PNG images in series
|
||||
* with a different name, for example), and to allow you to use string type objects which can be easily
|
||||
* turned into const char * (if theString is an object of type string, then it can be used as a const char *
|
||||
* by saying theString.c_str()).
|
||||
* It is also important to remember that whenever a function has a colour coeffiecient as its argument,
|
||||
* that argument can be either an int from 0 to 65535 or a double from 0.0 to 1.0.
|
||||
* It is important to make sure that you are calling the function with the type that you want.
|
||||
* Remember that 1 is an int, while 1.0 is a double, and will thus determine what version of the function
|
||||
* will be used. Similarly, do not make the mistake of calling for example plot(x, y, 0.0, 0.0, 65535),
|
||||
* because
|
||||
* there is no plot(int, int, double, double, int).
|
||||
* Also, please note that plot() and read() (and the functions that use them internally)
|
||||
* are protected against entering, for example, a colour coefficient that is over 65535
|
||||
* or over 1.0. Similarly, they are protected against negative coefficients. read() will return 0
|
||||
* when called outside the image range. This is actually useful as zero-padding should you need it.
|
||||
* */
|
||||
|
||||
/* Compilation
|
||||
* A typical compilation would look like this:
|
||||
*
|
||||
* g++ my_program.cc -o my_program freetype-config --cflags \
|
||||
* -I/usr/local/include -L/usr/local/lib -lpng -lpngwriter -lz -lfreetype
|
||||
*
|
||||
* If you did not compile PNGwriter with FreeType support, then remove the
|
||||
* FreeType-related flags and add -DNO_FREETYPE above.
|
||||
* */
|
||||
|
||||
/* Constructor
|
||||
* The constructor requires the width and the height of the image, the background colour for the
|
||||
* image and the filename of the file (a pointer or simple "myfile.png"). The background colour
|
||||
* can only be initialized to a shade of grey (once the object has been created you can do whatever
|
||||
* you want, though), because generally one wants either a white (65535 or 1.0) or a black (0 or 0.0)
|
||||
* background to start with.
|
||||
* The default constructor creates a PNGwriter instance that is 250x250, white background,
|
||||
* and filename "out.png".
|
||||
* Tip: The filename can be given as easily as:
|
||||
* pngwriter mypng(300, 300, 0.0, "myfile.png");
|
||||
* Tip: If you are going to create a PNGwriter instance for reading in a file that already exists,
|
||||
* then width and height can be 1 pixel, and the size will be automatically adjusted once you use
|
||||
* readfromfile().
|
||||
* */
|
||||
pngwriter();
|
||||
pngwriter(const pngwriter &rhs);
|
||||
pngwriter(int width, int height, int backgroundcolour, char * filename);
|
||||
pngwriter(int width, int height, double backgroundcolour, char * filename);
|
||||
pngwriter(int width, int height, int backgroundcolour, const char * filename);
|
||||
pngwriter(int width, int height, double backgroundcolour, const char * filename);
|
||||
|
||||
/* Destructor
|
||||
* */
|
||||
~pngwriter();
|
||||
|
||||
/* Assignment Operator
|
||||
* */
|
||||
pngwriter & operator = (const pngwriter & rhs);
|
||||
|
||||
/* Plot
|
||||
* With this function a pixel at coordinates (x, y) can be set to the desired colour.
|
||||
* The pixels are numbered starting from (1, 1) and go to (width, height).
|
||||
* As with most functions in PNGwriter, it has been overloaded to accept either int arguments
|
||||
* for the colour coefficients, or those of type double. If they are of type int,
|
||||
* they go from 0 to 65535. If they are of type double, they go from 0.0 to 1.0.
|
||||
* Tip: To plot using red, then specify plot(x, y, 1.0, 0.0, 0.0). To make pink,
|
||||
* just add a constant value to all three coefficients, like this:
|
||||
* plot(x, y, 1.0, 0.4, 0.4).
|
||||
* Tip: If nothing is being plotted to your PNG file, make sure that you remember
|
||||
* to close() the instance before your program is finished, and that the x and y position
|
||||
* is actually within the bounds of your image. If either is not, then PNGwriter will
|
||||
* not complain-- it is up to you to check for this!
|
||||
* Tip: If you try to plot with a colour coefficient out of range, a maximum or minimum
|
||||
* coefficient will be assumed, according to the given coefficient. For example, attempting
|
||||
* to plot plot(x, y, 1.0,-0.2,3.7) will set the green coefficient to 0 and the red coefficient
|
||||
* to 1.0.
|
||||
* */
|
||||
void plot(int x, int y, int red, int green, int blue);
|
||||
void plot(int x, int y, double red, double green, double blue);
|
||||
|
||||
/* Plot HSV
|
||||
* With this function a pixel at coordinates (x, y) can be set to the desired colour,
|
||||
* but with the colour coefficients given in the Hue, Saturation, Value colourspace.
|
||||
* This has the advantage that one can determine the colour that will be plotted with
|
||||
* only one parameter, the Hue. The colour coefficients must go from 0 to 65535 and
|
||||
* be of type int, or be of type double and go from 0.0 to 1.0.
|
||||
* */
|
||||
void plotHSV(int x, int y, double hue, double saturation, double value);
|
||||
void plotHSV(int x, int y, int hue, int saturation, int value);
|
||||
|
||||
/* Read
|
||||
* With this function we find out what colour the pixel (x, y) is. If "colour" is 1,
|
||||
* it will return the red coefficient, if it is set to 2, the green one, and if
|
||||
* it set to 3, the blue colour coefficient will be returned,
|
||||
* and this returned value will be of type int and be between 0 and 65535.
|
||||
* Note that if you call read() on a pixel outside the image range, the value returned
|
||||
* will be 0.
|
||||
* */
|
||||
int read(int x, int y, int colour);
|
||||
|
||||
/* Read, Average
|
||||
* Same as the above, only that the average of the three colour coefficients is returned.
|
||||
*/
|
||||
int read(int x, int y);
|
||||
|
||||
/* dRead
|
||||
* With this function we find out what colour the pixel (x, y) is. If "colour" is 1,
|
||||
* it will return the red coefficient, if it is set to 2, the green one, and if
|
||||
* it set to 3, the blue colour coefficient will be returned,
|
||||
* and this returned value will be of type double and be between 0.0 and 1.0.
|
||||
* Note that if you call dread() outside the image range, the value returned will be 0.0
|
||||
* */
|
||||
double dread(int x, int y, int colour);
|
||||
|
||||
/* dRead, Average
|
||||
* Same as the above, only that the average of the three colour coefficients is returned.
|
||||
*/
|
||||
double dread(int x, int y);
|
||||
|
||||
/* Read HSV
|
||||
* With this function we find out what colour the pixel (x, y) is, but in the Hue,
|
||||
* Saturation, Value colourspace. If "colour" is 1,
|
||||
* it will return the Hue coefficient, if it is set to 2, the Saturation one, and if
|
||||
* it set to 3, the Value colour coefficient will be returned, and this returned
|
||||
* value will be of type int and be between 0 and 65535. Important: If you attempt
|
||||
* to read the Hue of a pixel that is a shade of grey, the value returned will be
|
||||
* nonsensical or even NaN. This is just the way the RGB -> HSV algorithm works:
|
||||
* the Hue of grey is not defined. You might want to check whether the pixel
|
||||
* you are reading is grey before attempting a readHSV().
|
||||
* Tip: This is especially useful for categorizing sections of the image according
|
||||
* to their colour.
|
||||
* */
|
||||
int readHSV(int x, int y, int colour);
|
||||
|
||||
/* dRead HSV
|
||||
* With this function we find out what colour the pixel (x, y) is, but in the Hue,
|
||||
* Saturation, Value colourspace. If "colour" is 1,
|
||||
* it will return the Hue coefficient, if it is set to 2, the Saturation one, and if
|
||||
* it set to 3, the Value colour coefficient will be returned,
|
||||
* and this returned value will be of type double and be between 0.0 and 1.0.
|
||||
* */
|
||||
double dreadHSV(int x, int y, int colour);
|
||||
|
||||
/* Clear
|
||||
* The whole image is set to black.
|
||||
* */
|
||||
void clear(void);
|
||||
|
||||
/* Close
|
||||
* Close the instance of the class, and write the image to disk.
|
||||
* Tip: If you do not call this function before your program ends, no image
|
||||
* will be written to disk.
|
||||
* */
|
||||
void close(void);
|
||||
|
||||
/* Rename
|
||||
* To rename the file once an instance of pngwriter has been created.
|
||||
* Useful for assigning names to files based upon their content.
|
||||
* Tip: This is as easy as calling pngwriter_rename("newname.png")
|
||||
* If the argument is a long unsigned int, for example 77, the filename will be changed to
|
||||
* 0000000077.png
|
||||
* Tip: Use this to create sequences of images for movie generation.
|
||||
* */
|
||||
void pngwriter_rename(char * newname);
|
||||
void pngwriter_rename(const char * newname);
|
||||
void pngwriter_rename(long unsigned int index);
|
||||
|
||||
/* Figures
|
||||
* These functions draw basic shapes. Available in both int and double versions.
|
||||
* The line functions use the fast Bresenham algorithm. Despite the name,
|
||||
* the square functions draw rectangles. The circle functions use a fast
|
||||
* integer math algorithm. The filled circle functions make use of sqrt().
|
||||
* */
|
||||
void line(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue);
|
||||
void line(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue);
|
||||
|
||||
void triangle(int x1, int y1, int x2, int y2, int x3, int y3, int red, int green, int blue);
|
||||
void triangle(int x1, int y1, int x2, int y2, int x3, int y3, double red, double green, double blue);
|
||||
|
||||
void square(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue);
|
||||
void square(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue);
|
||||
|
||||
void filledsquare(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue);
|
||||
void filledsquare(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue);
|
||||
|
||||
void circle(int xcentre, int ycentre, int radius, int red, int green, int blue);
|
||||
void circle(int xcentre, int ycentre, int radius, double red, double green, double blue);
|
||||
|
||||
void filledcircle(int xcentre, int ycentre, int radius, int red, int green, int blue);
|
||||
void filledcircle(int xcentre, int ycentre, int radius, double red, double green, double blue);
|
||||
|
||||
|
||||
/* Read From File
|
||||
* Open the existing PNG image, and copy it into this instance of the class. It is important to mention
|
||||
* that PNG variants are supported. Very generally speaking, most PNG files can now be read (as of version 0.5.4),
|
||||
* but if they have an alpha channel it will be completely stripped. If the PNG file uses GIF-style transparency
|
||||
* (where one colour is chosen to be transparent), PNGwriter will not read the image properly, but will not
|
||||
* complain. Also, if any ancillary chunks are included in the PNG file (chroma, filter, etc.), it will render
|
||||
* with a slightly different tonality. For the vast majority of PNGs, this should not be an issue. Note:
|
||||
* If you read an 8-bit PNG, the internal representation of that instance of PNGwriter will be 8-bit (PNG
|
||||
* files of less than 8 bits will be upscaled to 8 bits). To convert it to 16-bit, just loop over all pixels,
|
||||
* reading them into a new instance of PNGwriter. New instances of PNGwriter are 16-bit by default.
|
||||
* */
|
||||
|
||||
void readfromfile(char * name);
|
||||
void readfromfile(const char * name);
|
||||
|
||||
/* Get Height
|
||||
* When you open a PNG with readfromfile() you can find out its height with this function.
|
||||
* */
|
||||
int getheight(void);
|
||||
|
||||
/* Get Width
|
||||
* When you open a PNG with readfromfile() you can find out its width with this function.
|
||||
* */
|
||||
int getwidth(void);
|
||||
|
||||
/* Set Compression Level
|
||||
* Set the compression level that will be used for the image. -1 is to use the default,
|
||||
* 0 is none, 9 is best compression.
|
||||
* Remember that this will affect how long it will take to close() the image. A value of 2 or 3
|
||||
* is good enough for regular use, but for storage or transmission you might want to take the time
|
||||
* to set it at 9.
|
||||
* */
|
||||
void setcompressionlevel(int level);
|
||||
|
||||
/* Get Bit Depth
|
||||
* When you open a PNG with readfromfile() you can find out its bit depth with this function.
|
||||
* Mostly for troubleshooting uses.
|
||||
* */
|
||||
int getbitdepth(void);
|
||||
|
||||
/* Get Colour Type
|
||||
* When you open a PNG with readfromfile() you can find out its colour type (libpng categorizes
|
||||
* different styles of image data with this number).
|
||||
* Mostly for troubleshooting uses.
|
||||
* */
|
||||
int getcolortype(void);
|
||||
|
||||
/* Set Gamma Coeff
|
||||
* Set the image's gamma (file gamma) coefficient. This is experimental, but use it if your image's colours seem too bright
|
||||
* or too dark. The default value of 0.5 should be fine. The standard disclaimer about Mac and PC gamma
|
||||
* settings applies.
|
||||
* */
|
||||
void setgamma(double gamma);
|
||||
|
||||
|
||||
/* Get Gamma Coeff
|
||||
* Get the image's gamma coefficient. This is experimental.
|
||||
* */
|
||||
double getgamma(void);
|
||||
|
||||
/* Bezier Curve
|
||||
* (After Frenchman Pierre BŽzier from Regie Renault)
|
||||
* A collection of formulae for describing curved lines
|
||||
* and surfaces, first used in 1972 to model automobile surfaces.
|
||||
* (from the The Free On-line Dictionary of Computing)
|
||||
* See http://www.moshplant.com/direct-or/bezier/ for one of many
|
||||
* available descriptions of bezier curves.
|
||||
* There are four points used to define the curve: the two endpoints
|
||||
* of the curve are called the anchor points, while the other points,
|
||||
* which define the actual curvature, are called handles or control points.
|
||||
* Moving the handles lets you modify the shape of the curve.
|
||||
* */
|
||||
|
||||
void bezier( int startPtX, int startPtY,
|
||||
int startControlX, int startControlY,
|
||||
int endPtX, int endPtY,
|
||||
int endControlX, int endControlY,
|
||||
double red, double green, double blue);
|
||||
|
||||
void bezier( int startPtX, int startPtY,
|
||||
int startControlX, int startControlY,
|
||||
int endPtX, int endPtY,
|
||||
int endControlX, int endControlY,
|
||||
int red, int green, int blue);
|
||||
|
||||
/* Set Text
|
||||
* Sets the text information in the PNG header. If it is not called, the default is used.
|
||||
*/
|
||||
void settext(char * title, char * author, char * description, char * software);
|
||||
void settext(const char * title, const char * author, const char * description, const char * software);
|
||||
|
||||
|
||||
/* Version Number
|
||||
* Returns the PNGwriter version number.
|
||||
*/
|
||||
static double version(void);
|
||||
|
||||
/* Write PNG
|
||||
* Writes the PNG image to disk. You can still change the PNGwriter instance after this.
|
||||
* Tip: This is exactly the same as close(), but easier to remember.
|
||||
* Tip: To make a sequence of images using only one instance of PNGwriter, alter the image, change its name,
|
||||
* write_png(), then alter the image, change its name, write_png(), etc.
|
||||
*/
|
||||
void write_png(void);
|
||||
|
||||
/* Plot Text
|
||||
* Uses the Freetype2 library to set text in the image. face_path is the file path to a
|
||||
* TrueType font file (.ttf) (FreeType2 can also handle other types). fontsize specifices the approximate
|
||||
* height of the rendered font in pixels. x_start and y_start specify the placement of the
|
||||
* lower, left corner of the text string. angle is the text angle in radians. text is the text to be rendered.
|
||||
* The colour coordinates can be doubles from 0.0 to 1.0 or ints from 0 to 65535.
|
||||
* Tip: PNGwriter installs a few fonts in /usr/local/share/pngwriter/fonts to get you started.
|
||||
* Tip: Remember to add -DNO_FREETYPE to your compilation flags if PNGwriter was compiled without FreeType support.
|
||||
* */
|
||||
void plot_text(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue);
|
||||
void plot_text(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue);
|
||||
|
||||
|
||||
/* Plot UTF-8 Text
|
||||
* Same as the above, but the text to be plotted is encoded in UTF-8. Why would you want this? To be able to plot
|
||||
* all characters available in a large TrueType font, for example: for rendering Japenese, Chinese and other
|
||||
* languages not restricted to the standard 128 character ASCII space.
|
||||
* Tip: The quickest way to get a string into UTF-8 is to write it in an adequate text editor, and save it as a file
|
||||
* in UTF-8 encoding, which can then be read in in binary mode.
|
||||
* */
|
||||
void plot_text_utf8(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue);
|
||||
void plot_text_utf8(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue);
|
||||
|
||||
|
||||
/* Bilinear Interpolation of Image
|
||||
* Given a floating point coordinate (x from 0.0 to width, y from 0.0 to height),
|
||||
* this function will return the interpolated colour intensity specified by
|
||||
* colour (where red = 1, green = 2, blue = 3).
|
||||
* bilinear_interpolate_read() returns an int from 0 to 65535, and
|
||||
* bilinear_interpolate_dread() returns a double from 0.0 to 1.0.
|
||||
* Tip: Especially useful for enlarging an image.
|
||||
* */
|
||||
int bilinear_interpolation_read(double x, double y, int colour);
|
||||
double bilinear_interpolation_dread(double x, double y, int colour);
|
||||
|
||||
/* Plot Blend
|
||||
* Plots the colour given by red, green blue, but blended with the existing pixel
|
||||
* value at that position. opacity is a double that goes from 0.0 to 1.0.
|
||||
* 0.0 will not change the pixel at all, and 1.0 will plot the given colour.
|
||||
* Anything in between will be a blend of both pixel levels. Please note: This is neither
|
||||
* alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels.
|
||||
* */
|
||||
|
||||
void plot_blend(int x, int y, double opacity, int red, int green, int blue);
|
||||
void plot_blend(int x, int y, double opacity, double red, double green, double blue);
|
||||
|
||||
|
||||
/* Invert
|
||||
* Inverts the image in RGB colourspace.
|
||||
* */
|
||||
void invert(void);
|
||||
|
||||
/* Resize Image
|
||||
* Resizes the PNGwriter instance. Note: All image data is set to black (this is
|
||||
* a resizing, not a scaling, of the image).
|
||||
* */
|
||||
void resize(int width, int height);
|
||||
|
||||
/* Boundary Fill
|
||||
* All pixels adjacent to the start pixel will be filled with the fill colour, until the boundary colour is encountered.
|
||||
* For example, calling boundary_fill() with the boundary colour set to red, on a pixel somewhere inside a red circle,
|
||||
* will fill the entire circle with the desired fill colour. If, on the other hand, the circle is not the boundary colour,
|
||||
* the rest of the image will be filled.
|
||||
* The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
|
||||
* */
|
||||
void boundary_fill(int xstart, int ystart, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ;
|
||||
void boundary_fill(int xstart, int ystart, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ;
|
||||
|
||||
/* Flood Fill
|
||||
* All pixels adjacent to the start pixel will be filled with the fill colour, if they are the same colour as the
|
||||
* start pixel. For example, calling flood_fill() somewhere in the interior of a solid blue rectangle will colour
|
||||
* the entire rectangle the fill colour. The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
|
||||
* */
|
||||
void flood_fill(int xstart, int ystart, double fill_red, double fill_green, double fill_blue) ;
|
||||
void flood_fill(int xstart, int ystart, int fill_red, int fill_green, int fill_blue) ;
|
||||
|
||||
/* Polygon
|
||||
* This function takes an array of integer values containing the coordinates of the vertexes of a polygon.
|
||||
* Note that if you want a closed polygon, you must repeat the first point's coordinates for the last point.
|
||||
* It also requires the number of points contained in the array. For example, if you wish to plot a triangle,
|
||||
* the array will contain 6 elements, and the number of points is 3. Be very careful about this; if you specify the wrong number
|
||||
* of points, your program will either segfault or produce points at nonsensical coordinates.
|
||||
* The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
|
||||
* */
|
||||
void polygon(int * points, int number_of_points, double red, double green, double blue);
|
||||
void polygon(int * points, int number_of_points, int red, int green, int blue);
|
||||
|
||||
/* Plot CMYK
|
||||
* Plot a point in the Cyan, Magenta, Yellow, Black colourspace. Please note that this colourspace is
|
||||
* lossy, i.e. it cannot reproduce all colours on screen that RGB can. The difference, however, is
|
||||
* barely noticeable. The algorithm used is a standard one. The colour components are either
|
||||
* doubles from 0.0 to 1.0 or ints from 0 to 65535.
|
||||
* */
|
||||
void plotCMYK(int x, int y, double cyan, double magenta, double yellow, double black);
|
||||
void plotCMYK(int x, int y, int cyan, int magenta, int yellow, int black);
|
||||
|
||||
/* Read CMYK, Double version
|
||||
* Get a pixel in the Cyan, Magenta, Yellow, Black colourspace. if 'colour' is 1, the Cyan component will be returned
|
||||
* as a double from 0.0 to 1.0. If 'colour is 2, the Magenta colour component will be returned, and so on, up to 4.
|
||||
* */
|
||||
double dreadCMYK(int x, int y, int colour);
|
||||
|
||||
/* Read CMYK
|
||||
* Same as the above, but the colour components returned are an int from 0 to 65535.
|
||||
* */
|
||||
int readCMYK(int x, int y, int colour);
|
||||
|
||||
/* Scale Proportional
|
||||
* Scale the image using bilinear interpolation. If k is greater than 1.0, the image will be enlarged.
|
||||
* If k is less than 1.0, the image will be shrunk. Negative or null values of k are not allowed.
|
||||
* The image will be resized and the previous content will be replaced by the scaled image.
|
||||
* Tip: use getheight() and getwidth() to find out the new width and height of the scaled image.
|
||||
* Note: After scaling, all images will have a bit depth of 16, even if the original image had
|
||||
* a bit depth of 8.
|
||||
* */
|
||||
void scale_k(double k);
|
||||
|
||||
/* Scale Non-Proportional
|
||||
* Scale the image using bilinear interpolation, with different horizontal and vertical scale factors.
|
||||
* */
|
||||
void scale_kxky(double kx, double ky);
|
||||
|
||||
/* Scale To Target Width and Height
|
||||
* Scale the image in such a way as to meet the target width and height.
|
||||
* Tip: if you want to keep the image proportional, scale_k() might be more appropriate.
|
||||
* */
|
||||
void scale_wh(int finalwidth, int finalheight);
|
||||
|
||||
|
||||
/* Blended Functions
|
||||
* All these functions are identical to their non-blended types. They take an extra argument, opacity, which is
|
||||
* a double from 0.0 to 1.0 and represents how much of the original pixel value is retained when plotting the
|
||||
* new pixel. In other words, if opacity is 0.7, then after plotting, the new pixel will be 30% of the
|
||||
* original colour the pixel was, and 70% of the new colour, whatever that may be. As usual, each function
|
||||
* is available in int or double versions. Please note: This is neither alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels.
|
||||
* */
|
||||
|
||||
// Start Blended Functions
|
||||
|
||||
void plotHSV_blend(int x, int y, double opacity, double hue, double saturation, double value);
|
||||
void plotHSV_blend(int x, int y, double opacity, int hue, int saturation, int value);
|
||||
|
||||
void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue);
|
||||
void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue);
|
||||
|
||||
void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue);
|
||||
void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue);
|
||||
|
||||
void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue);
|
||||
void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue);
|
||||
|
||||
void circle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue);
|
||||
void circle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue);
|
||||
|
||||
void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue);
|
||||
void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue);
|
||||
|
||||
void bezier_blend( int startPtX, int startPtY,
|
||||
int startControlX, int startControlY,
|
||||
int endPtX, int endPtY,
|
||||
int endControlX, int endControlY,
|
||||
double opacity,
|
||||
double red, double green, double blue);
|
||||
|
||||
void bezier_blend( int startPtX, int startPtY,
|
||||
int startControlX, int startControlY,
|
||||
int endPtX, int endPtY,
|
||||
int endControlX, int endControlY,
|
||||
double opacity,
|
||||
int red, int green, int blue);
|
||||
|
||||
void plot_text_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue);
|
||||
void plot_text_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue);
|
||||
|
||||
void plot_text_utf8_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue);
|
||||
void plot_text_utf8_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue);
|
||||
|
||||
void boundary_fill_blend(int xstart, int ystart, double opacity, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ;
|
||||
void boundary_fill_blend(int xstart, int ystart, double opacity, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ;
|
||||
|
||||
void flood_fill_blend(int xstart, int ystart, double opacity, double fill_red, double fill_green, double fill_blue) ;
|
||||
void flood_fill_blend(int xstart, int ystart, double opacity, int fill_red, int fill_green, int fill_blue) ;
|
||||
|
||||
void polygon_blend(int * points, int number_of_points, double opacity, double red, double green, double blue);
|
||||
void polygon_blend(int * points, int number_of_points, double opacity, int red, int green, int blue);
|
||||
|
||||
void plotCMYK_blend(int x, int y, double opacity, double cyan, double magenta, double yellow, double black);
|
||||
void plotCMYK_blend(int x, int y, double opacity, int cyan, int magenta, int yellow, int black);
|
||||
|
||||
// End of Blended Functions
|
||||
|
||||
/* Laplacian
|
||||
* This function applies a discrete laplacian to the image, multiplied by a constant factor.
|
||||
* The kernel used in this case is:
|
||||
* 1.0 1.0 1.0
|
||||
* 1.0 -8.0 1.0
|
||||
* 1.0 1.0 1.0
|
||||
* Basically, this works as an edge detector. The current pixel is assigned the sum of all neighbouring
|
||||
* pixels, multiplied by the corresponding kernel element. For example, imagine a pixel and its 8 neighbours:
|
||||
* 1.0 1.0 0.0 0.0
|
||||
* 1.0 ->1.0<- 0.0 0.0
|
||||
* 1.0 1.0 0.0 0.0
|
||||
* This represents a border between white and black, black is on the right. Applying the laplacian to
|
||||
* the pixel specified above pixel gives:
|
||||
* 1.0*1.0 + 1.0*1.0 + 0.0*1.0 +
|
||||
* 1.0*1.0 + 1.0*-8.0 + 0.0*1.0 +
|
||||
* 1.0*1.0 + 1.0*1.0 + 0.0*1.0 = -3.0
|
||||
* Applying this to the pixel to the right of the pixel considered previously, we get a sum of 3.0.
|
||||
* That is, after passing over an edge, we get a high value for the pixel adjacent to the edge. Since
|
||||
* PNGwriter limits the colour components if they are off-scale, and the result of the laplacian
|
||||
* may be negative, a scale factor and an offset value are included. This might be useful for
|
||||
* keeping things within range or for bringing out more detail in the edge detection. The
|
||||
* final pixel value will be given by:
|
||||
* final value = laplacian(original pixel)*k + offset
|
||||
* Tip: Try a value of 1.0 for k to start with, and then experiment with other values.
|
||||
* */
|
||||
void laplacian(double k, double offset);
|
||||
|
||||
/* Filled Triangle
|
||||
* Draws the triangle specified by the three pairs of points in the colour specified
|
||||
* by the colour coefficients. The colour components are either doubles from 0.0 to
|
||||
* 1.0 or ints from 0 to 65535.
|
||||
* */
|
||||
void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, int red, int green, int blue);
|
||||
void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, double red, double green, double blue);
|
||||
|
||||
/* Filled Triangle, Blended
|
||||
* Draws the triangle specified by the three pairs of points in the colour specified
|
||||
* by the colour coefficients, and blended with the background. See the description for Blended Functions.
|
||||
* The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535.
|
||||
* */
|
||||
void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, int red, int green, int blue);
|
||||
void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, double red, double green, double blue);
|
||||
|
||||
/* Arrow, Filled Arrow
|
||||
* Plots an arrow from (x1, y1) to (x2, y2) with the arrowhead at the second point, given the size in pixels
|
||||
* and the angle in radians of the arrowhead. The plotted arrow consists of one main line, and two smaller
|
||||
* lines originating from the second point. Filled Arrow plots the same, but the arrowhead is a solid triangle.
|
||||
* Tip: An angle of 10 to 30 degrees looks OK.
|
||||
* */
|
||||
|
||||
void arrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue);
|
||||
void arrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue);
|
||||
|
||||
void filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue);
|
||||
void filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue);
|
||||
|
||||
/* Cross, Maltese Cross
|
||||
* Plots a simple cross at x, y, with the specified height and width, and in the specified colour.
|
||||
* Maltese cross plots a cross, as before, but adds bars at the end of each arm of the cross.
|
||||
* The size of these bars is specified with x_bar_height and y_bar_width.
|
||||
* The cross will look something like this:
|
||||
*
|
||||
* ----- <-- ( y_bar_width)
|
||||
* |
|
||||
* |
|
||||
* |-------| <-- ( x_bar_height )
|
||||
* |
|
||||
* |
|
||||
* -----
|
||||
* */
|
||||
|
||||
void cross( int x, int y, int xwidth, int yheight, double red, double green, double blue);
|
||||
void cross( int x, int y, int xwidth, int yheight, int red, int green, int blue);
|
||||
|
||||
void maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, double red, double green, double blue);
|
||||
void maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, int red, int green, int blue);
|
||||
|
||||
/* Diamond and filled diamond
|
||||
* Plots a diamond shape, given the x, y position, the width and height, and the colour.
|
||||
* Filled diamond plots a filled diamond.
|
||||
* */
|
||||
|
||||
void filleddiamond( int x, int y, int width, int height, int red, int green, int blue);
|
||||
void diamond(int x, int y, int width, int height, int red, int green, int blue);
|
||||
|
||||
void filleddiamond( int x, int y, int width, int height, double red, double green, double blue);
|
||||
void diamond(int x, int y, int width, int height, double red, double green, double blue);
|
||||
|
||||
/* Get Text Width, Get Text Width UTF8
|
||||
* Returns the approximate width, in pixels, of the specified *unrotated* text. It is calculated by adding
|
||||
* each letter's width and kerning value (as specified in the TTF file). Note that this will not
|
||||
* give the position of the farthest pixel, but it will give a pretty good idea of what area the
|
||||
* text will occupy. Tip: The text, when plotted unrotated, will fit approximately in a box with its lower left corner at
|
||||
* (x_start, y_start) and upper right at (x_start + width, y_start + size), where width is given by get_text_width()
|
||||
* and size is the specified size of the text to be plotted. Tip: Text plotted at position
|
||||
* (x_start, y_start), rotated with a given 'angle', and of a given 'size'
|
||||
* whose width is 'width', will fit approximately inside a rectangle whose corners are at
|
||||
* 1 (x_start, y_start)
|
||||
* 2 (x_start + width*cos(angle), y_start + width*sin(angle))
|
||||
* 3 (x_start + width*cos(angle) - size*sin(angle), y_start + width*sin(angle) + size*cos(angle))
|
||||
* 4 (x_start - size*sin(angle), y_start + size*cos(angle))
|
||||
* */
|
||||
|
||||
int get_text_width(char * face_path, int fontsize, char * text);
|
||||
|
||||
int get_text_width_utf8(char * face_path, int fontsize, char * text);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
19
libsrc/utils/CMakeLists.txt
Normal file
19
libsrc/utils/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
# Define the current source locations
|
||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/utils)
|
||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/utils)
|
||||
|
||||
add_library(hyperion-utils
|
||||
${CURRENT_HEADER_DIR}/RgbColor.h
|
||||
${CURRENT_HEADER_DIR}/RgbImage.h
|
||||
|
||||
${CURRENT_SOURCE_DIR}/RgbColor.cpp
|
||||
${CURRENT_SOURCE_DIR}/RgbImage.cpp
|
||||
|
||||
${CURRENT_HEADER_DIR}/jsonschema/JsonFactory.h
|
||||
${CURRENT_HEADER_DIR}/jsonschema/JsonSchemaChecker.h
|
||||
${CURRENT_SOURCE_DIR}/jsonschema/JsonSchemaChecker.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(hyperion-utils
|
||||
jsoncpp)
|
10
libsrc/utils/RgbColor.cpp
Normal file
10
libsrc/utils/RgbColor.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
// Local includes
|
||||
#include <utils/RgbColor.h>
|
||||
|
||||
RgbColor RgbColor::BLACK = { 0, 0, 0 };
|
||||
RgbColor RgbColor::RED = { 255, 0, 0 };
|
||||
RgbColor RgbColor::GREEN = { 0, 255, 0 };
|
||||
RgbColor RgbColor::BLUE = { 0, 0, 255 };
|
||||
RgbColor RgbColor::YELLOW= { 255, 255, 0 };
|
||||
RgbColor RgbColor::WHITE = { 255, 255, 255 };
|
51
libsrc/utils/RgbImage.cpp
Normal file
51
libsrc/utils/RgbImage.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
|
||||
// STL includes
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
// hyperion Utils includes
|
||||
#include <utils/RgbImage.h>
|
||||
|
||||
|
||||
RgbImage::RgbImage(const unsigned width, const unsigned height, const RgbColor background) :
|
||||
mWidth(width),
|
||||
mHeight(height),
|
||||
mColors(NULL)
|
||||
{
|
||||
mColors = new RgbColor[width*height];
|
||||
for (RgbColor* color = mColors; color <= mColors+(mWidth*mHeight); ++color)
|
||||
{
|
||||
*color = background;
|
||||
}
|
||||
}
|
||||
|
||||
RgbImage::~RgbImage()
|
||||
{
|
||||
delete[] mColors;
|
||||
}
|
||||
|
||||
void RgbImage::setPixel(const unsigned x, const unsigned y, const RgbColor color)
|
||||
{
|
||||
// Debug-mode sanity check on given index
|
||||
(*this)(x,y) = color;
|
||||
}
|
||||
|
||||
const RgbColor& RgbImage::operator()(const unsigned x, const unsigned y) const
|
||||
{
|
||||
// Debug-mode sanity check on given index
|
||||
assert(x < mWidth);
|
||||
assert(y < mHeight);
|
||||
|
||||
const unsigned index = toIndex(x, y);
|
||||
return mColors[index];
|
||||
}
|
||||
|
||||
RgbColor& RgbImage::operator()(const unsigned x, const unsigned y)
|
||||
{
|
||||
// Debug-mode sanity check on given index
|
||||
assert(x < mWidth);
|
||||
assert(y < mHeight);
|
||||
|
||||
const unsigned index = toIndex(x, y);
|
||||
return mColors[index];
|
||||
}
|
460
libsrc/utils/jsonschema/JsonSchemaChecker.cpp
Normal file
460
libsrc/utils/jsonschema/JsonSchemaChecker.cpp
Normal file
@ -0,0 +1,460 @@
|
||||
// stdlib includes
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
// Utils-Jsonschema includes
|
||||
#include <utils/jsonschema/JsonSchemaChecker.h>
|
||||
|
||||
JsonSchemaChecker::JsonSchemaChecker()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
JsonSchemaChecker::~JsonSchemaChecker()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
bool JsonSchemaChecker::setSchema(const Json::Value & schema)
|
||||
{
|
||||
_schema = schema;
|
||||
|
||||
// TODO: check the schema
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonSchemaChecker::validate(const Json::Value & value)
|
||||
{
|
||||
// initialize state
|
||||
_error = false;
|
||||
_messages.clear();
|
||||
_currentPath.clear();
|
||||
_currentPath.push_back("[root]");
|
||||
_references.clear();
|
||||
|
||||
// collect dependencies
|
||||
collectDependencies(value, _schema);
|
||||
|
||||
// validate
|
||||
validate(value, _schema);
|
||||
|
||||
return !_error;
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::collectDependencies(const Json::Value & value, const Json::Value &schema)
|
||||
{
|
||||
assert (schema.isObject());
|
||||
|
||||
// check if id is present
|
||||
if (schema.isMember("id"))
|
||||
{
|
||||
// strore reference
|
||||
assert (schema["id"].isString());
|
||||
std::ostringstream ref;
|
||||
ref << "$(" << schema["id"].asString() << ")";
|
||||
_references[ref.str()] = &value;
|
||||
}
|
||||
|
||||
// check the current json value
|
||||
if (schema.isMember("properties"))
|
||||
{
|
||||
const Json::Value & properties = schema["properties"];
|
||||
assert(properties.isObject());
|
||||
|
||||
for (Json::Value::const_iterator j = properties.begin(); j != properties.end(); ++j)
|
||||
{
|
||||
std::string property = j.memberName();
|
||||
if (value.isMember(property))
|
||||
{
|
||||
collectDependencies(value[property], properties[property]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::validate(const Json::Value & value, const Json::Value &schema)
|
||||
{
|
||||
assert (schema.isObject());
|
||||
|
||||
// check the current json value
|
||||
for (Json::Value::const_iterator i = schema.begin(); i != schema.end(); ++i)
|
||||
{
|
||||
std::string attribute = i.memberName();
|
||||
const Json::Value & attributeValue = *i;
|
||||
|
||||
if (attribute == "type")
|
||||
checkType(value, attributeValue);
|
||||
else if (attribute == "properties")
|
||||
checkProperties(value, attributeValue);
|
||||
else if (attribute == "additionalProperties")
|
||||
{
|
||||
// ignore the properties which are handled by the properties attribute (if present)
|
||||
Json::Value::Members ignoredProperties;
|
||||
if (schema.isMember("properties")) {
|
||||
const Json::Value & props = schema["properties"];
|
||||
ignoredProperties = props.getMemberNames();
|
||||
}
|
||||
|
||||
checkAdditionalProperties(value, attributeValue, ignoredProperties);
|
||||
}
|
||||
else if (attribute == "dependencies")
|
||||
checkDependencies(value, attributeValue);
|
||||
else if (attribute == "minimum")
|
||||
checkMinimum(value, attributeValue);
|
||||
else if (attribute == "maximum")
|
||||
checkMaximum(value, attributeValue);
|
||||
else if (attribute == "items")
|
||||
checkItems(value, attributeValue);
|
||||
else if (attribute == "minItems")
|
||||
checkMinItems(value, attributeValue);
|
||||
else if (attribute == "maxItems")
|
||||
checkMaxItems(value, attributeValue);
|
||||
else if (attribute == "uniqueItems")
|
||||
checkUniqueItems(value, attributeValue);
|
||||
else if (attribute == "enum")
|
||||
checkEnum(value, attributeValue);
|
||||
else if (attribute == "required")
|
||||
; // nothing to do. value is present so always oke
|
||||
else if (attribute == "id")
|
||||
; // references have already been collected
|
||||
else
|
||||
{
|
||||
// no check function defined for this attribute
|
||||
setMessage(std::string("No check function defined for attribute ") + attribute);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::setMessage(const std::string & message)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
std::copy(_currentPath.begin(), _currentPath.end(), std::ostream_iterator<std::string>(oss, ""));
|
||||
oss << ": " << message;
|
||||
_messages.push_back(oss.str());
|
||||
}
|
||||
|
||||
const std::list<std::string> & JsonSchemaChecker::getMessages() const
|
||||
{
|
||||
return _messages;
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkType(const Json::Value & value, const Json::Value & schema)
|
||||
{
|
||||
assert(schema.isString());
|
||||
|
||||
std::string type = schema.asString();
|
||||
bool wrongType = false;
|
||||
if (type == "string")
|
||||
wrongType = !value.isString();
|
||||
else if (type == "number")
|
||||
wrongType = !value.isNumeric();
|
||||
else if (type == "integer")
|
||||
wrongType = !value.isIntegral();
|
||||
else if (type == "boolean")
|
||||
wrongType = !value.isBool();
|
||||
else if (type == "object")
|
||||
wrongType = !value.isObject();
|
||||
else if (type == "array")
|
||||
wrongType = !value.isArray();
|
||||
else if (type == "null")
|
||||
wrongType = !value.isNull();
|
||||
else if (type == "any")
|
||||
wrongType = false;
|
||||
else
|
||||
assert(false);
|
||||
|
||||
if (wrongType)
|
||||
{
|
||||
_error = true;
|
||||
setMessage(type + " expected");
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkProperties(const Json::Value & value, const Json::Value & schema)
|
||||
{
|
||||
assert(schema.isObject());
|
||||
|
||||
if (!value.isObject())
|
||||
{
|
||||
_error = true;
|
||||
setMessage("properies attribute is only valid for objects");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Json::Value::const_iterator i = schema.begin(); i != schema.end(); ++i)
|
||||
{
|
||||
std::string property = i.memberName();
|
||||
const Json::Value & propertyValue = *i;
|
||||
|
||||
assert(propertyValue.isObject());
|
||||
|
||||
_currentPath.push_back(std::string(".") + property);
|
||||
if (value.isMember(property))
|
||||
{
|
||||
validate(value[property], propertyValue);
|
||||
}
|
||||
else if (propertyValue.get("required", false).asBool())
|
||||
{
|
||||
_error = true;
|
||||
setMessage("missing member");
|
||||
}
|
||||
_currentPath.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkAdditionalProperties(const Json::Value & value, const Json::Value & schema, const Json::Value::Members & ignoredProperties)
|
||||
{
|
||||
if (!value.isObject())
|
||||
{
|
||||
_error = true;
|
||||
setMessage("additional properies attribute is only valid for objects");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Json::Value::const_iterator i = value.begin(); i != value.end(); ++i)
|
||||
{
|
||||
std::string property = i.memberName();
|
||||
if (std::find(ignoredProperties.begin(), ignoredProperties.end(), property) == ignoredProperties.end())
|
||||
{
|
||||
// property has no property definition. check against the definition for additional properties
|
||||
_currentPath.push_back(std::string(".") + property);
|
||||
if (schema.isBool())
|
||||
{
|
||||
if (schema.asBool() == false)
|
||||
{
|
||||
_error = true;
|
||||
setMessage("no schema definition");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
validate(value[property], schema);
|
||||
}
|
||||
_currentPath.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkDependencies(const Json::Value & value, const Json::Value & schemaLink)
|
||||
{
|
||||
if (!value.isObject())
|
||||
{
|
||||
_error = true;
|
||||
setMessage("dependencies attribute is only valid for objects");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(schemaLink.isString());
|
||||
std::map<std::string, const Json::Value *>::iterator iter = _references.find(schemaLink.asString());
|
||||
if (iter == _references.end())
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "reference " << schemaLink.asString() << " could not be resolved";
|
||||
setMessage(oss.str());
|
||||
return;
|
||||
}
|
||||
const Json::Value & schema = *(iter->second);
|
||||
|
||||
std::list<std::string> requiredProperties;
|
||||
if (schema.isString())
|
||||
{
|
||||
requiredProperties.push_back(schema.asString());
|
||||
}
|
||||
else if (schema.isArray())
|
||||
{
|
||||
for (Json::UInt i = 0; i < schema.size(); ++i)
|
||||
{
|
||||
assert(schema[i].isString());
|
||||
requiredProperties.push_back(schema[i].asString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "Exepected reference " << schemaLink.asString() << " to resolve to a string or array";
|
||||
setMessage(oss.str());
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::list<std::string>::const_iterator i = requiredProperties.begin(); i != requiredProperties.end(); ++i)
|
||||
{
|
||||
if (!value.isMember(*i))
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "missing member " << *i;
|
||||
setMessage(oss.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkMinimum(const Json::Value & value, const Json::Value & schema)
|
||||
{
|
||||
assert(schema.isNumeric());
|
||||
|
||||
if (!value.isNumeric())
|
||||
{
|
||||
// only for numeric
|
||||
_error = true;
|
||||
setMessage("minimum check only for numeric fields");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.asDouble() < schema.asDouble())
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "value is too small (minimum=" << schema.asDouble() << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkMaximum(const Json::Value & value, const Json::Value & schema)
|
||||
{
|
||||
assert(schema.isNumeric());
|
||||
|
||||
if (!value.isNumeric())
|
||||
{
|
||||
// only for numeric
|
||||
_error = true;
|
||||
setMessage("maximum check only for numeric fields");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.asDouble() > schema.asDouble())
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "value is too large (maximum=" << schema.asDouble() << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkItems(const Json::Value & value, const Json::Value & schema)
|
||||
{
|
||||
assert(schema.isObject());
|
||||
|
||||
if (!value.isArray())
|
||||
{
|
||||
// only for arrays
|
||||
_error = true;
|
||||
setMessage("items only valid for arrays");
|
||||
return;
|
||||
}
|
||||
|
||||
for(Json::ArrayIndex i = 0; i < value.size(); ++i)
|
||||
{
|
||||
// validate each item
|
||||
std::ostringstream oss;
|
||||
oss << "[" << i << "]";
|
||||
_currentPath.push_back(oss.str());
|
||||
validate(value[i], schema);
|
||||
_currentPath.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkMinItems(const Json::Value & value, const Json::Value & schema)
|
||||
{
|
||||
assert(schema.isIntegral());
|
||||
|
||||
if (!value.isArray())
|
||||
{
|
||||
// only for arrays
|
||||
_error = true;
|
||||
setMessage("minItems only valid for arrays");
|
||||
return;
|
||||
}
|
||||
|
||||
int minimum = schema.asInt();
|
||||
|
||||
if (static_cast<int>(value.size()) < minimum)
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "array is too small (minimum=" << minimum << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkMaxItems(const Json::Value & value, const Json::Value & schema)
|
||||
{
|
||||
assert(schema.isIntegral());
|
||||
|
||||
if (!value.isArray())
|
||||
{
|
||||
// only for arrays
|
||||
_error = true;
|
||||
setMessage("maxItems only valid for arrays");
|
||||
return;
|
||||
}
|
||||
|
||||
int maximum = schema.asInt();
|
||||
|
||||
if (static_cast<int>(value.size()) > maximum)
|
||||
{
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "array is too large (maximum=" << maximum << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkUniqueItems(const Json::Value & value, const Json::Value & schema)
|
||||
{
|
||||
assert(schema.isBool());
|
||||
|
||||
if (!value.isArray())
|
||||
{
|
||||
// only for arrays
|
||||
_error = true;
|
||||
setMessage("maxItems only valid for arrays");
|
||||
return;
|
||||
}
|
||||
|
||||
if (schema.asBool() == true)
|
||||
{
|
||||
// make sure no two items are identical
|
||||
|
||||
for(Json::UInt i = 0; i < value.size(); ++i)
|
||||
{
|
||||
for (Json::UInt j = i+1; j < value.size(); ++j)
|
||||
{
|
||||
if (value[i] == value[j])
|
||||
{
|
||||
// found a value twice
|
||||
_error = true;
|
||||
setMessage("array must have unique values");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JsonSchemaChecker::checkEnum(const Json::Value & value, const Json::Value & schema)
|
||||
{
|
||||
assert(schema.isArray());
|
||||
|
||||
for(Json::ArrayIndex i = 0; i < schema.size(); ++i)
|
||||
{
|
||||
if (schema[i] == value)
|
||||
{
|
||||
// found enum value. done.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// nothing found
|
||||
_error = true;
|
||||
std::ostringstream oss;
|
||||
oss << "Unknown enum value (allowed values are: ";
|
||||
std::string values = Json::FastWriter().write(schema);
|
||||
oss << values.substr(0, values.size()-1); // The writer append a new line which we don't want
|
||||
oss << ")";
|
||||
setMessage(oss.str());
|
||||
}
|
44
src/CMakeLists.txt
Normal file
44
src/CMakeLists.txt
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
# Find the libPNG
|
||||
find_package(PNG REQUIRED QUIET)
|
||||
|
||||
# Add additional includes dirs
|
||||
include_directories(${PNG_INCLUDE_DIR})
|
||||
|
||||
# Add the simple test executable 'TestSpi'
|
||||
add_executable(TestSpi
|
||||
TestSpi.cpp)
|
||||
|
||||
target_link_libraries(TestSpi
|
||||
hyperion
|
||||
hyperion-utils)
|
||||
|
||||
add_executable(TestHyperionPng
|
||||
TestHyperionPng.cpp)
|
||||
|
||||
target_link_libraries(TestHyperionPng
|
||||
hyperion-png)
|
||||
|
||||
add_executable(WriteConfig
|
||||
WriteConfig.cpp)
|
||||
|
||||
add_executable(TestConfigFile
|
||||
TestConfigFile.cpp)
|
||||
|
||||
target_link_libraries(TestConfigFile
|
||||
hyperion-utils
|
||||
hyperion)
|
||||
|
||||
add_executable(ViewPng
|
||||
ViewPng.cpp)
|
||||
|
||||
target_link_libraries(ViewPng
|
||||
hyperion
|
||||
hyperion-utils
|
||||
${PNG_LIBRARIES})
|
||||
|
||||
add_executable(Test2BobLight
|
||||
Test2BobLight.cpp)
|
||||
|
||||
target_link_libraries(Test2BobLight
|
||||
bob2hyperion)
|
115
src/FbWriter.h
Normal file
115
src/FbWriter.h
Normal file
@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/fb.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <utils/RgbImage.h>
|
||||
|
||||
class FbWriter
|
||||
{
|
||||
public:
|
||||
FbWriter()
|
||||
{
|
||||
initialise();
|
||||
}
|
||||
|
||||
~FbWriter()
|
||||
{
|
||||
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &orig_vinfo))
|
||||
{
|
||||
printf("Error re-setting variable information.\n");
|
||||
}
|
||||
|
||||
close(fbfd);
|
||||
}
|
||||
|
||||
int initialise()
|
||||
{
|
||||
// Open the file for reading and writing
|
||||
fbfd = open("/dev/fb0", O_RDWR);
|
||||
if (!fbfd)
|
||||
{
|
||||
printf("Error: cannot open framebuffer device.\n");
|
||||
return(-1);
|
||||
}
|
||||
printf("The framebuffer device was opened successfully.\n");
|
||||
|
||||
// Get fixed screen information
|
||||
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
|
||||
{
|
||||
printf("Error reading fixed information.\n");
|
||||
}
|
||||
// Get variable screen information
|
||||
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &orig_vinfo))
|
||||
{
|
||||
printf("Error reading variable information.\n");
|
||||
}
|
||||
printf("Original %dx%d, %dbpp\n", orig_vinfo.xres, orig_vinfo.yres, orig_vinfo.bits_per_pixel );
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void writeImage(const RgbImage& image)
|
||||
{
|
||||
std::cout << "Writing image [" << image.width() << "x" << image.height() << "]" << std::endl;
|
||||
|
||||
// Make a copy of the original screen-info
|
||||
fb_var_screeninfo vinfo = orig_vinfo;
|
||||
// memcpy(&vinfo, &orig_vinfo, sizeof(fb_var_screeninfo));
|
||||
|
||||
// Configure the frame-buffer for the new image
|
||||
vinfo.xres = image.width();
|
||||
vinfo.yres = image.height();
|
||||
vinfo.bits_per_pixel = 24;
|
||||
if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo))
|
||||
{
|
||||
printf("Error configuring frame-buffer");
|
||||
}
|
||||
|
||||
ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);
|
||||
std::cout << "New set resolution: " << vinfo.xres << "x" << vinfo.yres << std::endl;
|
||||
|
||||
// map fb to user mem
|
||||
long screensize = vinfo.yres * finfo.line_length;//vinfo.yres * vinfo.bits_per_pixel / 8;
|
||||
char* fbp = (char*)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
|
||||
if (!fbp)
|
||||
{
|
||||
// Failed to create memory map
|
||||
std::cout << "Failed to create the memory map" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::cout << "Screensize : " << screensize << std::endl;
|
||||
std::cout << "Max fb-index: " << (image.width()-1)*3 + (image.height()-1)*finfo.line_length << std::endl;
|
||||
std::cout << "[" << vinfo.xres << "x" << vinfo.yres << "] == [" << image.width() << "x" << image.height() << "]" << std::endl;
|
||||
|
||||
for (unsigned iY=0; iY<image.height(); ++iY)
|
||||
{
|
||||
memcpy(fbp + iY*finfo.line_length, &(image(0, iY)), image.width()*3);
|
||||
// for (unsigned iX=0; iX<image.width(); ++iX)
|
||||
// {
|
||||
// const unsigned pixOffset = iX*3 + iY*finfo.line_length;
|
||||
// fbp[pixOffset ] = image(iX, iY).red;
|
||||
// fbp[pixOffset+1] = image(iX, iY).green;
|
||||
// fbp[pixOffset+2] = image(iX, iY).blue;
|
||||
// }
|
||||
}
|
||||
std::cout << "FINISHED COPYING IMAGE TO FRAMEBUFFER" << std::endl;
|
||||
// cleanup
|
||||
munmap(fbp, screensize);
|
||||
}
|
||||
|
||||
// The identifier of the FrameBuffer File-Device
|
||||
int fbfd;
|
||||
// The 'Fixed' screen information
|
||||
fb_fix_screeninfo finfo;
|
||||
// The original 'Variable' screen information
|
||||
fb_var_screeninfo orig_vinfo;
|
||||
};
|
39
src/Test2BobLight.cpp
Normal file
39
src/Test2BobLight.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
// STL includes
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// Boblight includes
|
||||
#include <boblight.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
void* boblight_ptr = boblight_init();
|
||||
if (!boblight_ptr)
|
||||
{
|
||||
std::cerr << "Failed to initialise bob-light" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const unsigned width = 112;
|
||||
const unsigned height = 63;
|
||||
|
||||
boblight_setscanrange(boblight_ptr, width, height);
|
||||
|
||||
std::vector<int> rgbColor = { 255, 255, 0 };
|
||||
for (unsigned iY=0; iY<height; ++iY)
|
||||
{
|
||||
for (unsigned iX=0; iX<width; ++iX)
|
||||
{
|
||||
boblight_addpixelxy(boblight_ptr, iX, iY, rgbColor.data());
|
||||
}
|
||||
}
|
||||
boblight_sendrgb(boblight_ptr, 0, nullptr);
|
||||
|
||||
//sleep(5);
|
||||
|
||||
boblight_destroy(boblight_ptr);
|
||||
|
||||
return 0;
|
||||
}
|
16
src/TestBoblightOrig.cpp
Normal file
16
src/TestBoblightOrig.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
// STL includes
|
||||
#include <iostream>
|
||||
|
||||
// Boblight includes
|
||||
#include <boblight.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "TestBoblightOrig started" << std::endl;
|
||||
|
||||
std::cout << "TestBoblightOrig finished" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
38
src/TestConfigFile.cpp
Normal file
38
src/TestConfigFile.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
// STL includes
|
||||
#include <cstdlib>
|
||||
|
||||
// JsonSchema includes
|
||||
#include <utils/jsonschema/JsonFactory.h>
|
||||
|
||||
// hyperion includes
|
||||
#include <hyperion/LedString.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::string homeDir = getenv("RASPILIGHT_HOME");
|
||||
|
||||
const std::string schemaFile = homeDir + "/hyperion.schema.json";
|
||||
const std::string configFile = homeDir + "/hyperion.config.json";
|
||||
|
||||
Json::Value config;
|
||||
if (JsonFactory::load(schemaFile, configFile, config) < 0)
|
||||
{
|
||||
std::cerr << "UNABLE TO LOAD CONFIGURATION" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const Json::Value& deviceConfig = config["device"];
|
||||
const Json::Value& ledConfig = config["leds"];
|
||||
const Json::Value& colorConfig = config["color"];
|
||||
|
||||
std::cout << "COLOR CONFIGURATION: " << colorConfig.toStyledString() << std::endl;
|
||||
|
||||
const Json::Value& redConfig = colorConfig["red"];
|
||||
double redGamma = redConfig["gamma"].asDouble();
|
||||
std::cout << "RED GAMMA = " << redGamma << std::endl;
|
||||
std::cout << "RED GAMMA = " << colorConfig["red.gamma"].asDouble() << std::endl;
|
||||
LedString ledString = LedString::construct(ledConfig, colorConfig);
|
||||
|
||||
return 0;
|
||||
}
|
43
src/TestHyperionPng.cpp
Normal file
43
src/TestHyperionPng.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
|
||||
// STL includes
|
||||
#include <iostream>
|
||||
|
||||
// Boblight includes
|
||||
#include <boblight.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "Initialisaing Boblight" << std::endl;
|
||||
void* blPng = boblight_init();
|
||||
|
||||
int width = 112;
|
||||
int height = 64;
|
||||
std::cout << "Defining scan range (" << width << "x" << height << ")" << std::endl;
|
||||
boblight_setscanrange(blPng, width, height);
|
||||
|
||||
int colorPtr[3];
|
||||
colorPtr[0] = 255;
|
||||
colorPtr[1] = 0;
|
||||
colorPtr[2] = 0;
|
||||
std::cout << "Using color [" << colorPtr[0] << "; " << colorPtr[1] << "; " << colorPtr[2] << "]" << std::endl;
|
||||
|
||||
int nrOfFrames = 150;
|
||||
std::cout << "Generating " << nrOfFrames << " frames" << std::endl;
|
||||
for (int iFrame=0; iFrame<nrOfFrames; ++iFrame)
|
||||
{
|
||||
for (int iWidth=0; iWidth<width; ++iWidth)
|
||||
{
|
||||
for (int iHeight=0; iHeight<height; ++iHeight)
|
||||
{
|
||||
boblight_addpixelxy(blPng, iWidth, iHeight, colorPtr);
|
||||
}
|
||||
}
|
||||
|
||||
boblight_sendrgb(blPng, 0, NULL);
|
||||
}
|
||||
|
||||
std::cout << "Destroying Boblight" << std::endl;
|
||||
boblight_destroy(blPng);
|
||||
|
||||
return 0;
|
||||
}
|
161
src/TestSpi.cpp
Normal file
161
src/TestSpi.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
|
||||
// STL includes
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
// Local includes
|
||||
#include <utils/RgbColor.h>
|
||||
|
||||
#include "../libsrc/hyperion/LedDeviceWs2801.h"
|
||||
|
||||
void setColor(char* colorStr)
|
||||
{
|
||||
RgbColor color = RgbColor::BLACK;
|
||||
std::cout << "Switching all leds to: ";
|
||||
if (strncmp("red", colorStr, 3) == 0)
|
||||
{
|
||||
std::cout << "red";
|
||||
color = RgbColor::RED;
|
||||
}
|
||||
else if (strncmp("green", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "green";
|
||||
color = RgbColor::GREEN;
|
||||
}
|
||||
else if (strncmp("blue", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "blue";
|
||||
color = RgbColor::BLUE;
|
||||
}
|
||||
else if (strncmp("cyan", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "cyan";
|
||||
}
|
||||
else if (strncmp("gray", colorStr, 4) == 0)
|
||||
{
|
||||
std::cout << "gray";
|
||||
}
|
||||
else if (strncmp("white", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "white";
|
||||
color = RgbColor::WHITE;
|
||||
}
|
||||
else if (strncmp("black", colorStr, 5) == 0)
|
||||
{
|
||||
std::cout << "black";
|
||||
color = RgbColor::BLACK;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
unsigned ledCnt = 50;
|
||||
std::vector<RgbColor> buff(ledCnt, color);
|
||||
|
||||
LedDeviceWs2801 ledDevice("SpiPi", "/dev/spidev0.0", 20000, 40000);
|
||||
ledDevice.open();
|
||||
ledDevice.write(buff);
|
||||
}
|
||||
|
||||
bool _running = true;
|
||||
void doCircle()
|
||||
{
|
||||
RgbColor color_1 = RgbColor::RED;
|
||||
RgbColor color_2 = RgbColor::YELLOW;
|
||||
|
||||
unsigned ledCnt = 50;
|
||||
std::vector<RgbColor> data(ledCnt, RgbColor::BLACK);
|
||||
|
||||
LedDeviceWs2801 ledDevice("SpiPi", "/dev/spidev0.0", 20000, 40000);
|
||||
ledDevice.open();
|
||||
|
||||
timespec loopTime;
|
||||
loopTime.tv_sec = 0;
|
||||
loopTime.tv_nsec = 100000000; // 100 ms
|
||||
|
||||
int curLed_1 = 0;
|
||||
int nextLed_1 = 1;
|
||||
|
||||
int curLed_2 = 49;
|
||||
int nextLed_2 = 48;
|
||||
|
||||
|
||||
while (_running)
|
||||
{
|
||||
data[curLed_1] = RgbColor::BLACK;
|
||||
data[curLed_2] = RgbColor::BLACK;
|
||||
|
||||
// Move the current and the next pointer
|
||||
curLed_1 = nextLed_1;
|
||||
curLed_2 = nextLed_2;
|
||||
++nextLed_1;
|
||||
--nextLed_2;
|
||||
if (nextLed_1 == int(ledCnt))
|
||||
{
|
||||
nextLed_1 = 0;
|
||||
}
|
||||
if (nextLed_2 < 0)
|
||||
{
|
||||
nextLed_2 = 49;
|
||||
}
|
||||
|
||||
data[curLed_1] = color_1;
|
||||
|
||||
data[curLed_2] = color_2;
|
||||
|
||||
ledDevice.write(data);
|
||||
|
||||
nanosleep(&loopTime, NULL);
|
||||
}
|
||||
|
||||
// Switch the current leds off
|
||||
data[curLed_1] = RgbColor::BLACK;
|
||||
data[curLed_2] = RgbColor::BLACK;
|
||||
|
||||
ledDevice.write(data);
|
||||
}
|
||||
|
||||
#include <csignal>
|
||||
|
||||
void signal_handler(int signum)
|
||||
{
|
||||
_running = false;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (sizeof(RgbColor) != 3)
|
||||
{
|
||||
std::cout << "sizeof(RgbColor) = " << sizeof(RgbColor) << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Install signal handlers to stop loops
|
||||
signal(SIGTERM, &signal_handler);
|
||||
signal(SIGINT, &signal_handler);
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
std::cerr << "Missing argument" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strncmp("fixed", argv[1], 5) == 0)
|
||||
{
|
||||
setColor(argv[2]);
|
||||
return 0;
|
||||
}
|
||||
else if (strncmp("circle", argv[1], 6) == 0)
|
||||
{
|
||||
doCircle();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Unknown option: " << argv[1] << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
155
src/ViewPng.cpp
Normal file
155
src/ViewPng.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
|
||||
// STL includes
|
||||
#include <iostream>
|
||||
|
||||
// LibPNG includes
|
||||
#include <png.h>
|
||||
|
||||
// Utils includes
|
||||
#include <utils/RgbImage.h>
|
||||
#include <utils/jsonschema/JsonFactory.h>
|
||||
|
||||
// Raspilight includes
|
||||
#include <hyperion/Hyperion.h>
|
||||
|
||||
// Local includes
|
||||
#include "FbWriter.h"
|
||||
|
||||
bool read_png(std::string file_name, RgbImage*& rgbImage)
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen(file_name.c_str(), "rb")) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
|
||||
if (png_ptr == NULL)
|
||||
{
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == NULL)
|
||||
{
|
||||
fclose(fp);
|
||||
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
|
||||
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_SWAP_ALPHA | PNG_TRANSFORM_EXPAND, NULL);
|
||||
|
||||
png_uint_32 width = png_get_image_width(png_ptr, info_ptr);
|
||||
png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
|
||||
|
||||
png_uint_32 bitdepth = png_get_bit_depth(png_ptr, info_ptr);
|
||||
png_uint_32 channels = png_get_channels(png_ptr, info_ptr);
|
||||
png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr);
|
||||
|
||||
std::cout << "BitDepth" << std::endl;
|
||||
std::cout << bitdepth << std::endl;
|
||||
std::cout << "Channels" << std::endl;
|
||||
std::cout << channels << std::endl;
|
||||
std::cout << "ColorType" << std::endl;
|
||||
std::cout << color_type << std::endl;
|
||||
|
||||
png_bytepp row_pointers;
|
||||
row_pointers = png_get_rows(png_ptr, info_ptr);
|
||||
|
||||
rgbImage = new RgbImage(width, height);
|
||||
|
||||
for (unsigned iRow=0; iRow<height; ++iRow)
|
||||
{
|
||||
if (color_type == PNG_COLOR_TYPE_RGB)
|
||||
{
|
||||
RgbColor* rowPtr = reinterpret_cast<RgbColor*>(row_pointers[iRow]);
|
||||
for (unsigned iCol=0; iCol<width; ++iCol)
|
||||
{
|
||||
rgbImage->setPixel(iCol, iRow, rowPtr[iCol]);
|
||||
}
|
||||
}
|
||||
else if (color_type == PNG_COLOR_TYPE_RGBA)
|
||||
{
|
||||
unsigned* rowPtr = reinterpret_cast<unsigned*>(row_pointers[iRow]);
|
||||
for (unsigned iCol=0; iCol<width; ++iCol)
|
||||
{
|
||||
const unsigned argbValue = rowPtr[iCol];
|
||||
rgbImage->setPixel(iCol, iRow, {uint8_t((argbValue >> 16) & 0xFF), uint8_t((argbValue >> 8) & 0xFF), uint8_t((argbValue) & 0xFF)});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown/Unimplemented color-format
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
// Missing required argument
|
||||
std::cout << "Missing PNG-argumet. Usage: 'ViewPng [png-file]" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string pngFilename = argv[1];
|
||||
|
||||
RgbImage* image = nullptr;
|
||||
if (!read_png(pngFilename, image) || image == nullptr)
|
||||
{
|
||||
std::cout << "Failed to load image" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char* homeDir = getenv("RASPILIGHT_HOME");
|
||||
if (!homeDir)
|
||||
{
|
||||
homeDir = "/home/pi";
|
||||
}
|
||||
|
||||
std::cout << "RASPILIGHT HOME DIR: " << homeDir << std::endl;
|
||||
|
||||
const std::string schemaFile = std::string(homeDir) + "/hyperion.schema.json";
|
||||
const std::string configFile = std::string(homeDir) + "/hyperion.config.json";
|
||||
|
||||
Json::Value raspiConfig;
|
||||
if (JsonFactory::load(schemaFile, configFile, raspiConfig) < 0)
|
||||
{
|
||||
std::cerr << "UNABLE TO LOAD CONFIGURATION" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
std::cout << "Loaded configuration: " << raspiConfig << std::endl;
|
||||
|
||||
FbWriter fbWriter;
|
||||
|
||||
Hyperion raspiLight(raspiConfig);
|
||||
raspiLight.setInputSize(image->width(), image->height());
|
||||
|
||||
fbWriter.writeImage(*image);
|
||||
raspiLight(*image);
|
||||
|
||||
sleep(5);
|
||||
|
||||
delete image;
|
||||
}
|
198
src/WriteConfig.cpp
Normal file
198
src/WriteConfig.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
// STL includes
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
ofstream& indent(ofstream& ofs, unsigned indent)
|
||||
{
|
||||
for (unsigned i=0; i<indent; ++i)
|
||||
{
|
||||
ofs << '\t';
|
||||
}
|
||||
return ofs;
|
||||
}
|
||||
|
||||
struct LedFrame
|
||||
{
|
||||
unsigned topLedCnt = 17;
|
||||
unsigned rightLedCnt = 8;
|
||||
unsigned bottomLedCnt = 17;
|
||||
unsigned leftLedCnt = 8;
|
||||
|
||||
unsigned topLeftOffset = 17;
|
||||
|
||||
unsigned borderWidth = 10;
|
||||
unsigned borderHeight = 10;
|
||||
|
||||
unsigned totalLedCnt() const
|
||||
{
|
||||
return topLeftOffset + rightLedCnt + bottomLedCnt + leftLedCnt;
|
||||
}
|
||||
};
|
||||
|
||||
struct Led
|
||||
{
|
||||
unsigned index;
|
||||
double minX;
|
||||
double maxX;
|
||||
double minY;
|
||||
double maxY;
|
||||
};
|
||||
|
||||
void determineBoundaries(const LedFrame& ledFrame, const unsigned iLed, double& minX, double& maxX, double& minY, double& maxY)
|
||||
{
|
||||
if (iLed < ledFrame.topLedCnt)
|
||||
{
|
||||
// TOP of screen
|
||||
minX = iLed * 100.0/ledFrame.topLedCnt;
|
||||
maxX = (iLed+1) * 100.0/ledFrame.topLedCnt;
|
||||
|
||||
minY = 100.0 - ledFrame.borderHeight;
|
||||
maxY = 100.0;
|
||||
}
|
||||
else if (iLed < (ledFrame.topLedCnt+ledFrame.rightLedCnt))
|
||||
{
|
||||
// RIGHT of screen
|
||||
minX = 100.0 - ledFrame.borderWidth;
|
||||
maxX = 100.0;
|
||||
|
||||
minY = 100.0 - (iLed-15) * 100.0/(ledFrame.rightLedCnt+2);
|
||||
maxY = 100.0 - (iLed-16) * 100.0/(ledFrame.rightLedCnt+2);
|
||||
}
|
||||
else if (iLed < (ledFrame.topLedCnt+ledFrame.rightLedCnt+ledFrame.bottomLedCnt))
|
||||
{
|
||||
// BOTTOM of screen
|
||||
minX = 100.0 - (iLed-24) * 100.0/ledFrame.bottomLedCnt;
|
||||
maxX = 100.0 - (iLed-25) * 100.0/ledFrame.bottomLedCnt;
|
||||
|
||||
minY = 0.0;
|
||||
maxY = ledFrame.borderHeight;
|
||||
}
|
||||
else if (iLed < (ledFrame.topLedCnt+ledFrame.rightLedCnt+ledFrame.bottomLedCnt+ledFrame.leftLedCnt))
|
||||
{
|
||||
// LEFT of screen
|
||||
minX = 0.0;
|
||||
maxX = ledFrame.borderWidth;
|
||||
|
||||
minY = (iLed-41) * 100.0/(ledFrame.leftLedCnt+2);
|
||||
maxY = (iLed-40) * 100.0/(ledFrame.leftLedCnt+2);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Requested led index(" << iLed << ") out of bound" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Led> createLedMapping(const LedFrame ledFrame)
|
||||
{
|
||||
std::vector<Led> leds;
|
||||
for (unsigned iLed=0; iLed<ledFrame.totalLedCnt(); ++iLed)
|
||||
{
|
||||
Led led;
|
||||
|
||||
led.index = (iLed + ledFrame.topLeftOffset)%ledFrame.totalLedCnt();
|
||||
determineBoundaries(ledFrame, iLed, led.minX, led.maxX, led.minY, led.maxY);
|
||||
|
||||
leds.push_back(led);
|
||||
}
|
||||
|
||||
std::sort(leds.begin(), leds.end(), [](const Led& lhs, const Led& rhs){ return lhs.index < rhs.index; });
|
||||
|
||||
return leds;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const std::string filename = "hyperion.config.json";
|
||||
|
||||
LedFrame myFrame;
|
||||
std::vector<Led> leds = createLedMapping(myFrame);
|
||||
ofstream configOfs(filename.c_str());
|
||||
|
||||
configOfs << "// Automatically generated configuration file for 'Hyperion'" << endl;
|
||||
configOfs << "// Generation script: " << argv[0] << endl;
|
||||
configOfs << endl;
|
||||
configOfs << "{" << endl;
|
||||
|
||||
// Write the device section
|
||||
indent(configOfs, 1) << R"("device" : )" << endl;
|
||||
indent(configOfs, 1) << "{" << endl;
|
||||
indent(configOfs, 2) << R"("name" : "MyPi",)" << endl;
|
||||
indent(configOfs, 2) << R"("type" : "ws2801",)" << endl;
|
||||
indent(configOfs, 2) << R"("output" : "/dev/spidev0.0",)" << endl;
|
||||
indent(configOfs, 2) << R"("interval" : 20000,)" << endl;
|
||||
indent(configOfs, 2) << R"("rate" : 48000)" << endl;
|
||||
indent(configOfs, 1) << "}," << endl;
|
||||
|
||||
// Write the color-correction section
|
||||
indent(configOfs, 1) << R"("color" : )" << endl;
|
||||
indent(configOfs, 1) << "{" << endl;
|
||||
indent(configOfs, 2) << R"("red" : )" << endl;
|
||||
indent(configOfs, 2) << "{" << endl;
|
||||
indent(configOfs, 3) << R"("gamma" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("adjust" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("blacklevel" : 0.0)" << endl;
|
||||
indent(configOfs, 2) << "}," << endl;
|
||||
indent(configOfs, 2) << R"("green" : )" << endl;
|
||||
indent(configOfs, 2) << "{" << endl;
|
||||
indent(configOfs, 3) << R"("gamma" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("adjust" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("blacklevel" : 0.0)" << endl;
|
||||
indent(configOfs, 2) << "}," << endl;
|
||||
indent(configOfs, 2) << R"("blue" : )" << endl;
|
||||
indent(configOfs, 2) << "{" << endl;
|
||||
indent(configOfs, 3) << R"("gamma" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("adjust" : 1.0,)" << endl;
|
||||
indent(configOfs, 3) << R"("blacklevel" : 0.0)" << endl;
|
||||
indent(configOfs, 2) << "}" << endl;
|
||||
indent(configOfs, 1) << "}," << endl;
|
||||
|
||||
// Write the leds section
|
||||
indent(configOfs, 1) << R"("leds" : )" << endl;
|
||||
indent(configOfs, 1) << "[" << endl;
|
||||
for (const Led& led : leds)
|
||||
{
|
||||
// Add comments indicating the corners of the configuration
|
||||
if (led.minX == 0.0)
|
||||
{
|
||||
if (led.minY == 0.0)
|
||||
{
|
||||
indent(configOfs, 2) << "// TOP-LEFT Corner" << endl;
|
||||
}
|
||||
else if (led.maxY == 100.0)
|
||||
{
|
||||
indent(configOfs, 2) << "// BOTTOM-LEFT Corner" << endl;
|
||||
}
|
||||
}
|
||||
else if (led.maxX == 100.0)
|
||||
{
|
||||
if (led.minY == 0.0)
|
||||
{
|
||||
indent(configOfs, 2) << "// TOP-RIGHT Corner" << endl;
|
||||
}
|
||||
else if (led.maxY == 100.0)
|
||||
{
|
||||
indent(configOfs, 2) << "// BOTTOM-RIGHT Corner" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the configuration of the led
|
||||
indent(configOfs, 2) << "{" << endl;
|
||||
indent(configOfs, 3) << R"("index" : )" << led.index << "," << endl;
|
||||
indent(configOfs, 3) << R"("hscan" : { "minimum" : )" << led.minX << R"(, "maximum" : )" << led.maxX << R"( },)" << endl;
|
||||
indent(configOfs, 3) << R"("vscan" : { "minimum" : )" << led.minY << R"(, "maximum" : )" << led.maxY << R"( })" << endl;
|
||||
indent(configOfs, 2) << "}";
|
||||
if (led.index != leds.back().index)
|
||||
{
|
||||
configOfs << ",";
|
||||
}
|
||||
configOfs << endl;
|
||||
}
|
||||
indent(configOfs, 1) << "]" << endl;
|
||||
|
||||
configOfs << "}" << endl;
|
||||
}
|
Loading…
Reference in New Issue
Block a user