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