├── .gitignore ├── CMakeLists.txt ├── COPYING ├── COPYING.LESSER ├── COPYING.MIT ├── INSTALL ├── Makefile-all ├── README ├── README.md ├── README_PlanetLabs.md ├── cmake_uninstall.cmake.in ├── documentation ├── index.html ├── wjelement.html ├── wjreader.html └── wjwriter.html ├── example ├── Makefile ├── example.c ├── layout.json ├── layout.schema └── validate.c ├── include ├── CMakeLists.txt ├── memmgr.h ├── nmutil.h ├── wjelement.h ├── wjreader.h ├── wjwriter.h └── xpl.h ├── pkg-config.pc.cmake ├── src ├── CMakeLists.txt ├── cli │ ├── CMakeLists.txt │ ├── cmds.c │ ├── wje │ ├── wjecli.c │ └── wjecli.h ├── lib │ ├── CMakeLists.txt │ └── xpl.c ├── wjelement │ ├── CMakeLists.txt │ ├── element.c │ ├── element.h │ ├── hash.c │ ├── schema.c │ ├── search.c │ ├── types.c │ └── wjeunit.c ├── wjreader │ ├── CMakeLists.txt │ └── wjreader.c └── wjwriter │ ├── CMakeLists.txt │ └── wjwriter.c └── windows ├── wjelement-VC100.sln ├── wjelement-VC100.vcxproj ├── wjelement.sln └── wjelement.vcproj /.gitignore: -------------------------------------------------------------------------------- 1 | # CMake files 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Makefile 6 | CTestTestfile.cmake 7 | cmake_install.cmake 8 | cmake_uninstall.cmake 9 | install_manifest.txt 10 | 11 | # Output files 12 | wjelement.pc 13 | wjecli 14 | wjeunit 15 | 16 | # Compiled Object files 17 | *.slo 18 | *.lo 19 | *.o 20 | *.obj 21 | 22 | # Precompiled Headers 23 | *.gch 24 | *.pch 25 | 26 | # Compiled Dynamic libraries 27 | *.so 28 | *.so.* 29 | *.dylib 30 | *.dll 31 | 32 | # Fortran module files 33 | *.mod 34 | 35 | # Compiled Static libraries 36 | *.lai 37 | *.la 38 | *.a 39 | *.lib 40 | 41 | # Executables 42 | *.exe 43 | *.out 44 | *.app 45 | 46 | # Log files 47 | *.log 48 | 49 | # Visual Studio specific files 50 | Win32/ 51 | x64/ 52 | ipch/ 53 | *.suo 54 | *.sdf 55 | *.user 56 | *.tlog 57 | 58 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(WJElement) 2 | cmake_minimum_required(VERSION 2.6) 3 | include(CheckIncludeFiles) 4 | include(CheckSymbolExists) 5 | 6 | option(STATIC_LIB "Compile as static libraries" OFF) 7 | 8 | if(STATIC_LIB) 9 | set(BUILD_SHARED_LIBS OFF) 10 | add_definitions(-DCOMPILE_AS_STATIC) 11 | else(STATIC_LIB) 12 | set(BUILD_SHARED_LIBS ON) 13 | endif(STATIC_LIB) 14 | 15 | option(DISTINGUISH_INTEGERS "Distinguish between integer and non-integer numbers" OFF) 16 | if(DISTINGUISH_INTEGERS) 17 | add_definitions(-DWJE_DISTINGUISH_INTEGER_TYPE) 18 | endif() 19 | 20 | if("${CMAKE_SYSTEM}" MATCHES "Linux") 21 | add_definitions(-D_GNU_SOURCE) 22 | endif() 23 | 24 | if(NOT CMAKE_INSTALL_PREFIX) 25 | set(CMAKE_INSTALL_PREFIX /usr/local) 26 | endif(NOT CMAKE_INSTALL_PREFIX) 27 | set(INC_DEST_DIR ${CMAKE_INSTALL_PREFIX}/include) 28 | if(NOT LIB_DEST_DIR) 29 | set(LIB_DEST_DIR ${CMAKE_INSTALL_PREFIX}/lib) 30 | endif(NOT LIB_DEST_DIR) 31 | set(BIN_DEST_DIR ${CMAKE_INSTALL_PREFIX}/bin) 32 | 33 | if(CMAKE_BUILD_TYPE MATCHES Debug) 34 | add_definitions(-DDEBUG) 35 | option(SHOWNOTES "Show preprocessor notes" OFF) 36 | 37 | if(CMAKE_COMPILER_IS_GNUCC) 38 | # GCC specific debug options 39 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g3 -ggdb3 -gdwarf-2") 40 | set(AVOID_VERSION -avoid-version) 41 | endif(CMAKE_COMPILER_IS_GNUCC) 42 | endif(CMAKE_BUILD_TYPE MATCHES Debug) 43 | 44 | add_definitions(-DHAVE_CONFIG_H) 45 | 46 | check_include_files(string.h HAVE_STRING_H) 47 | check_symbol_exists(strcasecmp "strings.h" HAVE_STRCASECMP) 48 | 49 | check_include_files(regex.h HAVE_REGEX_H) 50 | if(HAVE_REGEX_H) 51 | add_definitions(-DHAVE_REGEX_H) 52 | else(HAVE_REGEX_H) 53 | message("*** WARNING: GNU C regex library not found.") 54 | message(" WJESchemaValidate() will not support:") 55 | message(" pattern") 56 | message(" patternProperties") 57 | message(" format") 58 | endif(HAVE_REGEX_H) 59 | 60 | # use, i.e. don't skip the full RPATH for the build tree 61 | SET(CMAKE_SKIP_BUILD_RPATH FALSE) 62 | # when building, don't use the install RPATH already 63 | # (but later on when installing) 64 | SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 65 | # the RPATH to be used when installing 66 | SET(CMAKE_INSTALL_RPATH ${LIB_DEST_DIR}) 67 | # add the automatically determined parts of the RPATH 68 | # which point to directories outside the build tree to the install RPATH 69 | SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 70 | 71 | ENABLE_TESTING(1) 72 | 73 | INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/documentation/ 74 | DESTINATION doc/wjelement/ 75 | ) 76 | 77 | include_directories(include) 78 | add_subdirectory(src) 79 | add_subdirectory(include) 80 | 81 | # pkg-config .pc 82 | SET(PKG_CONFIG_REQUIRES glib-2.0) 83 | SET(PKG_CONFIG_LIBDIR 84 | ${LIB_DEST_DIR} 85 | ) 86 | SET(PKG_CONFIG_INCLUDEDIR 87 | ${INC_DEST_DIR} 88 | ) 89 | SET(PKG_CONFIG_LIBS 90 | "-L\${libdir} -lwjelement -lwjreader -lwjwriter" 91 | ) 92 | SET(PKG_CONFIG_CFLAGS 93 | "-I\${includedir}" 94 | ) 95 | CONFIGURE_FILE( 96 | "${CMAKE_CURRENT_SOURCE_DIR}/pkg-config.pc.cmake" 97 | "${CMAKE_CURRENT_BINARY_DIR}/wjelement.pc" 98 | ) 99 | INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/wjelement.pc" 100 | DESTINATION ${LIB_DEST_DIR}/pkgconfig) 101 | 102 | # uninstall target 103 | configure_file( 104 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" 105 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 106 | IMMEDIATE @ONLY) 107 | 108 | add_custom_target(uninstall 109 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 110 | 111 | SET(MAJOR_VERSION 1) 112 | SET(MINOR_VERSION 0) 113 | SET(PATCH_VERSION 1) 114 | IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") 115 | 116 | INCLUDE (InstallRequiredSystemLibraries) 117 | 118 | SET (CPACK_SET_DESTDIR "on") 119 | SET (CPACK_PACKAGING_INSTALL_PREFIX "/tmp") 120 | SET (CPACK_GENERATOR "DEB") 121 | 122 | SET (CPACK_DEBIAN_PACKAGE_PRIORITY "extra") 123 | SET (CPACK_DEBIAN_PACKAGE_SECTION "libs") 124 | SET (CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) 125 | # autogenerate dependency information 126 | set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) 127 | 128 | SET (CPACK_PACKAGE_DESCRIPTION "Short description") 129 | SET (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Long description") 130 | SET (CPACK_PACKAGE_VENDOR "Titan Lien (digbil)") 131 | SET (CPACK_PACKAGE_CONTACT "titan@digbil.com") 132 | SET (CPACK_PACKAGE_VERSION_MAJOR "${MAJOR_VERSION}") 133 | SET (CPACK_PACKAGE_VERSION_MINOR "${MINOR_VERSION}") 134 | SET (CPACK_PACKAGE_VERSION_PATCH "${PATCH_VERSION}") 135 | 136 | SET (CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${MAJOR_VERSION}.${MINOR_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}") 137 | SET (CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${MAJOR_VERSION}.${MINOR_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}") 138 | 139 | SET (CPACK_COMPONENTS_ALL Libraries ApplicationData) 140 | INCLUDE (CPack) 141 | ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") 142 | 143 | -------------------------------------------------------------------------------- /COPYING.LESSER: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /COPYING.MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015 Netmail / Reveal Data 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Compile and install WJElement: 2 | 3 | $ ccmake . #change settings if desired, 'c'onfigure and 'g'enerate 4 | $ cmake -DLIB_DEST_DIR=/usr/local/lib64 #set lib path if needed 5 | $ make 6 | # make install 7 | 8 | You may also use: 9 | $ cmake-gui . 10 | instead of ccmake. 11 | 12 | 13 | Use it in your program: 14 | 15 | #include 16 | 17 | 18 | Link against it in your project: 19 | 20 | -lwjelement 21 | (simple usage) 22 | -lwjelement -lwjreader -lwjwriter 23 | (advanced and lower-level functionality) 24 | 25 | 26 | By default, WJElement will install to /usr/local. If linking fails to find 27 | WJElement immediately after installation, you may need to run ldconfig. 28 | -------------------------------------------------------------------------------- /Makefile-all: -------------------------------------------------------------------------------- 1 | #This file can be called with `make -f Makefile-all` 2 | #The windows build for this file uses mingw 3 | 4 | THIS = Makefile-all 5 | 6 | # Compiler 7 | CC = _ 8 | CC_WIN32 = i686-w64-mingw32-gcc 9 | CC_WIN64 = x86_64-w64-mingw32-gcc 10 | CC_LINUX = gcc 11 | CC_MACOS = gcc 12 | 13 | 14 | MAKEDIR = @mkdir -p $(@D) 15 | PLATFORMDIR = _ 16 | BUILDDIR = $(PLATFORMDIR)release/ 17 | NAME_LIB = libwjelement 18 | CFLAGS += -Wall -Wextra -DWJE_DISTINGUISH_INTEGER_TYPE -Iinclude 19 | 20 | release: export CFLAGS=-O3 21 | release: all 22 | 23 | debug: export CFLAGS=-g -DDEBUG 24 | debug: all 25 | 26 | 27 | HDRDIR = ./include/ 28 | SRCDIR = ./src/ 29 | OBJDIR = $(BUILDDIR)obj/ 30 | 31 | # Set platform-specific variables 32 | ifeq ($(OS),Windows_NT) 33 | OSFLAG := "WIN" 34 | PLATFORMDIR = ./windows/ 35 | ifeq ($(PROCESSOR_ARCHITECTURE),x86) 36 | CC := $(CC_WIN32) 37 | endif 38 | ifeq ($(PROCESSOR_ARCHITECTURE),AMD64) 39 | CC := $(CC_WIN64) 40 | endif 41 | else 42 | UNAME_S := $(shell uname -s) 43 | PLATFORMDIR = ./unix/ 44 | ifeq ($(UNAME_S),Linux) 45 | OSFLAG := "LINUX" 46 | CC := $(CC_LINUX) 47 | CFLAGS += -fPIC 48 | endif 49 | ifeq ($(UNAME_S),Darwin) 50 | OSFLAG := "MACOS" 51 | CC := $(CC_MACOS) 52 | endif 53 | endif 54 | 55 | 56 | SRCS = lib/xpl.c \ 57 | wjelement/element.c \ 58 | wjelement/schema.c \ 59 | wjelement/hash.c \ 60 | wjelement/search.c \ 61 | wjelement/types.c \ 62 | wjreader/wjreader.c \ 63 | wjwriter/wjwriter.c 64 | 65 | OBJS = ${SRCS:%.c=$(OBJDIR)%.o} 66 | 67 | 68 | 69 | all: $(NAME_LIB)_static $(NAME_LIB)_dynamic 70 | 71 | 72 | # This rule compiles object files from source files 73 | $(OBJDIR)%.o : $(SRCDIR)%.c 74 | @$(MAKEDIR) 75 | @printf "Compiling file: "$@" -> " 76 | @$(CC) $(CFLAGS) -c $< -o $@ -I$(HDRDIR) 77 | @printf $(GREEN)"OK!"$(RESET)"\n" 78 | 79 | #This rule compiles the static version of libwjelement 80 | $(BUILDDIR)$(NAME_LIB).a: $(OBJS) 81 | @ar rs $@ $(OBJS) 82 | 83 | #This rule compiles the static version of libwjelement 84 | $(NAME_LIB)_static: $(BUILDDIR)$(NAME_LIB).a 85 | 86 | #This rule compiles the platform-specific dynamic version of libwjelement 87 | $(NAME_LIB)_dynamic: $(OBJS) 88 | @if [ $(OSFLAG) = "WIN" ]; then printf \ 89 | "Compiling DLL: "$(BUILDDIR)$(NAME_LIB).dll" -> " ; \ 90 | $(CC) -shared -o $(BUILDDIR)$(NAME_LIB).dll $(CFLAGS) $(OBJS) \ 91 | -Wl,--output-def,$(BUILDDIR)$(NAME_LIB).def \ 92 | -Wl,--out-implib,$(BUILDDIR)$(NAME_LIB).lib \ 93 | -Wl,--export-all-symbols ; \ 94 | elif [ $(OSFLAG) = "MACOS" ]; then printf \ 95 | "Compiling dylib: "$(BUILDDIR)$(NAME_LIB).dylib" -> " ; \ 96 | $(CC) -shared -o $(BUILDDIR)$(NAME_LIB).dylib $(CFLAGS) $(OBJS) ; \ 97 | elif [ $(OSFLAG) = "LINUX" ]; then \ 98 | printf "Compiling so: "$(BUILDDIR)$(NAME_LIB).so" -> " ; \ 99 | $(CC) -shared -o $(BUILDDIR)$(NAME_LIB).so $(CFLAGS) $(OBJS) ; \ 100 | fi 101 | @printf $(GREEN)"OK!"$(RESET)"\n" 102 | 103 | clean: 104 | @rm -rf $(BUILDDIR)* 105 | 106 | re: clean all 107 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | WJElement - JSON manipulation in C 2 | 3 | WJElement is a very flexible JSON library developed by Messaging Architects. 4 | It was created for MA's "WARP" webserver ("Warp Json Elements"), and is built 5 | on top of the lower-level WJReader and WJWriter libraries (also included). 6 | 7 | WJReader and WJWriter are optimized for speed and memory-efficiency. 8 | WJElement focuses on flexibility and handy features, allowing C code to 9 | manipulate JSON documents with as few statements (fewer, sometimes!) as 10 | JavaScript itself. WJElement is also capable of json-schema validation. 11 | 12 | WJElement has grown into a generally-useful library, and is used across 13 | Messaging Architects' netmail and related projects. It is loved enough by 14 | MA's developers that we desire to use it elsewhere too, and we think others 15 | will enjoy it as well. So, here it is, ready to be consumed in any project, 16 | open or closed, as outlined by the GNU LGPL (any version). Include it as-is 17 | and link to it from your code, massage it into your own statically-linked 18 | package, or use it in ways we haven't thought of. Read the docs/headers, have 19 | fun, and if you use it for something awesome, let us know about it! :^) 20 | 21 | 22 | License: 23 | WJElement may be used, modified, and distributed under the terms of any of 24 | the following licenses. 25 | - GPL (see COPYING) 26 | - LGPL (see COPYING.LESSER) 27 | - MIT (aka Expat) (see COPYING.MIT) 28 | 29 | 30 | Owen Swerkstrom - community/repo admin, WJESchema 31 | Micah N Gorrell - primary author of WJElement 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WJElement - JSON manipulation in C 2 | ================================== 3 | 4 | WJElement is a very flexible JSON library developed by Messaging Architects. 5 | It was created for MA's "WARP" webserver ("Warp Json Elements"), and is built 6 | on top of the lower-level WJReader and WJWriter libraries (also included). 7 | 8 | See the [wiki](https://github.com/netmail-open/wjelement/wiki) for more information, 9 | [example code](https://github.com/netmail-open/wjelement/wiki/WJElement-Example) 10 | and full [API](https://github.com/netmail-open/wjelement/wiki/WJElement-API) reference. 11 | 12 | WJReader and WJWriter are optimized for speed and memory-efficiency. 13 | WJElement focuses on flexibility and handy features, allowing C code to 14 | manipulate JSON documents with as few statements (fewer, sometimes!) as 15 | JavaScript itself. WJElement is also capable of json-schema validation. 16 | 17 | WJElement has grown into a generally-useful library, and is used across 18 | Messaging Architects' netmail and related projects. It is loved enough by 19 | MA's developers that we desire to use it elsewhere too, and we think others 20 | will enjoy it as well. So, here it is, ready to be consumed in any project, 21 | open or closed, as outlined by the GNU LGPL (any version). Include it as-is 22 | and link to it from your code, massage it into your own statically-linked 23 | package, or use it in ways we haven't thought of. Read the docs/headers, have 24 | fun, and if you use it for something awesome, let us know about it! :^) 25 | 26 | 27 | * Owen Swerkstrom <> - community/repo admin, WJESchema 28 | * Micah N Gorrell <> - primary author of WJElement 29 | -------------------------------------------------------------------------------- /README_PlanetLabs.md: -------------------------------------------------------------------------------- 1 | 2 | Upstream: https://github.com/netmail-open/wjelement 3 | 4 | Packaging as a .deb in debuild/wjelement (package wjelement-pl) 5 | 6 | This package is used by plcompositor for JSON parsing and schema validation. 7 | 8 | This repo was cloned by Frank Warmerdam, and is lightly modified from 9 | upstream for clean building. 10 | 11 | -------------------------------------------------------------------------------- /cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 3 | endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | 5 | file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 6 | string(REGEX REPLACE "\n" ";" files "${files}") 7 | foreach(file ${files}) 8 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 9 | if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 10 | exec_program( 11 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 12 | OUTPUT_VARIABLE rm_out 13 | RETURN_VALUE rm_retval 14 | ) 15 | if(NOT "${rm_retval}" STREQUAL 0) 16 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 17 | endif(NOT "${rm_retval}" STREQUAL 0) 18 | else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 19 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 20 | endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 21 | endforeach(file) 22 | -------------------------------------------------------------------------------- /documentation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | WJElement Documentation: index 4 | 5 | 6 | 7 |

About

8 |

9 | WJElement - JSON manipulation in C 10 |

11 |

12 | WJElement is a very flexible JSON library developed by Messaging Architects. 13 | It was created for MA's "WARP" webserver, and is built on top of the 14 | (also-included) lower-level WJReader and WJWriter libraries. 15 |

16 |

17 |

    18 |
  • 19 | WJReader and WJWriter are optimized for speed and memory-efficiency. 20 |
  • 21 |
  • 22 | WJElement focuses on flexibility and handy features, allowing C code to 23 | manipulate JSON documents with as few statements (fewer, sometimes!) as 24 | JavaScript itself. 25 |
      26 |
    • 27 | WJElement provides complete 28 | JSON-schema validation 29 | (draft 30 | v3 31 | is fully supported; v4 support is working but incomplete). 32 |
    • 33 |
    34 |
  • 35 |
36 |

37 | 38 |

License

39 |

40 | WJElement and its related libraries may be consumed in any project, 41 | open or closed, as outlined by the 42 | GNU Lesser 43 | General Public License (any version). 44 | Include it as-is and link to it 45 | from your code, massage it into your own statically-linked package, or use it 46 | in ways we haven't thought of. Read the docs/headers, have fun, and if you 47 | use it for something awesome, let us know about it! :^) 48 |

49 | 50 |

API

51 |

52 |

69 |

70 | 71 |

Quirks

72 |

73 | In the spirit of being upfront, and to help you guage whether WJElement is 74 | right for you without asking you to invest too much time, there are a few 75 | things to note about this library: 76 |

77 |

78 |

    79 |
  • 80 | XplBool return values 81 |
      82 |
    • 83 | Many functions return TRUE on success. Deal. :^) 84 |
    • 85 |
    86 |
  • 87 |
  • 88 | Schema "backlink" 89 |
      90 |
    • 91 | This is something we're making use of in netmail, but is not 92 | part of the base json-schema spec. 93 | You can safely ignore it (or dig in and use it, why not? :^) 94 |
    • 95 |
    96 |
  • 97 |
  • 98 | Libraries, headers (stubs and #define's) 99 |
      100 |
    • 101 | Xpl (cross-platform library) provides a consistent set of utility 102 | functions within netmail. WJElement uses a subset of these functions 103 | and definitions, so they have been included. 104 |
    • 105 |
    • 106 | MemMgr (memory manager) provides optimized, slab-based memory management 107 | in netmail; for the sake of a general WJElement release, the MemMgr API 108 | simply calls malloc et al. 109 |
    • 110 |
    111 |
  • 112 | 113 |
114 |

115 |

116 | You are free and encouraged to add and contribute features if 117 | you are so inclined. In some cases, there are comments or even empty code 118 | blocks, just waiting to be filled in. WJElement is great, but you can make it 119 | even better! 120 |

121 | 122 |

Contact

123 |

124 |

136 |

137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /documentation/wjelement.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | WJElement Documentation: wjelement 4 | 5 | 6 | 7 | Index 8 | 9 |

WJElement Synopsis

10 |

11 | The WJElement interfaces allow you to load an entire JSON document into 12 | memory and to then access elements within it more easily. 13 |

14 |

15 | WJElement uses UTF-8 encoding internally, as do the underlying 16 | WJReader 17 | and 18 | WJWriter. 19 | libraries. 20 | Adding other unicode support to WJR/WJW would not take too much work. 21 |

22 |

23 | WJElement is thread-safe, though an individual WJElement document and its 24 | children should not be used across threads without locking. WJElement does 25 | not provide locking, but its structure provides a handy client pointer which 26 | you may use for this or any other purpose. 27 |

28 | 29 |

WJElement Data Types

30 |

31 | WJElement 32 | is the main structure used for JSON documents. In most circumstances 33 | it will not be necessary to access anything within such a structure directly, 34 | but there are times when peeking at a JSON object's name or type (and other 35 | properties) comes in handy. 36 |

37 |

38 | From wjelement.h: 39 |

 40 | typedef struct WJElementPublic {
 41 |     char                            *name;
 42 |     WJRType                         type;
 43 | 
 44 |     struct WJElementPublic          *next;
 45 |     struct WJElementPublic          *prev;
 46 | 
 47 |     struct WJElementPublic          *child;
 48 |     struct WJElementPublic          *parent;
 49 | 
 50 |     /* The number of children */
 51 |     int                             count;
 52 | 
 53 |     /*
 54 |         A count of changes that have been performed on this element, which can
 55 |         be reset by the consumer.
 56 |     */
 57 |     int                             changes;
 58 | 
 59 |     void                            *client;
 60 | 
 61 |     /*
 62 |         If set then this freecb will be called before actually free'ing a
 63 |         WJElement.  If it returns FALSE then the WJElement will NOT be free'd.
 64 | 
 65 |         This can be used to allow caching of objects.  If used in this way then
 66 |         the consumer that set the callback is responsible for ensuring that it
 67 |         does get free'd correctly at the correct time.
 68 |     */
 69 |     XplBool                         (* freecb)(struct WJElementPublic *);
 70 | } WJElementPublic;
 71 | typedef WJElementPublic *            WJElement;
 72 | 
73 |

74 |

75 | WJEAction 76 | specifies which operation to carry out when calling the JSON manipulation 77 | functions. 78 |

79 |

80 | From wjelement.h: 81 |

 82 | typedef enum {
 83 |     WJE_GET = 0,
 84 |     WJE_SET,
 85 |     WJE_NEW,
 86 |     WJE_MOD
 87 | } WJEAction;
 88 | 
89 |

90 |

91 |

    92 |
  • 93 | WJE_GET 94 |
      95 |
    • 96 | Return the value of an element. If the element does not exist then the 97 | provided default value will be returned. 98 |
    • 99 |
    100 |
  • 101 |
  • 102 | WJE_SET 103 |
      104 |
    • 105 | Assign the specified value to an element. If the element does not exist 106 | then it will be created. 107 |
    • 108 |
    • 109 | If the element can not be created then an appropriate value will be 110 | returned to indicate the error. 111 |
    • 112 |
    • 113 | When applicable a NULL will be returned. Otherwise a value that does 114 | not match the requested value will be returned. 115 |
    • 116 |
    117 |
  • 118 |
  • 119 | WJE_NEW 120 |
      121 |
    • 122 | Create a new element and assign it the specified value. 123 |
    • 124 |
    • 125 | If an element already exists then it will not be modified, and the value 126 | of that existing element will be returned. 127 |
    • 128 |
    129 |
  • 130 |
  • 131 | WJE_MOD 132 |
      133 |
    • 134 | Assign the specified value to an existing element, and return the value 135 | if successful. 136 |
    • 137 |
    • 138 | If the element does not exist then no elements are created or modified. 139 |
    • 140 |
    • 141 | When applicable a NULL will be returned. Otherwise a value that does 142 | not match the requested value will be returned. 143 |
    • 144 |
    145 |
  • 146 |
147 |

148 | 149 |

WJElement Interfaces

150 |

Document/Element Management

151 |

152 | WJEParse 153 | - Parse the provided JSON document and return the new WJElement 154 |

155 |

156 |

157 | WJElement WJEParse(const char *json);
158 | WJElement _WJEParse(const char *json, char quote);
159 | 
160 |

161 |

162 | The _WJEParse version can be used to parse a document with a non-standard 163 | quote character. This allows easy parsing of simple documents directly in a 164 | C source file without having to escape double quote characters. Example: 165 |

166 | doc = _WJEParse("{ 'foo': true, 'bar': 'yup' }", '\'');
167 |     
168 |

169 |

170 | WJEOpenDocument 171 | - Load a WJElement object from the provided 172 | WJReader 173 |

174 |

175 |

176 | WJElement WJEOpenDocument(WJReader reader, char *where, WJELoadCB loadcb, void *data);
177 | 
178 |

179 |

180 | If a load callback is provided then it will be called before adding any new 181 | children, allowing the consumer to leave specific elements of the hierarchy. 182 |

183 |

184 | WJEWriteDocument 185 | - Write a WJElement object to the provided 186 | WJWriter 187 |

188 | XplBool WJEWriteDocument(WJElement document, WJWriter writer, char *name);
189 | 
190 |

191 |

192 | WJEWriteFILE 193 | - Write a WJElement object to the provided FILE* 194 |

195 | void WJEWriteFILE(WJElement document, FILE* fd);
196 | 
197 |

198 |

199 | WJEWriteFILE() requires an already opened FILE* to write to. 200 | It is also used internally by WJEDump() 201 |

202 | 203 |

204 | WJEWriteMEM 205 | - Allocate and write to a string 206 |

207 | char * WJEWriteMEM(WJElement document, XplBool pretty, size_t maxlength);
208 | 
209 |

210 |

211 | WJEWriteMEM() allocates and returns a string containing the document. 212 | A maxlength of 0 means the string may be of unlimited length. 213 | The returned string must be freed with MemFree by the consumer. 214 |

215 | 216 |

217 | WJECloseDocument 218 | - Destroy a WJElement object 219 |

220 |

221 |

222 | XplBool WJECloseDocument(WJElement document);
223 | 
224 |

225 |

226 | WJECloseDocument is also used to delete/remove an item from a parent document: 227 | WJECloseDocument(WJEGet(...)); 228 |

229 |

230 | WJECopyDocument 231 | - Duplicate an existing WJElement 232 |

233 |

234 |

235 | WJElement WJECopyDocument(WJElement to, WJElement from, WJECopyCB loadcb, void *data);
236 | 
237 |

238 |

239 | If a copy callback is provided, then it will be called with each element in 240 | order to allow filtered copying on an element-by-element basis, using any 241 | criteria. 242 |

243 |

244 | WJECopyDocument is normally used to create a new copy or to populate a new, 245 | empty document, but that is not required or enforced. If "to" is already 246 | populated, WJEMergeObjects is probably the desired function for copying in 247 | other contents. 248 |

249 |

250 | WJEDetach 251 | - Remove a WJElement from it's parent (and siblings) 252 |

253 |

254 |

255 | XplBool WJEDetach(WJElement document);
256 | 
257 |

258 |

259 | WJEAttach 260 | - Add a document to another document as a child 261 |

262 |

263 |

264 | XplBool WJEAttach(WJElement container, WJElement document);
265 | 
266 |

267 |

268 | WJERename 269 | - Rename an element 270 |

271 |

272 |

273 | XplBool WJERename(WJElement document, const char *name);
274 | 
275 |

276 |

277 | WJEMergeObjects 278 | - Merge all fields from one object to another 279 |

280 |

281 |

282 | XplBool WJEMergeObjects(WJElement to, WJElement from, XplBool overwrite);
283 | 
284 |

285 |

JSON Manipulation

286 |

287 | All JSON manipulation functions take a 'path' argument. This is a string as 288 | explained below, see WJElement Selectors 289 |

290 |

291 | Functions which take a 'last' parameter allow enumeration of multiple 292 | matching elements, if non-NULL is passed. Handy for looping through objects 293 | and arrays. 294 |

295 |

296 | WJEGet 297 | - Find the first element within the hierarchy of a WJElement that matches the 298 | specified path. 299 |

300 |

301 |

302 | WJElement WJEGet(WJElement container, char *path, WJElement last);
303 | 
304 |

305 |

306 | In cases where a direct child of the WJElement is needed, 307 | WJEChild may be more suitable, especially if the child's 308 | name begins with a non-alphanumeric character. 309 |

310 |

311 | WJEBool 312 | - Access a boolean element 313 |

314 |

315 |

316 | XplBool WJEBool(WJElement container, char *path, WJEAction action, XplBool value);
317 | XplBool _WJEBool(WJElement container, char *path, WJEAction action, WJElement *last, XplBool value);
318 | 
319 |

320 |

321 | WJEString, WJEStringN 322 | - Access a string element 323 |

324 |

325 |

326 | char * WJEString(WJElement container, char *path, WJEAction action, char *value);
327 | char * _WJEString(WJElement container, char *path, WJEAction action, WJElement *last, char *value);
328 | 
329 | char * WJEStringN(WJElement container, char *path, WJEAction action, char *value, size_t len);
330 | char * _WJEStringN(WJElement container, char *path, WJEAction action, WJElement *last, char *value, size_t len);
331 | 
332 |

333 |

334 | WJEObject 335 | - Access an object element 336 |

337 |

338 |

339 | WJElement WJEObject(WJElement container, char *path, WJEAction action);
340 | WJElement _WJEObject(WJElement container, char *path, WJEAction action, WJElement *last);
341 | 
342 |

343 |

344 | WJEArray 345 | - Access an array element 346 |

347 |

348 |

349 | WJElement WJEArray(WJElement container, char *path, WJEAction action);
350 | WJElement _WJEArray(WJElement container, char *path, WJEAction action, WJElement *last);
351 | 
352 |

353 |

354 | WJENull 355 | - Access a null element 356 |

357 |

358 |

359 | WJElement WJENull(WJElement container, char *path, WJEAction action);
360 | WJElement _WJENull(WJElement container, char *path, WJEAction action, WJElement *last);
361 | 
362 |

363 |

364 | WJEInt32 365 | - Access a number element, as a 32-bit integer 366 |

367 |

368 |

369 | int32 WJEInt32(WJElement container, char *path, WJEAction action, int32 value);
370 | int32 _WJEInt32(WJElement container, char *path, WJEAction action, WJElement *last, int32 value);
371 | 
372 |

373 |

374 | WJEUInt32 375 | - Access a number element, as a 32-bit unsigned integer 376 |

377 |

378 |

379 | uint32 WJEUInt32(WJElement container, char *path, WJEAction action, uint32 value);
380 | uint32 _WJEUInt32(WJElement container, char *path, WJEAction action, WJElement *last, uint32 value);
381 | 
382 |

383 |

384 | WJEInt64 385 | - Access a number element, as a 64-bit integer 386 |

387 |

388 |

389 | int64 WJEInt64(WJElement container, char *path, WJEAction action, int64 value);
390 | int64 _WJEInt64(WJElement container, char *path, WJEAction action, WJElement *last, int64 value);
391 | 
392 |

393 |

394 | WJEUInt64 395 | - Access a number element, as a 64-bit unsigned integer 396 |

397 |

398 |

399 | uint64 WJEUInt64(WJElement container, char *path, WJEAction action, uint64 value);
400 | uint64 _WJEUInt64(WJElement container, char *path, WJEAction action, WJElement *last, uint64 value);
401 | 
402 |

403 |

404 | WJEDouble 405 | - Access a number element, as a double (as in double-precision floating point) 406 |

407 |

408 |

409 | double WJEDouble(WJElement container, char *path, WJEAction action, double value);
410 | double _WJEDouble(WJElement container, char *path, WJEAction action, WJElement *last, double value);
411 | 
412 |

413 |

414 | WJE...F variants 415 | - Format-capable versions of element functions 416 |

417 |

418 | The following functions... 419 |

    420 |
  • WJEGetF
  • 421 |
  • WJEBoolF
  • 422 |
  • WJEStringF
  • 423 |
  • WJEStringNF
  • 424 |
  • WJEObjectF
  • 425 |
  • WJEArrayF
  • 426 |
  • WJENullF
  • 427 |
  • WJEInt32F
  • 428 |
  • WJEUInt32F
  • 429 |
  • WJEInt64F
  • 430 |
  • WJEUInt64F
  • 431 |
  • WJEDoubleF
  • 432 |
433 | ...are identical to the non F variants except that the 434 | path argument has been moved to the end and is used as a format string. For 435 | example if you need a value by index, and that index is stored in the 436 | variable x: 437 |
438 | val = WJENumberF(doc, WJE_GET, NULL, 0, "foo[%d]", x);
439 | 
440 |

441 |

442 | WJEChild 443 | - Find, create or update an element by name instead of path. This allows 444 | access to elements that would be difficult to reference by path. No selector 445 | syntax is used, so only direct children of the element can be found. 446 |

447 |

448 |

449 | WJElement WJEChild(WJElement container, char *name, WJEAction action);
450 | 
451 |

452 |

453 | Type specific actions may be done by passing the resulting WJElement and a 454 | NULL path to WJEBool(), WJENumber(), WJEString(), WJEObject(), WJEArray() or 455 | WJENull(). 456 |

457 |

Data Processing

458 |

459 | WJEHash 460 | - Calculate a hash for a document 461 |

462 |

463 |

464 | typedef int (* WJEHashCB)(void *context, void *data, size_t size);
465 | EXPORT void WJEHash(WJElement document, WJEHashCB update, void *context);
466 | 
467 |

468 |

Schema

469 |

470 | Callbacks: 471 |

472 |

473 |

474 | typedef WJElement (* WJESchemaLoadCB)(const char *name, void *client, const char *file, const int line);
475 | typedef void (* WJESchemaFreeCB)(WJElement schema, void *client);
476 | typedef void (* WJESchemaMatchCB)(WJElement schema, const char *selector, void *client);
477 | typedef void (* WJEErrCB)(void *client, const char *format, ...);
478 | 
479 |

480 |

481 | WJESchemaLoadCB callbacks are used to fetch schema as needed. 482 | WJESchemaFreeCB are called when schema is no longer needed. 483 |

484 |

485 | WJESchemaValidate 486 | - Validate a document against a given schema. 487 |

488 |

489 |

490 | XplBool WJESchemaValidate(WJElement schema, WJElement document,
491 |                           WJEErrCB err, WJESchemaLoadCB load,
492 |                           WJESchemaFreeCB freecb, void *client);
493 | 
494 |

495 |

496 | Additional schema will be loaded 497 | via the load callback if needed. Any validation errors will be reported, 498 | printf-style, to errcb.

499 |

500 | If a the load callback is used to acquire schema but a NULL free callback is 501 | provided, WJECloseDocument will be used internally to release it. 502 |

503 |

504 | WJESchemaIsType 505 | - Determine if a document implements a specific schema. 506 |

507 |

508 |

509 | XplBool WJESchemaIsType(WJElement document, const char *type,
510 |                         WJESchemaLoadCB loadcb, WJESchemaFreeCB freecb,
511 |                         void *client);
512 | 
513 |

514 |

515 | Additional schema will be loaded via the load callback if needed. 516 |

517 |

518 | If a load callback is not provided then the object type will still be checked 519 | but it will not be considered a match if it is a type that extends the 520 | specifed type. 521 |

522 |

523 | WJESchemaNameIsType 524 | - variation of WJESchemaIsType which acts on schema name instead of a document 525 |

526 |

527 |

528 | XplBool WJESchemaNameIsType(const char *describedby, const char *type,
529 |                             WJESchemaLoadCB loadcb,
530 |                             WJESchemaFreeCB freecb, void *client);
531 | 
532 |

533 |

534 | WJESchemaGetSelectors 535 | - find type/format-matching properties 536 |

537 |

538 |

539 | void WJESchemaGetSelectors(WJElement document,
540 |                            char *type, char *format,
541 |                            WJESchemaLoadCB load,
542 |                            WJESchemaFreeCB freecb,
543 |                            WJESchemaMatchCB matchcb, void *client);
544 | 
545 |

546 |

547 | WJESchemaGetSelectors 548 | calls back matchcb for each WJElement selector which will fetch a property 549 | of a given type and format, from a given document. The load callback will be 550 | used to load all necessary schema, starting with the document's "describedby". 551 | stripat-type wildcards may be used; "Date*" will find "date" and "date-time". 552 |

553 |

554 | WJESchemaGetAllSelectors 555 | - variation of WJESchemaGetSelectors which provides selectors that 556 | could exist in objects of the given "describedby" schema name 557 |

558 |

559 |

560 | void WJESchemaGetAllSelectors(char *describedby,
561 |                               char *type, char *format,
562 |                               WJESchemaLoadCB load,
563 |                               WJESchemaFreeCB freecb,
564 |                               WJESchemaMatchCB matchcb, void *client);
565 | 
566 |

567 |

568 | WJESchemaFindBacklink 569 | - find "backlink" property by schema 570 |

571 |

572 |

573 | char * WJESchemaFindBacklink(WJElement document, const char *format,
574 |                              WJESchemaLoadCB loadcb, WJESchemaFreeCB freecb,
575 |                              void *client);
576 | 
577 |

578 |

579 | WJESchemaNameFindBacklink 580 | - find "backlink" property by name 581 |

582 |

583 |

584 | char * WJESchemaNameFindBacklink(char *describedby, const char *format,
585 |                                  WJESchemaLoadCB loadcb, WJESchemaFreeCB freecb,
586 |                                  void *client);
587 | 
588 |

589 |

590 | WJESchemaFreeBacklink 591 | - clean up a previously-found backlink 592 |

593 |

594 |

595 | void WJESchemaFreeBacklink(char *backlink);
596 | 
597 |

598 |

Debug

599 |

600 | WJEDump 601 | - write a document to stdout 602 |

603 |

604 |

605 | void WJEDump(WJElement document);
606 | 
607 |

608 | 609 |

WJElement Selectors

610 |

611 | Elements within the hierarchy of a JSON document can be referenced using a 612 | path. Multiple levels of hierarchy can be referenced to find any element 613 | below the provided container. The following rules apply to any WJE 614 | functions that take a path argument. 615 |

616 |

617 | A child may be referenced with an alpha-numeric name, or a subscript within 618 | square brackets: 619 |

620 | foo
621 | ["foo"]
622 | ["$foo"]
623 | 
624 |

625 |

626 | Additional levels of heirarchy can be referenced by appending an additional 627 | subscript, or appending a dot and an additional alpha-numeric name: 628 |

629 | one.two.three.four
630 | one["two"]["three"].four
631 | 
632 |

633 |

634 | Subscripts may contain double quoted names. Any special characters, 635 | (including .[]*?"'\) can be included by prefixing with a \. 636 |

637 | foo["bar.smeg"]
638 | foo["something with a \"quote\""]
639 | 
640 |

641 |

642 | Subscripts may contain single quoted names, which behave as double quoted 643 | names but also allow for * and ? wild card substitution: 644 |

645 | foo['bar.*']
646 | 
647 |

648 |

649 | Subscripts may reference an item by it's offset in an array (or object): 650 |

651 | foo[0]
652 | foo[3]
653 | 
654 |

655 |

656 | Negative offsets are wrapped to the end of the array (or object) meaning 657 | that [-1] references the last item. 658 |

659 |

660 | Subscripts may reference a range of offsets by providing 2 offsets seperated 661 | by a colon: 662 |

663 | foo[2:5]
664 | 
665 |

666 |

667 | Subscripts may reference a set of items by seperating offsets, offset, 668 | ranges, double quoted and single quoted values: 669 |

670 | foo[2,4:6,'bar.*', "smeg"]
671 | 
672 |

673 |

674 | An empty subscript may be specified to reference all children. 675 |

676 | []
677 | 
678 |

679 |

680 | A subscript of $ may be specified in actions perform creations to reference 681 | the item after the end of an array. This allows appending to an array. 682 |

683 | [$]
684 | 
685 |

686 |

687 | A subscript may be prefixed by an | character to indicate that the subscript 688 | is optional. The portion of the selector from the | on will be ignored if 689 | there is a match and that match has no children. 690 |

691 |

692 | For example, if an element named foo may either be a string or an array of 693 | strings you can enumerate all values using a selector of: 694 |

695 | foo|[]
696 | 
697 |

698 |

699 | A NULL path refers to the container itself. 700 |

701 |

702 | A path may end in a condition. The condition consists of an operator and a 703 | value. The value may be a number, a double quoted string, or a single 704 | quoted string. If a single quoted string is used it may contain * and ? 705 | wild cards. 706 |

707 |

708 | The following operators are supported for any value: 709 |

710 | ==, !=
711 | 
712 |

713 |

714 | A number value may also use the following operators: 715 |

716 | <, >, <=, >=
717 | 
718 |

719 |

720 | Example: 721 |

722 | foo.bar <= 3
723 | foo.bar != 'foo*'
724 | foo.bar != "one"
725 | 
726 |

727 | A condition may be separated from a path with a ; character. 728 |

729 |

730 | In the following examples the object named "foo" will be returned if it has 731 | a child named "bar" that matches the condition. 732 |

733 | foo; bar <= 3
734 | foo; bar != 'foo*'
735 | foo; bar != "one"
736 | 
737 |

738 | 739 | 740 | 741 | -------------------------------------------------------------------------------- /documentation/wjreader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | WJElement Documentation: wjreader 4 | 5 | 6 | 7 | Index 8 | 9 |

WJReader Synopsis

10 |

11 | The WARP JSON Reader provides the ability to parse a JSON document as a 12 | stream. All parsing is done with a portion of the document loaded into a 13 | buffer, and the buffer is reloaded as needed. 14 |

15 |

16 | This allows the parser to be very fast, but does require that data in the 17 | document is accessed in the order of the document. 18 |

19 | 20 |

WJReader Data Types

21 |

22 | WJReader 23 | is The WJReader document, the library's primary structure 24 |

25 |

26 | From wjreader.h: 27 |

 28 | typedef struct {
 29 |     uint32                  depth;
 30 |     uint32                  maxdepth;
 31 |     void                    *userdata;
 32 | } WJReaderPublic;
 33 | typedef WJReaderPublic *    WJReader;
 34 | 
35 |

36 |

37 | WJRType 38 | specifies the type of a value being read. 39 |

40 |

41 | From wjreader.h: 42 |

 43 | typedef enum {
 44 |     WJR_TYPE_OBJECT         = 'O',
 45 |     WJR_TYPE_ARRAY          = 'A',
 46 | 
 47 |     WJR_TYPE_STRING         = 'S',
 48 |     WJR_TYPE_NUMBER         = 'N',
 49 | 
 50 |     WJR_TYPE_BOOL           = 'B',
 51 |     WJR_TYPE_TRUE           = 'T',
 52 |     WJR_TYPE_FALSE          = 'F',
 53 |     WJR_TYPE_NULL           = '0',
 54 | 
 55 |     WJR_TYPE_UNKNOWN        = '?'
 56 | } WJRType;
 57 | 
58 |

59 |

60 | WJReadCallback 61 | - Generic data reader (from file, socket, decoder, etc.) 62 |

63 |

64 |

 65 | typedef size_t (* WJReadCallback)(char *data, size_t length, size_t seen, void *userdata);
 66 | 
67 |

68 | 69 |

WJReader Interfaces

70 |

Document/Reader Management

71 |

72 | WJROpenDocument 73 | - Open a JSON document and prepare to parse. 74 |

75 |

76 |

 77 | WJReader WJROpenDocument(WJReadCallback callback, void *userdata, char *buffer,
 78 |                          size_t buffersize);
 79 | WJReader _WJROpenDocument(WJReadCallback callback, void *userdata, char *buffer,
 80 |                           size_t buffersize, uint32 maxdepth);
 81 | 
82 |

83 |

84 | A callback function must be 85 | provided which will be used to read data as it is needed. The callback is 86 | expected to load data into the provided buffer and return the number of 87 | bytes that where loaded. If the number of bytes loaded is less than the 88 | requested length then it is assumed that the end of the document has been 89 | reached. 90 |

91 |

92 | If a buffer is provided to WJROpenDocument() then that buffer will be used, 93 | rather than allocating a new buffer. The size of the buffer must be 94 | provided as buffersize. If a buffer is not provided then one will be 95 | allocated of size buffersize. 96 |

97 |

98 | If a buffersize of 0 is passed to WJROpenDocument then the default size will 99 | be used (4KB). Some data is kept in the buffer while parsing, such as 100 | element names and values. If the buffer is not large enough for these then 101 | the document will fail to be parsed and will be aborted. 102 |

103 |

104 | WJROpenFILEDocument 105 | - helper to read from an open FILE *. 106 |

107 |

108 |

109 | WJReader WJROpenFILEDocument(FILE *jsonfile, char *buffer, size_t buffersize);
110 | 
111 |

112 |

113 | An alternative method of opening a JSON document, which will provide a 114 | proper callback for reading the data from an open FILE *. 115 |

116 |

117 | As with the standard WJROpenDocument() a buffersize of 0 will use the 118 | default buffer size. 119 |

120 |

121 | WJROpenMemDocument 122 | - helper to read from memory. 123 |

124 |

125 |

126 | WJReader WJROpenMemDocument(char *json, char *buffer, size_t buffersize);
127 | 
128 |

129 |

130 | An alternative method of opening a JSON document, which will provide a 131 | proper callback for reading from a pre-allocated buffer in memory. 132 |

133 |

134 | As with the standard WJROpenDocument() a buffersize of 0 will use the 135 | default buffer size. 136 |

137 |

138 | WJRCloseDocument 139 | - Close a WJReader document. 140 |

141 |

142 |

143 | XplBool WJRCloseDocument(WJReader doc);
144 | 
145 |

146 |

JSON Values

147 |

148 | WJRNext 149 | - Get the type and name of the next element in 'doc'. 150 |

151 |

152 |

153 | char * WJRNext(char *parent, size_t maxnamelen, WJReader doc);
154 | 
155 |

156 |

157 | Returns a string, which contains the name of the next element of the 158 | specified parent, prefixed by a single character that represents the type. 159 | The pointer returned may be used as the parent argument in future calls to 160 | WJRNext() in order to return the children of the current object. 161 |

162 |

163 | If the object's name is larger than the maxnamelen argument then it will be 164 | truncated. 165 |

166 |

167 | These WJReader functions 168 | Return the value of the last object returned by WJRNext(). The calling 169 | application is expected to know the type of the value, and call the 170 | appropriate function. When possible the value will be converted if it does 171 | not match the requested type. 172 |

173 |

174 | If the buffer is not large enough to contain the entire value then the 175 | WJRString() function may return a partial value. It may be called multiple 176 | times until a NULL is returned to ensure that the entire value has been 177 | read. 178 |

179 |

180 |

181 | char *  WJRString(XplBool *complete, WJReader doc);
182 | char *  WJRStringEx(XplBool *complete, size_t *length, WJReader doc);
183 | XplBool WJRBoolean(WJReader doc);
184 | 
185 | int32   WJRInt32(WJReader doc);
186 | uint32  WJRUInt32(WJReader doc);
187 | int64   WJRInt64(WJReader doc);
188 | uint64  WJRUInt64(WJReader doc);
189 | double  WJRDouble(WJReader doc);
190 | 
191 |

192 |

193 | WJRNegative 194 | - Check whether the current WJR_TYPE_NUMBER value is negative 195 |

196 |

197 |

198 | XplBool WJRNegative(WJReader doc);
199 | 
200 |

201 |

202 | If the current element is a WJR_TYPE_NUMBER then this function can be used 203 | to determine if the value is negative or positive. If negative then TRUE 204 | will be returned. 205 |

206 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /documentation/wjwriter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | WJElement Documentation: wjwriter 4 | 5 | 6 | 7 | Index 8 | 9 |

WJWriter Synopsis

10 |

11 | The WARP JSON Writer provides the ability to easily write a JSON document to 12 | a stream. All data formatting is done automatically. 13 |

14 | 15 |

WJWriter Data Types

16 |

17 | WJWriter 18 | is The WJWriter document, the library's primary structure 19 |

20 |

21 | From wjwriter.h: 22 |

 23 | typedef struct {
 24 |     XplBool                pretty;
 25 | 
 26 |     /*
 27 |         Base may be set to 8, 10 (default), or 16.  Using a base other than 10
 28 |         will result in a non standard JSON document which may not be read
 29 |         properly by all parsers.
 30 |     */
 31 |     int                    base;
 32 | 
 33 |     struct {
 34 |         void               *data;
 35 |         WJWriteCallback    cb;
 36 |     } write;
 37 | 
 38 |     struct {
 39 |         void               *data;
 40 |         void               (* freecb)(void *data);
 41 |     } user;
 42 | } WJWriterPublic;
 43 | typedef WJWriterPublic*    WJWriter;
 44 | 
45 |

46 |

47 | WJWriteCallback 48 | - Generic data writer (to file, socket, encoder, etc.) 49 |

50 |

51 |

 52 | typedef size_t (* WJWriteCallback)(char *data, size_t size, void *writedata);
 53 | 
54 |

55 | 56 |

WJWriter Interfaces

57 |

Document/Writer Management

58 |

59 | WJWOpenDocument 60 | - Open a stream that is ready to accept a JSON document. 61 |

62 |

63 |

 64 | WJWriter WJWOpenDocument(XplBool pretty, WJWriteCallback callback,
 65 |                          void *writeData);
 66 | WJWriter _WJWOpenDocument(XplBool pretty, WJWriteCallback callback,
 67 |                           void *writedata, size_t buffersize);
 68 | 
69 |

70 |

71 | A callback function 72 | must be provided which will be used to write data as it is ready. 73 |

74 |

75 | A buffersize of 0 will disable write buffering entirely. The write buffer 76 | used will be at least the size requested, but may be larger. 77 |

78 |

79 | WJWOpenFILEDocument 80 | - helper to write to an open FILE *. 81 |

82 |

83 |

 84 | WJWriter WJWOpenFILEDocument(XplBool pretty, FILE *file);
 85 | 
86 |

87 |

88 | An alternative method of opening a JSON document for writing, which will 89 | provide a proper callback for writing the data to an open FILE *. 90 |

91 |

92 | WJWCloseDocument 93 | - Close a WJWriter document 94 |

95 |

96 |

 97 | XplBool WJWCloseDocument(WJWriter doc);
 98 | 
99 |

100 |

JSON Structures

101 |

102 | WJWOpenArray 103 | - Open an array. 104 |

105 |

106 |

107 | XplBool WJWOpenArray(char *name, WJWriter doc);
108 | 
109 |

110 |

111 | All objects that are direct children of the array MUST NOT 112 | be named. A value of NULL should be passed as name for any such values. 113 |

114 |

115 | When all values of the array have been written it can be closed with 116 | WJWCloseArray(). 117 |

118 |

119 | WJWCloseArray 120 | - Close an array. 121 |

122 |

123 |

124 | XplBool WJWCloseArray(WJWriter doc);
125 | 
126 |

127 |

128 | WJWOpenObject 129 | - Open an object. 130 |

131 |

132 |

133 | XplBool WJWOpenObject(char *name, WJWriter doc);
134 | 
135 |

136 |

137 | Open an object. All objects that are direct children of the object MUST be 138 | named. A value of NULL should NOT be passed as name for any such values. 139 |

140 |

141 | When all values of the object have been written it can be closed with 142 | WJWCloseObject(). 143 |

144 |

145 | WJWCloseObject 146 | - Close an object. 147 |

148 |

149 |

150 | XplBool WJWCloseObject(WJWriter doc);
151 | 
152 |

153 |

JSON Values

154 |

155 | These WJWriter functions 156 | write a value to the document. If any values are written that are a direct 157 | child of an object then a non-NULL name MUST be provided. If any values are 158 | written that are a direct child of an array then a non-NULL name MUST NOT be 159 | provided. 160 |

161 |

162 | A string value may be written in multiple pieces. A JSON string will be 163 | started with the first call to WJWString, or WJWStringN and the string will 164 | not be completed until the "done" argument is set to TRUE or there is a call 165 | to write a non-string type value. 166 |

167 |

168 |

169 | XplBool WJWStringN(char *name, char *value, size_t length, XplBool done, WJWriter doc);
170 | XplBool WJWString(char *name, char *value, XplBool done, WJWriter doc);
171 | XplBool WJWBoolean(char *name, XplBool value, WJWriter doc);
172 | XplBool WJWNull(char *name, WJWriter doc);
173 | 
174 | XplBool WJWInt32(char *name, int32 value, WJWriter doc);
175 | XplBool WJWUInt32(char *name, uint32 value, WJWriter doc);
176 | XplBool WJWInt64(char *name, int64 value, WJWriter doc);
177 | XplBool WJWUInt64(char *name, uint64 value, WJWriter doc);
178 | XplBool WJWDouble(char *name, double value, WJWriter doc);
179 | 
180 |

181 |

182 | WJWRawValue 183 | - Write a raw, pre-formatted value to the document. 184 |

185 |

186 |

187 | XplBool WJWRawValue(char *name, char *value, XplBool done, WJWriter doc);
188 | 
189 |

190 |

191 | It is up to the caller to 192 | ensure that the data is properly formatted and complete. 193 |

194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=validate 2 | TARGET2=example 3 | 4 | all: 5 | gcc -o ${TARGET} ${TARGET}.c -lwjelement -lwjreader 6 | gcc -o ${TARGET2} ${TARGET2}.c -lwjelement -lwjreader 7 | 8 | clean: 9 | rm ${TARGET} ${TARGET2} 10 | -------------------------------------------------------------------------------- /example/example.c: -------------------------------------------------------------------------------- 1 | /* 2 | example.c: an (incredibly basic) example of a WJElement consumer program 3 | 4 | after installing libwjelement (and running ldconfig if needed)... 5 | gcc -o example -lwjelement example.c 6 | or 7 | gcc -o example `pkg-config --libs wjelement` example.c 8 | 9 | the JSON operations performed in this example are parallel to the following 10 | javascript code. notice how similar the code is in both size and clarity: 11 | 12 | var doc = { 13 | "name": "Serenity", 14 | "class": "firefly", 15 | "crew": [ 16 | { 17 | "name": "Malcolm Reynolds", 18 | "job": "captain", 19 | "born": 2468 20 | }, 21 | { 22 | "name": "Kaywinnet Lee Fry", 23 | "job": "mechanic", 24 | "born": 2494 25 | }, 26 | { 27 | "name": "Jayne Cobb", 28 | "job": "public relations" 29 | "born": 2485 30 | } 31 | ], 32 | "cameo" : [ 33 | "Battlestar Galactica", 34 | "Star Wars Evasive Action", 35 | "Dr. Horrible's Sing-Along Blog", 36 | "Ready Player One" 37 | ], 38 | "shiny": true 39 | }; 40 | var person = null; 41 | var cameo = null; 42 | 43 | for(i in doc.crew) { // note: tedious... 44 | person = doc.crew[i]; 45 | if(person.born == 2468) { 46 | person.born = 2486; 47 | } 48 | } 49 | delete(doc.shiny); 50 | 51 | for(i in doc.crew) { 52 | person = doc.crew[i]; 53 | console.log(person.name +" ("+ person.job +") is "+ (2517 - person.born)); 54 | } 55 | for(i in doc.cameo) { 56 | cameo = doc.cameo[i]; 57 | console.log("Cameo: " + cameo); 58 | } 59 | 60 | console.log(JSON.stringify(doc)); 61 | */ 62 | 63 | 64 | #include 65 | #include 66 | 67 | WJRType 68 | WJE_GET_TYPE(WJElement parent) 69 | { 70 | return parent->child->next->type; 71 | } 72 | 73 | int main(int argc, char **argv) { 74 | WJElement doc = NULL; 75 | WJElement person = NULL; 76 | WJElement cameo = NULL; 77 | 78 | doc = WJEObject(NULL, NULL, WJE_NEW); 79 | WJEString(doc, "name", WJE_SET, "Serenity"); 80 | WJEString(doc, "class", WJE_SET, "firefly"); 81 | WJEArray(doc, "crew", WJE_SET); 82 | 83 | WJEObject(doc, "crew[$]", WJE_NEW); 84 | WJEString(doc, "crew[-1].name", WJE_SET, "Malcolm Reynolds"); 85 | WJEString(doc, "crew[-1].job", WJE_SET, "captain"); 86 | WJEInt64(doc, "crew[-1].born", WJE_SET, 2468); 87 | 88 | WJEObject(doc, "crew[$]", WJE_NEW); 89 | WJEString(doc, "crew[-1].name", WJE_SET, "Kaywinnet Lee Fry"); 90 | WJEString(doc, "crew[-1].job", WJE_SET, "mechanic"); 91 | WJEInt64(doc, "crew[-1].born", WJE_SET, 2494); 92 | 93 | WJEObject(doc, "crew[$]", WJE_NEW); 94 | WJEString(doc, "crew[-1].name", WJE_SET, "Jayne Cobb"); 95 | WJEString(doc, "crew[-1].job", WJE_SET, "public relations"); 96 | WJEInt64(doc, "crew[-1].born", WJE_SET, 2485); 97 | 98 | WJEArray(doc, "cameo", WJE_SET); 99 | WJEString(doc, "cameo[$]", WJE_NEW, "Battlestar Galactica"); 100 | WJEString(doc, "cameo[$]", WJE_NEW, "Star Wars Evasive Action"); 101 | WJEString(doc, "cameo[$]", WJE_NEW, "Dr. Horrible's Sing-Along Blog"); 102 | WJEString(doc, "cameo[$]", WJE_NEW, "Ready Player One"); 103 | 104 | WJEBool(doc, "shiny", WJE_SET, TRUE); 105 | 106 | WJEInt64(doc, "crew[].born == 2468", WJE_SET, 2486); /* note: awesome! */ 107 | WJECloseDocument(WJEGet(doc, "shiny", NULL)); 108 | 109 | while((person = _WJEObject(doc, "crew[]", WJE_GET, &person))) { 110 | printf("person Type is %c\n", WJE_GET_TYPE(person)); 111 | } 112 | while((cameo = WJEGet(doc, "cameo[]", cameo))) { 113 | printf("Cameo: %s\n", WJEString(cameo, NULL, WJE_GET, "")); 114 | } 115 | 116 | WJEDump(doc); 117 | WJECloseDocument(doc); 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /example/layout.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "layout", 3 | "headers": { 4 | "msg_id": "DSCS1385112923586" 5 | }, 6 | "obj": { 7 | "name": "test", 8 | "status": "draft", 9 | "orientation": "landscape", 10 | "widget": [] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example/layout.schema: -------------------------------------------------------------------------------- 1 | { 2 | "name": "layout schema check", 3 | "type": "object", 4 | "properties": { 5 | "_id": { 6 | "type": "string", 7 | "required": true 8 | }, 9 | "name": { 10 | "type": "string", 11 | "required": true 12 | }, 13 | "template": { 14 | "type": "string", 15 | }, 16 | "orientation": { 17 | "type": "string", 18 | "enum": [ 19 | "portrait", 20 | "landscape" 21 | ], 22 | "required": true 23 | }, 24 | "status": { 25 | "type": "string", 26 | "enum": [ 27 | "draft", 28 | "ready" 29 | ], 30 | "default": "ready", 31 | "required": true 32 | }, 33 | "ts": { 34 | "type": "string", 35 | "required": true 36 | }, 37 | "widgets": { 38 | "type": "array", 39 | "required": true, 40 | "items": { 41 | "name": "widget setting", 42 | "type": "object", 43 | "additionalProperties": false, 44 | "properties": { 45 | "widget": { 46 | "type": "string", 47 | "required": true 48 | }, 49 | "name": { 50 | "type": "string", 51 | "description": "Must be the widget name( package name )", 52 | "required": true 53 | }, 54 | "h": { 55 | "type": "number", 56 | "description": " 0.0 ~ 1.0", 57 | "required": true 58 | }, 59 | "w": { 60 | "type": "number", 61 | "description": " 0.0 ~ 1.0", 62 | "required": true 63 | }, 64 | "top": { 65 | "type": "number", 66 | "description": " 0.0 ~ 1.0", 67 | "required": true 68 | }, 69 | "left": { 70 | "type": "number", 71 | "description": " 0.0 ~ 1.0", 72 | "required": true 73 | }, 74 | "_id": { 75 | "type": "string", 76 | "required": true 77 | }, 78 | "param": { 79 | "type": "array", 80 | "items": { 81 | "type": "object", 82 | "additionalProperties": false, 83 | "properties": { 84 | "name": { 85 | "type": "string", 86 | "required": true 87 | }, 88 | "val": { 89 | "required": true 90 | }, 91 | 92 | "_id": { 93 | "type": "string", 94 | "required": true 95 | } 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /example/validate.c: -------------------------------------------------------------------------------- 1 | /* 2 | validate.c: a proof-of-concept json-schema validator 3 | thanks to xiaoping.x.liu@intel.com 4 | 5 | after installing libwjelement (and running ldconfig if needed)... 6 | gcc -o validate -lwjelement -lwjreader validate.c 7 | or 8 | gcc -o validate `pkg-config --libs wjelement` validate.c 9 | */ 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | /* 21 | callback: load more schema from files based on "name" and a pattern argument 22 | */ 23 | static WJElement schema_load(const char *name, void *client, 24 | const char *file, const int line) { 25 | char *format; 26 | char *path; 27 | FILE *schemafile; 28 | WJReader readschema; 29 | WJElement schema; 30 | 31 | schema = NULL; 32 | if(client && name) { 33 | format = (char *)client; 34 | path = malloc(strlen(format) + strlen(name)); 35 | sprintf(path, format, name); 36 | 37 | if ((schemafile = fopen(path, "r"))) { 38 | if((readschema = WJROpenFILEDocument(schemafile, NULL, 0))) { 39 | schema = WJEOpenDocument(readschema, NULL, NULL, NULL); 40 | } else { 41 | fprintf(stderr, "json document failed to open: '%s'\n", path); 42 | } 43 | fclose(schemafile); 44 | } else { 45 | fprintf(stderr, "json file not found: '%s'\n", path); 46 | } 47 | free(path); 48 | } 49 | WJEDump(schema); 50 | return schema; 51 | } 52 | 53 | /* 54 | callback: cleanup/free open schema 55 | */ 56 | static void schema_free(WJElement schema, void *client) { 57 | WJECloseDocument(schema); 58 | return; 59 | } 60 | 61 | /* 62 | callback: plop validation errors to stderr 63 | */ 64 | static void schema_error(void *client, const char *format, ...) { 65 | va_list ap; 66 | va_start(ap, format); 67 | vfprintf(stderr, format, ap); 68 | va_end(ap); 69 | fprintf(stderr, "\n"); 70 | } 71 | 72 | 73 | int main(int argc, char **argv) { 74 | int ret = 0; 75 | FILE *jsonfile = NULL; 76 | FILE *schemafile = NULL; 77 | WJReader readjson = NULL; 78 | WJReader readschema = NULL; 79 | WJElement json = NULL; 80 | WJElement schema = NULL; 81 | char *format = NULL; 82 | 83 | if(argc != 3 && argc != 4) { 84 | printf("usage:\n"); 85 | printf("\t%s \n", argv[0]); 86 | printf("\t%s \n", argv[0]); 87 | printf(": \"path/to/%%s.json\" additional schemas\n"); 88 | return 255; 89 | } 90 | 91 | if(!(jsonfile = fopen(argv[1], "r"))) { 92 | fprintf(stderr, "json file not found: '%s'\n", argv[1]); 93 | ret = 1; 94 | } else if(!(schemafile = fopen(argv[2], "r"))) { 95 | fprintf(stderr, "schema file not found: '%s'\n", argv[2]); 96 | ret = 2; 97 | } 98 | if(argc == 4) { 99 | format = argv[3]; 100 | } else { 101 | format = NULL; 102 | } 103 | 104 | if(jsonfile && schemafile) { 105 | if(!(readjson = WJROpenFILEDocument(jsonfile, NULL, 0)) || 106 | !(json = WJEOpenDocument(readjson, NULL, NULL, NULL))) { 107 | fprintf(stderr, "json could not be read.\n"); 108 | ret = 3; 109 | } else if(!(readschema = WJROpenFILEDocument(schemafile, NULL, 0)) || 110 | !(schema = WJEOpenDocument(readschema, NULL, NULL, NULL))) { 111 | fprintf(stderr, "schema could not be read.\n"); 112 | ret = 4; 113 | } 114 | } 115 | 116 | if(json && schema) { 117 | WJEDump(json); 118 | printf("json: %s\n", readjson->depth ? "bad" : "good"); 119 | WJEDump(schema); 120 | printf("schema: %s\n", readschema->depth ? "bad" : "good"); 121 | 122 | if(WJESchemaValidate(schema, json, schema_error, 123 | schema_load, schema_free, format)) { 124 | printf("validation: PASS\n"); 125 | } else { 126 | printf("validation: FAIL\n"); 127 | } 128 | } 129 | 130 | if(json) WJECloseDocument(json); 131 | if(schema) WJECloseDocument(schema); 132 | if(readjson) WJRCloseDocument(readjson); 133 | if(readschema) WJRCloseDocument(readschema); 134 | if(jsonfile) fclose(jsonfile); 135 | if(schemafile) fclose(schemafile); 136 | return ret; 137 | } 138 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | FILE(GLOB INCLUDES_HEADERS *.h ) 2 | LIST(REMOVE_ITEM INCLUDES_HEADERS ${PROJECT_SOURCE_DIR}/include/config.h) 3 | INSTALL(FILES ${INCLUDES_HEADERS} DESTINATION include/) 4 | -------------------------------------------------------------------------------- /include/memmgr.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | /**************************************************************************** 19 | * stub replacement for Messaging Architects' internal MemMgr library 20 | ****************************************************************************/ 21 | 22 | #ifndef MEMMGR_H 23 | #define MEMMGR_H 24 | 25 | #include "xpl.h" 26 | #include 27 | #include 28 | #include 29 | 30 | #ifndef asprintf 31 | EXPORT int asprintf(char **strp, const char *fmt, ...); 32 | #else 33 | #define HAS_ASPRINTF 34 | #endif 35 | 36 | #define MemAssert(p) 37 | 38 | #define MemoryManagerOpen( c ) 39 | #define MemoryManagerOpenEx( c, cfg ) 40 | #define MemoryManagerClose( c ) 41 | #define MemUpdateOwner( p, f, l ) 42 | #define MemCopyOwner( d, s ) 43 | #define MemGetOwner( p, f, l ) 44 | #define MemMalloc( s ) malloc( (s) ) 45 | #define MemMallocWait( s ) malloc( (s) ) 46 | #define MemFree( p ) free( (p) ) 47 | #define MemFreeEx( p, f, l ) free( (p) ) 48 | #define MemRelease( p ) do { free( (*p) ); (*p) = NULL; } while (0) 49 | #define MemReleaseEx( p, f, l ) do { free( (*p) ); (*p) = NULL; } while (0) 50 | #define MemRealloc( p, s ) realloc( (p), (s) ) 51 | #define MemReallocWait( p, s ) realloc( (p), (s) ) 52 | #define MemStrdup( s ) strdup( (s) ) 53 | #define MemStrdupWait( s ) strdup( (s) ) 54 | #define MemStrndup( s, m ) strndup( (s), (m) ) 55 | #define MemStrndupWait( s, m ) strndup( (s), (m) ) 56 | #define MemSprintf( f, ... ) sprintf( (f), __VA_ARGS__ ) 57 | #define MemAsprintf( p, f, ... ) (void)!asprintf( (p), (f), __VA_ARGS__ ) 58 | #define MemCalloc( c, s ) calloc( (c), (s) ) 59 | #define MemCallocWait( c, s ) calloc( (c), (s) ) 60 | 61 | #define MemGenerateReports() 62 | #define MemDumpPools( f ) 63 | #define MemConsumer() 64 | 65 | EXPORT void * MemMallocEx(void *ptr, size_t size, size_t *actual, XplBool wait, XplBool zero); 66 | 67 | #endif // MEMMGR_H 68 | -------------------------------------------------------------------------------- /include/nmutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | /**************************************************************************** 19 | * stub replacement for Messaging Architects' internal netmail utility library 20 | ****************************************************************************/ 21 | #include "xpl.h" 22 | #include 23 | #include 24 | 25 | 26 | #ifndef NMUTIL_H 27 | #define NMUTIL_H 28 | 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/wjelement.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | #ifndef WARP_JSON_ELEMENT_H 19 | #define WARP_JSON_ELEMENT_H 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* 29 | WJElement Interfaces 30 | 31 | The WJElement interfaces allow you to load an entire JSON document into 32 | memory and to then access elements within it more easily. 33 | 34 | Elements within the hierarchy of a JSON document can be referenced using a 35 | path. Multiple levels of hierarchy can be referenced to find any element 36 | below the provided container. The following rules apply to any WJE 37 | functions that take a path argument. 38 | 39 | A child may be referenced with a alpha-numeric name, or a subscript within 40 | square brackets: 41 | foo 42 | ["foo"] 43 | 44 | Additional levels of heirarchy can be referenced by appending an additional 45 | subscript, or appending a dot and an additional alpha-numeric name: 46 | one.two.three.four 47 | one["two"]["three"].four 48 | 49 | Subscripts may contain double quoted names. Any special characters, 50 | (including .[]*?"'\) can be included by prefixing with a \. 51 | foo["bar.smeg"] 52 | foo["something with a \"quote\""] 53 | 54 | Subscripts may contain single quoted names, which behave as double quoted 55 | names but also allow for * and ? wild card substitution: 56 | foo['bar.*'] 57 | 58 | Subscripts may reference an item by it's offset in an array (or object): 59 | foo[0] 60 | foo[3] 61 | 62 | Negative offsets are wrapped to the end of the array (or object) meaning 63 | that [-1] references the last item. 64 | 65 | Subscripts may reference a range of offsets by providing 2 offsets separated 66 | by a colon: 67 | foo[2:5] 68 | 69 | Subscripts may reference a set of items by separating offsets, offset, 70 | ranges, double quoted and single quoted values: 71 | foo[2,4:6,'bar.*', "smeg"] 72 | 73 | An empty subscript may be specified to reference all children. 74 | [] 75 | 76 | A subscript of $ may be specified in actions perform creations to reference 77 | the item after the end of an array. This allows appending to an array. 78 | [$] 79 | 80 | A subscript may be prefixed by an | character to indicate that the subscript 81 | is optional. The portion of the selector from the | on will be ignored if 82 | there is a match and that match has no children. 83 | 84 | For example, if an element named foo may either be a string or an array of 85 | strings you can enumerate all values using a selector of: 86 | foo|[] 87 | 88 | A NULL path refers to the container itself. 89 | 90 | A path may end in a condition. The condition consists of an operator and a 91 | value. The value may be a number, a double quoted string, or a single 92 | quoted string. If a single quoted string is used it may contain * and ? 93 | wild cards. 94 | 95 | The following operators are supported for any value: 96 | ==, != 97 | 98 | A number value may also use the following operators: 99 | <, >, <=, >= 100 | 101 | Example: 102 | foo.bar <= 3 103 | foo.bar != 'foo*' 104 | foo.bar != "one" 105 | 106 | A condition may be separated from a path with a ; character. 107 | 108 | In the following examples the object named "foo" will be returned if it has 109 | a child named "bar" that matches the condition. 110 | foo; bar <= 3 111 | foo; bar != 'foo*' 112 | foo; bar != "one" 113 | */ 114 | 115 | typedef struct WJElementPublic 116 | { 117 | char *name; 118 | WJRType type; 119 | 120 | struct WJElementPublic *next; 121 | struct WJElementPublic *prev; 122 | 123 | struct WJElementPublic *child; 124 | struct WJElementPublic *last; 125 | struct WJElementPublic *parent; 126 | 127 | /* The number of children */ 128 | int count; 129 | 130 | /* The length if the type is WJR_TYPE_STRING */ 131 | size_t length; 132 | 133 | /* 134 | A count of changes that have been performed on this element, which can 135 | be reset by the consumer. 136 | */ 137 | int changes; 138 | 139 | void *client; 140 | 141 | /* 142 | If set then this freecb will be called before actually free'ing a 143 | WJElement. If it returns FALSE then the WJElement will NOT be free'd. 144 | 145 | This can be used to allow caching of objects. If used in this way then 146 | the consumer that set the callback is responsible for ensuring that it 147 | does get free'd correctly at the correct time. 148 | */ 149 | XplBool (* freecb)(struct WJElementPublic *); 150 | 151 | /* 152 | If set then this callback will be called when this element is written 153 | with WJEWriteDocument() and the callback is responsible for writing the 154 | JSON for this node and it's children. 155 | */ 156 | XplBool (* writecb)(struct WJElementPublic *, WJWriter writer, char *name); 157 | } WJElementPublic; 158 | typedef WJElementPublic * WJElement; 159 | 160 | /* 161 | Parse the provided JSON document and return the new WJElement 162 | 163 | The _WJEParse version can be used to parse a document with a non-standard 164 | quote character. This allows easy parsing of simple documents directly in a 165 | C source file without having to escape double quote characters. Example: 166 | doc = _WJEParse("{ 'foo': true, 'bar': 'yup' }", '\''); 167 | */ 168 | #define WJEFromString(j) __WJEFromString((j), '"', __FILE__, __LINE__) 169 | #define WJEParse(j) __WJEFromString((j), '"', __FILE__, __LINE__) 170 | #define _WJEFromString(j, q) __WJEFromString((j), (q), __FILE__, __LINE__) 171 | #define _WJEParse(j, q) __WJEFromString((j), (q), __FILE__, __LINE__) 172 | EXPORT WJElement __WJEFromString(const char *json, char quote, const char *file, const int line); 173 | 174 | /* 175 | Allocate a string and write the JSON source for the provided WJElement to 176 | it. The consumer is responsible for calling MemFree() on the result. 177 | 178 | If the consumer and WJE are linked to separate memory libraries, it may be 179 | necessary to call WJEMemFree() instead. 180 | */ 181 | EXPORT char * _WJEToString(WJElement document, XplBool pretty, const char *file, const int line); 182 | #define WJEToString( d, p ) _WJEToString( (d), (p), __FILE__, __LINE__) 183 | 184 | /* Read or write a WJElement to a file by path */ 185 | EXPORT WJElement WJEFromFile(const char *path); 186 | EXPORT XplBool WJEToFile(WJElement document, XplBool pretty, const char *path); 187 | 188 | /* 189 | Load a WJElement object from the provided WJReader 190 | 191 | If a load callback is provided then it will be called before adding any new 192 | children, allowing the consumer to leave ignore specific elements of the 193 | hierarchy. 194 | */ 195 | typedef XplBool (* WJELoadCB)(WJElement parent, char *path, void *data, const char *file, const int line); 196 | EXPORT WJElement _WJEOpenDocument(WJReader reader, char *where, WJELoadCB loadcb, void *data, const char *file, const int line); 197 | #define WJEOpenDocument(r, w, lcb, d) _WJEOpenDocument((r), (w), (lcb), (d), __FILE__, __LINE__) 198 | 199 | /* Write a WJElement object to the provided WJWriter */ 200 | typedef XplBool (* WJEWriteCB)(WJElement node, WJWriter writer, void *data); 201 | EXPORT XplBool _WJEWriteDocument(WJElement document, WJWriter writer, char *name, 202 | WJEWriteCB precb, WJEWriteCB postcb, void *data); 203 | #define WJEWriteDocument(d, w, n) _WJEWriteDocument((d), (w), (n), NULL, NULL, NULL) 204 | 205 | /* Write a WJElement object to the provided FILE* */ 206 | EXPORT void WJEWriteFILE(WJElement document, FILE* fd); 207 | 208 | /* Read a WJElement object from the provided FILE* */ 209 | EXPORT WJElement WJEReadFILE(FILE* fd); 210 | 211 | /* Destroy a WJElement object */ 212 | EXPORT XplBool _WJECloseDocument(WJElement document, const char *file, const int line); 213 | #define WJECloseDocument(d) _WJECloseDocument((d), __FILE__, __LINE__) 214 | 215 | /* 216 | WJECloseDocument is also used to delete/remove an item from a parent 217 | document: 218 | WJECloseDocument(WJEGet(...)); 219 | */ 220 | 221 | /* 222 | Remove any items matching the specified selector 223 | */ 224 | #define WJERemove(d, p) \ 225 | while ((WJECloseDocument(WJEGet((d), (p), NULL)))) { ; } 226 | 227 | /* Duplicate an existing WJElement */ 228 | typedef XplBool (* WJECopyCB)(WJElement destination, WJElement object, void *data, const char *file, const int line); 229 | EXPORT WJElement _WJECopyDocument(WJElement to, WJElement from, WJECopyCB loadcb, void *data, const char *file, const int line); 230 | #define WJECopyDocument(t, f, lcb, d) _WJECopyDocument((t), (f), (lcb), (d), __FILE__, __LINE__) 231 | 232 | 233 | /* Remove a WJElement from it's parent (and siblings) */ 234 | EXPORT XplBool _WJEDetach(WJElement document, const char *file, const int line); 235 | #define WJEDetach( d ) _WJEDetach( (d), __FILE__, __LINE__ ) 236 | #define WJEDettach( d ) _WJEDetach( (d), __FILE__, __LINE__ ) 237 | 238 | /* Add a document to another document as a child */ 239 | EXPORT XplBool WJEAttach(WJElement container, WJElement document); 240 | 241 | /* Rename an element */ 242 | EXPORT XplBool WJERename(WJElement document, const char *name); 243 | 244 | /* Merge all fields from one object to another */ 245 | EXPORT XplBool WJEMergeObjects(WJElement to, WJElement from, XplBool overwrite); 246 | 247 | /* 248 | Find the first element within the hierarchy of a WJElement that matches the 249 | specified path. 250 | 251 | If 'last' is non-NULL then the next match will be returned instead, allowing 252 | enumeration of multiple matching elements. 253 | */ 254 | EXPORT WJElement _WJEGet(WJElement container, char *path, WJElement last, const char *file, const int line); 255 | #define WJEGet( c, p, l ) _WJEGet( (c), (p), (l), __FILE__, __LINE__ ) 256 | 257 | typedef enum { 258 | /* 259 | Return the value of an element. If the element does not exist then the 260 | provided default value will be returned. 261 | */ 262 | WJE_GET = 0, 263 | 264 | /* 265 | Assign the specified value to an element. If the element does not exist 266 | then it will be created. 267 | 268 | If the element can not be created then an appropriate value will be 269 | returned to indicate the error. 270 | 271 | When applicable a NULL will be returned. Otherwise a value that does 272 | not match the requested value will be returned. 273 | */ 274 | WJE_SET = 1, 275 | 276 | /* 277 | Create a new element and assign it the specified value. 278 | 279 | If an element already exists then it will not be modified, and the value 280 | of that existing element will be returned. 281 | */ 282 | WJE_NEW = 2, 283 | 284 | /* 285 | Assign the specified value to an existing element, and return the value 286 | if successful. 287 | 288 | If the element does not exist then no elements are created or modified. 289 | When applicable a NULL will be returned. Otherwise a value that does 290 | not match the requested value will be returned. 291 | */ 292 | WJE_MOD = 3 293 | } WJEAction; 294 | 295 | /* 296 | The following flags can be OR'ed with a WJEAction value for any function 297 | that takes a WJEAction: 298 | */ 299 | #define WJE_IGNORE_CASE 0x00010000 300 | 301 | 302 | // TODO Remove this. WJE_PUT was renamed to WJE_MOD. 303 | #define WJE_PUT WJE_MOD 304 | 305 | #define _WJEString( container, path, action, last, value) __WJEString( (container), (path), (action), (last), (value), __FILE__, __LINE__) 306 | #define WJEString( container, path, action, value) __WJEString( (container), (path), (action), NULL, (value), __FILE__, __LINE__) 307 | #define _WJEStringN(container, path, action, last, value, len) __WJEStringN( (container), (path), (action), (last), (value), (len), __FILE__, __LINE__) 308 | #define WJEStringN(container, path, action, value, len) __WJEStringN( (container), (path), (action), NULL, (value), (len), __FILE__, __LINE__) 309 | #define _WJEObject( container, path, action, last) __WJEObject( (container), (path), (action), (last), __FILE__, __LINE__) 310 | #define WJEObject( container, path, action) __WJEObject( (container), (path), (action), NULL, __FILE__, __LINE__) 311 | #define _WJEBool( container, path, action, last, value) __WJEBool( (container), (path), (action), (last), (value), __FILE__, __LINE__) 312 | #define WJEBool( container, path, action, value) __WJEBool( (container), (path), (action), NULL, (value), __FILE__, __LINE__) 313 | #define _WJEArray( container, path, action, last) __WJEArray( (container), (path), (action), (last), __FILE__, __LINE__) 314 | #define WJEArray( container, path, action) __WJEArray( (container), (path), (action), NULL, __FILE__, __LINE__) 315 | #define _WJENull( container, path, action, last) __WJENull( (container), (path), (action), (last), __FILE__, __LINE__) 316 | #define WJENull( container, path, action) __WJENull( (container), (path), (action), NULL, __FILE__, __LINE__) 317 | #define _WJEInt32( container, path, action, last, value) __WJEInt32( (container), (path), (action), (last), (value), __FILE__, __LINE__) 318 | #define WJEInt32( container, path, action, value) __WJEInt32( (container), (path), (action), NULL, (value), __FILE__, __LINE__) 319 | #define _WJENumber( container, path, action, last, value) __WJEInt32( (container), (path), (action), (last), (value), __FILE__, __LINE__) 320 | #define WJENumber( container, path, action, value) __WJEInt32( (container), (path), (action), NULL, (value), __FILE__, __LINE__) 321 | #define _WJEUInt32( container, path, action, last, value) __WJEUInt32( (container), (path), (action), (last), (value), __FILE__, __LINE__) 322 | #define WJEUInt32( container, path, action, value) __WJEUInt32( (container), (path), (action), NULL, (value), __FILE__, __LINE__) 323 | #define _WJEInt64( container, path, action, last, value) __WJEInt64( (container), (path), (action), (last), (value), __FILE__, __LINE__) 324 | #define WJEInt64( container, path, action, value) __WJEInt64( (container), (path), (action), NULL, (value), __FILE__, __LINE__) 325 | #define _WJEUInt64( container, path, action, last, value) __WJEUInt64( (container), (path), (action), (last), (value), __FILE__, __LINE__) 326 | #define WJEUInt64( container, path, action, value) __WJEUInt64( (container), (path), (action), NULL, (value), __FILE__, __LINE__) 327 | #define _WJEDouble( container, path, action, last, value) __WJEDouble( (container), (path), (action), (last), (value), __FILE__, __LINE__) 328 | #define WJEDouble( container, path, action, value) __WJEDouble( (container), (path), (action), NULL, (value), __FILE__, __LINE__) 329 | 330 | EXPORT XplBool __WJEBool( WJElement container, const char *path, WJEAction action, WJElement *last, XplBool value, const char *file, const int line); 331 | EXPORT char * __WJEString( WJElement container, const char *path, WJEAction action, WJElement *last, const char *value, const char *file, const int line); 332 | EXPORT char * __WJEStringN( WJElement container, const char *path, WJEAction action, WJElement *last, const char *value, size_t len,const char *file, const int line); 333 | EXPORT WJElement __WJEObject( WJElement container, const char *path, WJEAction action, WJElement *last, const char *file, const int line); 334 | EXPORT WJElement __WJEArray( WJElement container, const char *path, WJEAction action, WJElement *last, const char *file, const int line); 335 | EXPORT WJElement __WJENull( WJElement container, const char *path, WJEAction action, WJElement *last, const char *file, const int line); 336 | EXPORT int32 __WJEInt32( WJElement container, const char *path, WJEAction action, WJElement *last, int32 value, const char *file, const int line); 337 | EXPORT uint32 __WJEUInt32( WJElement container, const char *path, WJEAction action, WJElement *last, uint32 value, const char *file, const int line); 338 | EXPORT int64 __WJEInt64( WJElement container, const char *path, WJEAction action, WJElement *last, int64 value, const char *file, const int line); 339 | EXPORT uint64 __WJEUInt64( WJElement container, const char *path, WJEAction action, WJElement *last, uint64 value, const char *file, const int line); 340 | EXPORT double __WJEDouble( WJElement container, const char *path, WJEAction action, WJElement *last, double value, const char *file, const int line); 341 | 342 | /* 343 | The following functions are identical to the non F variants except that the 344 | path argument has been moved to the end and is used as a format string. For 345 | example if you need a value by index, and that index is stored in the 346 | variable x: 347 | val = WJENumberF(doc, WJE_GET, NULL, 0, "foo[%d]", x); 348 | */ 349 | EXPORT WJElement WJEGetF( WJElement container, WJElement last, const char *pathf, ...) XplFormatString(3, 4); 350 | EXPORT XplBool WJEBoolF( WJElement container, WJEAction action, WJElement *last, XplBool value, const char *pathf, ...) XplFormatString(5, 6); 351 | EXPORT char * WJEStringF( WJElement container, WJEAction action, WJElement *last, const char *value, const char *pathf, ...) XplFormatString(5, 6); 352 | EXPORT char * WJEStringNF(WJElement container, WJEAction action, WJElement *last, const char *value, size_t len, const char *pathf, ...) XplFormatString(6, 7); 353 | EXPORT WJElement WJEObjectF( WJElement container, WJEAction action, WJElement *last, const char *pathf, ...) XplFormatString(4, 5); 354 | EXPORT WJElement WJEArrayF( WJElement container, WJEAction action, WJElement *last, const char *pathf, ...) XplFormatString(4, 5); 355 | EXPORT WJElement WJENullF( WJElement container, WJEAction action, WJElement *last, const char *pathf, ...) XplFormatString(4, 5); 356 | EXPORT int32 WJEInt32F( WJElement container, WJEAction action, WJElement *last, int32 value, const char *pathf, ...) XplFormatString(5, 6); 357 | EXPORT uint32 WJEUInt32F( WJElement container, WJEAction action, WJElement *last, uint32 value, const char *pathf, ...) XplFormatString(5, 6); 358 | EXPORT int64 WJEInt64F( WJElement container, WJEAction action, WJElement *last, int64 value, const char *pathf, ...) XplFormatString(5, 6); 359 | EXPORT uint64 WJEUInt64F( WJElement container, WJEAction action, WJElement *last, uint64 value, const char *pathf, ...) XplFormatString(5, 6); 360 | EXPORT double WJEDoubleF( WJElement container, WJEAction action, WJElement *last, double value, const char *pathf, ...) XplFormatString(5, 6); 361 | 362 | 363 | 364 | /* 365 | Find, create or update an element by name instead of path. This allows 366 | access to elements that would be difficult to reference by path. 367 | 368 | Type specific actions may be done by passing the resulting WJElement and a 369 | NULL path to WJEBool(), WJENumber(), WJEString(), WJEObject(), WJEArray() or 370 | WJENull(). 371 | */ 372 | EXPORT WJElement _WJEChild(WJElement container, char *name, WJEAction action, const char *file, const int line); 373 | #define WJEChild(c, n, a) _WJEChild((c), (n), (a), __FILE__, __LINE__) 374 | 375 | 376 | /* 377 | Find, create or update an element by path regardless of type. 378 | 379 | Type specific actions may be done by passing the resulting WJElement and a 380 | NULL path to WJEBool(), WJENumber(), WJEString(), WJEObject(), WJEArray() or 381 | WJENull(). 382 | */ 383 | EXPORT WJElement _WJEAny(WJElement container, char *path, WJEAction action, WJElement last, const char *file, const int line); 384 | #define WJEAny(c, p, a, l) _WJEAny((c), (p), (a), (l), __FILE__, __LINE__) 385 | 386 | 387 | /* Calculate a hash for a document */ 388 | typedef int (* WJEHashCB)(void *context, void *data, size_t size); 389 | EXPORT void WJEHash(WJElement document, WJEHashCB update, void *context); 390 | 391 | /* WJElement Schema-related stuff */ 392 | /* 393 | Validate or find selectors according to schema. 394 | WJESchemaLoadCB callbacks are used to fetch schema as needed. 395 | WJESchemaFreeCB are called when schema is no longer needed. 396 | */ 397 | 398 | typedef WJElement (* WJESchemaLoadCB)(const char *name, void *client, const char *file, const int line); 399 | typedef void (* WJESchemaFreeCB)(WJElement schema, void *client); 400 | typedef void (* WJESchemaMatchCB)(WJElement schema, const char *selector, void *client); 401 | typedef void (* WJEErrCB)(void *client, const char *format, ...); 402 | 403 | /* 404 | Validate a document against a given schema. Additional schema will be loaded 405 | via the load callback if needed. Any validation errors will be reported, 406 | printf-style, to errcb. 407 | */ 408 | EXPORT XplBool WJESchemaValidate(WJElement schema, WJElement document, 409 | WJEErrCB err, WJESchemaLoadCB load, 410 | WJESchemaFreeCB freecb, void *client); 411 | 412 | /* 413 | Determine if a document does or does not implement a specific schema. 414 | Additional schema will be loaded via the load callback if needed. 415 | 416 | If a load callback is not provided then the object type will still be checked 417 | but it will not be considered a match if it is a type that extends the 418 | specifed type. 419 | */ 420 | EXPORT XplBool WJESchemaIsType(WJElement document, const char *type, 421 | WJESchemaLoadCB loadcb, WJESchemaFreeCB freecb, 422 | void *client); 423 | /* 424 | variation of WJESchemaIsType which acts on a schema name instead of a document 425 | */ 426 | EXPORT XplBool WJESchemaNameIsType(const char *describedby, const char *type, 427 | WJESchemaLoadCB loadcb, 428 | WJESchemaFreeCB freecb, void *client); 429 | /* 430 | calls back matchcb for each WJElement selector which will fetch a property 431 | of a given type and format, from a given document. The load callback will be 432 | used to load all necessary schema, starting with the document's "describedby". 433 | stripat-type wildcards may be used; "Date*" will find "date" and "date-time". 434 | */ 435 | EXPORT void WJESchemaGetSelectors(WJElement document, 436 | char *type, char *format, 437 | WJESchemaLoadCB load, 438 | WJESchemaFreeCB freecb, 439 | WJESchemaMatchCB matchcb, void *client); 440 | /* 441 | variation of WJESchemaGetSelectors which provides selectors that _could_ exist 442 | in objects of the given "describedby" schema name 443 | */ 444 | EXPORT void WJESchemaGetAllSelectors(char *describedby, 445 | char *type, char *format, 446 | WJESchemaLoadCB load, 447 | WJESchemaFreeCB freecb, 448 | WJESchemaMatchCB matchcb, void *client); 449 | 450 | 451 | EXPORT char * WJESchemaNameFindBacklink(char *describedby, const char *format, 452 | WJESchemaLoadCB loadcb, WJESchemaFreeCB freecb, 453 | void *client); 454 | 455 | EXPORT char * WJESchemaFindBacklink(WJElement document, const char *format, 456 | WJESchemaLoadCB loadcb, WJESchemaFreeCB freecb, 457 | void *client); 458 | 459 | EXPORT void WJESchemaFreeBacklink(char *backlink); 460 | 461 | 462 | /* Debug function that will write a document to stdout */ 463 | EXPORT void WJEDump(WJElement document); 464 | 465 | /* Debug function that will write a document to a file in the current dir */ 466 | EXPORT void WJEDumpFile(WJElement document); 467 | 468 | /* 469 | Our own MemFree wrapper, in cases where consumer code uses a different 470 | memory library than WJElement. 471 | It is always safe (but usually unnecessary) to use this instead of MemFree. 472 | */ 473 | EXPORT void WJEMemFree(void *mem); 474 | EXPORT void WJEMemRelease(void **mem); 475 | 476 | 477 | #ifdef __cplusplus 478 | } 479 | #endif 480 | 481 | #endif /* WARP_JSON_ELEMENT_H */ 482 | -------------------------------------------------------------------------------- /include/wjreader.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | #ifndef WARP_JSON_READER_H 19 | #define WARP_JSON_READER_H 20 | 21 | #include 22 | 23 | #ifdef __cplusplus 24 | extern "C"{ 25 | #endif 26 | 27 | /* 28 | WARP JSON Reader 29 | 30 | The WARP JSON Reader provides the ability to parse a JSON document as a 31 | stream. All parsing is done with a portion of the document loaded into a 32 | buffer, and the buffer is reloaded as needed. 33 | 34 | This allows the parser to be very fast, but does require that data in the 35 | document is accessed in the order of the document. 36 | */ 37 | 38 | typedef struct { 39 | uint32 depth; 40 | uint32 maxdepth; 41 | void *userdata; 42 | } WJReaderPublic; 43 | typedef WJReaderPublic * WJReader; 44 | 45 | typedef size_t (* WJReadCallback)(char *data, size_t length, size_t seen, void *userdata); 46 | 47 | /* 48 | Open a JSON document, and prepare to parse. A callback function must be 49 | provided which will be used to read data as it is needed. The callback is 50 | expected to load data into the provided buffer and return the number of 51 | bytes that where loaded. If the number of bytes loaded is less than the 52 | requested length then it is assumed that the end of the document has been 53 | reached. 54 | 55 | If a buffer is provided to WJROpenDocument() then that buffer will be used, 56 | rather than allocating a new buffer. The size of the buffer must be 57 | provided as buffersize. If a buffer is not provided then one will be 58 | allocated of size buffersize. 59 | 60 | If a buffersize of 0 is passed to WJROpenDocument then the default size will 61 | be used (4KB). Some data is kept in the buffer while parsing, such as 62 | element names and values. If the buffer is not large enough for these then 63 | the document will fail to be parsed and will be aborted. 64 | */ 65 | EXPORT WJReader _WJROpenDocument(WJReadCallback callback, void *userdata, char *buffer, size_t buffersize, uint32 maxdepth); 66 | #define WJROpenDocument(c, u, b, s) \ 67 | _WJROpenDocument((c), (u), (b), (s), 250) 68 | EXPORT XplBool WJRCloseDocument(WJReader doc); 69 | 70 | /* 71 | Return a string, which contains the name of the next element of the 72 | specified parent, prefixed by a single character that represents the type. 73 | The pointer returned may be used as the parent argument in future calls to 74 | WJRNext() in order to return the children of the current object. 75 | 76 | If the object's name is larger than the maxnamelen argument then it will be 77 | truncated. 78 | */ 79 | typedef enum { 80 | WJR_TYPE_OBJECT = 'O', 81 | WJR_TYPE_ARRAY = 'A', 82 | 83 | WJR_TYPE_STRING = 'S', 84 | WJR_TYPE_NUMBER = 'N', 85 | 86 | #ifdef WJE_DISTINGUISH_INTEGER_TYPE 87 | WJR_TYPE_INTEGER = 'I', 88 | #endif 89 | 90 | WJR_TYPE_BOOL = 'B', 91 | WJR_TYPE_TRUE = 'T', 92 | WJR_TYPE_FALSE = 'F', 93 | WJR_TYPE_NULL = '0', 94 | 95 | WJR_TYPE_UNKNOWN = '?' 96 | } WJRType; 97 | 98 | EXPORT char * WJRNext(char *parent, size_t maxnamelen, WJReader doc); 99 | 100 | /* 101 | Return the value of the last object returned by WJRNext(). The calling 102 | application is expected to know the type of the value, and call the 103 | appropriate function. When possible the value will be converted if it does 104 | not match the requested type. 105 | 106 | If the buffer is not large enough to contain the entire value then the 107 | WJRString() function may return a partial value. It may be called multiple 108 | times until a NULL is returned to ensure that the entire value has been 109 | read. 110 | */ 111 | EXPORT char * WJRStringEx(XplBool *complete, size_t *length, WJReader doc); 112 | #define WJRString(c, d) WJRStringEx((c), NULL, (d)) 113 | EXPORT XplBool WJRBoolean(WJReader doc); 114 | 115 | EXPORT int32 WJRInt32(WJReader doc); 116 | EXPORT uint32 WJRUInt32(WJReader doc); 117 | EXPORT int64 WJRInt64(WJReader doc); 118 | EXPORT uint64 WJRUInt64(WJReader doc); 119 | EXPORT double WJRDouble(WJReader doc); 120 | 121 | /* 122 | If the number type is not known, then attempt to read it as either a uint64 123 | or a double. 124 | 125 | If a decimal point is found in the number then TRUE will be returned and the 126 | value will be stored in *d. Otherwise FALSE will be returned and the value 127 | stored in *i. 128 | */ 129 | EXPORT XplBool WJRIntOrDouble(WJReader doc, uint64 *i, double *d); 130 | 131 | /* 132 | If the current element is a WJR_TYPE_NUMBER then this function can be used 133 | to determine if the value is negative or positive. If negative then TRUE 134 | will be returned. 135 | */ 136 | EXPORT XplBool WJRNegative(WJReader doc); 137 | 138 | 139 | /* 140 | An alternative method of opening a JSON document, which will provide a 141 | proper callback for reading the data from an open FILE *. 142 | 143 | As with the standard WJROpenDocument() a buffersize of 0 will use the 144 | default buffer size. 145 | */ 146 | EXPORT size_t WJRFileCallback(char *buffer, size_t length, size_t seen, void *data); 147 | #define WJROpenFILEDocument(jsonfile, buffer, buffersize) \ 148 | WJROpenDocument(WJRFileCallback, (jsonfile), (buffer), (buffersize)) 149 | 150 | /* 151 | An alternative method of opening a JSON document, which will provide a 152 | proper callback for reading from a pre-allocated buffer in memory. 153 | 154 | As with the standard WJROpenDocument() a buffersize of 0 will use the 155 | default buffer size. 156 | */ 157 | EXPORT size_t WJRMemCallback(char *buffer, size_t length, size_t seen, void *userdata); 158 | #define WJROpenMemDocument(json, buffer, buffersize) \ 159 | WJROpenDocument(WJRMemCallback, (json), (buffer), (buffersize)) 160 | 161 | #ifdef __cplusplus 162 | } 163 | #endif 164 | 165 | #endif /* WARP_JSON_READER_H */ 166 | 167 | -------------------------------------------------------------------------------- /include/wjwriter.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | #ifndef WARP_JSON_WRITER_H 19 | #define WARP_JSON_WRITER_H 20 | 21 | #include 22 | 23 | #ifdef __cplusplus 24 | extern "C"{ 25 | #endif 26 | 27 | /* 28 | WARP JSON Writer 29 | 30 | The WARP JSON Writer provides the ability to easily write a JSON document to 31 | a stream. All data formatting is done automatically. 32 | */ 33 | typedef size_t (* WJWriteCallback)(char *data, size_t size, void *writedata); 34 | 35 | typedef struct { 36 | XplBool pretty; 37 | 38 | /* 39 | Base may be set to 8, 10 (default), or 16. Using a base other than 10 40 | will result in a non standard JSON document which may not be read 41 | properly by all parsers. 42 | */ 43 | int base; 44 | 45 | /* 46 | If set to TRUE (enabled by default) then any character that can not be 47 | encoded as a UTF8 character will be written as \xXX where XX are a hex 48 | representation of the value. 49 | 50 | This can be disabled since it is non-standard JSON and will cause parse 51 | errors with some parsers. 52 | 53 | If disabled then any invalid characters will not be written to the 54 | document. 55 | */ 56 | XplBool escapeInvalidChars; 57 | 58 | struct { 59 | void *data; 60 | WJWriteCallback cb; 61 | } write; 62 | 63 | struct { 64 | void *data; 65 | void (* freecb)(void *data); 66 | } user; 67 | } WJWriterPublic; 68 | typedef WJWriterPublic* WJWriter; 69 | 70 | /* 71 | Open a stream that is ready to accept a JSON document. A callback function 72 | must be provided which will be used to write data as it is ready. 73 | 74 | A buffersize of 0 will disable write buffering entirely. The write buffer 75 | used will be at least the size requested, but may be larger. 76 | */ 77 | #define WJWOpenDocument(p, c, d) _WJWOpenDocument((p), (c), (d), (3 * 1024)) 78 | EXPORT WJWriter _WJWOpenDocument(XplBool pretty, WJWriteCallback callback, void *writedata, size_t buffersize); 79 | EXPORT XplBool WJWCloseDocument(WJWriter doc); 80 | 81 | /* 82 | Open an array. All objects that are direct children of the array MUST NOT 83 | be named. A value of NULL should be passed as name for any such values. 84 | 85 | When all values of the array have been written it can be closed with 86 | WJWCloseArray(). 87 | */ 88 | EXPORT XplBool WJWOpenArray(char *name, WJWriter doc); 89 | EXPORT XplBool WJWCloseArray(WJWriter doc); 90 | 91 | /* 92 | Open an object. All objects that are direct children of the object MUST be 93 | named. A value of NULL should NOT be passed as name for any such values. 94 | 95 | When all values of the object have been written it can be closed with 96 | WJWCloseObject(). 97 | */ 98 | EXPORT XplBool WJWOpenObject(char *name, WJWriter doc); 99 | EXPORT XplBool WJWCloseObject(WJWriter doc); 100 | 101 | /* 102 | Write a value to the document. If any values are written that are a direct 103 | child of an object then a non-NULL name MUST be provided. If any values are 104 | written that are a direct child of an array then a non-NULL name MUST NOT be 105 | provided. 106 | */ 107 | EXPORT XplBool WJWStringN(char *name, char *value, size_t length, XplBool done, WJWriter doc); 108 | EXPORT XplBool WJWString(char *name, char *value, XplBool done, WJWriter doc); 109 | EXPORT XplBool WJWBoolean(char *name, XplBool value, WJWriter doc); 110 | EXPORT XplBool WJWNull(char *name, WJWriter doc); 111 | 112 | EXPORT XplBool WJWInt32(char *name, int32 value, WJWriter doc); 113 | EXPORT XplBool WJWUInt32(char *name, uint32 value, WJWriter doc); 114 | EXPORT XplBool WJWInt64(char *name, int64 value, WJWriter doc); 115 | EXPORT XplBool WJWUInt64(char *name, uint64 value, WJWriter doc); 116 | EXPORT XplBool WJWDouble(char *name, double value, WJWriter doc); 117 | 118 | /* 119 | Write a raw pre-formatted value to the document. It is up to the caller to 120 | ensure that the data is properly formatted and complete. 121 | */ 122 | EXPORT XplBool WJWRawValue(char *name, char *value, XplBool done, WJWriter doc); 123 | 124 | /* 125 | An alternative method of opening a JSON document for writing, which will 126 | provide a proper callback for writing the data to an open FILE *. 127 | */ 128 | EXPORT size_t WJWFileCallback(char *buffer, size_t length, void *data); 129 | #define WJWOpenFILEDocument(pretty, file) _WJWOpenDocument((pretty), WJWFileCallback, (file), 0) 130 | 131 | /* 132 | An alternative method of opening a JSON document for writing, which will 133 | provide a proper callback for allocating and writing to a memory allocation. 134 | */ 135 | EXPORT WJWriter WJWOpenMemDocument(XplBool pretty, char **mem); 136 | 137 | #ifdef __cplusplus 138 | } 139 | #endif 140 | 141 | #endif /* WARP_JSON_WRITER_H */ 142 | 143 | -------------------------------------------------------------------------------- /include/xpl.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | /**************************************************************************** 19 | * stub replacement for netmail's internal Xpl library 20 | ****************************************************************************/ 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | #ifndef XPL_H 29 | #define XPL_H 30 | 31 | 32 | #ifdef _WIN32 33 | # define WIN_CDECL __cdecl 34 | # define WIN_STDCALL __stdcall 35 | # ifndef COMPILE_AS_STATIC 36 | # define EXPORT __declspec(dllexport) 37 | # define IMPORT __declspec(dllimport) 38 | # else 39 | # define EXPORT 40 | # define IMPORT 41 | #endif 42 | # define INLINE __inline 43 | #else 44 | # define WIN_CDECL 45 | # define WIN_STDCALL 46 | # define EXPORT 47 | # define IMPORT 48 | # define INLINE __inline 49 | 50 | # include 51 | # include 52 | # include 53 | #endif 54 | 55 | 56 | /* xpldefs.h */ 57 | 58 | #ifndef xpl_min 59 | #define xpl_min(a, b) (((a) < (b))? (a): (b)) 60 | #endif 61 | 62 | #ifndef xpl_max 63 | #define xpl_max(a, b) (((a) > (b))? (a): (b)) 64 | #endif 65 | 66 | 67 | /* xpltypes.h */ 68 | 69 | typedef int XplBool; 70 | 71 | #ifndef WIN32 72 | typedef long LONG; 73 | #endif 74 | 75 | #ifndef FALSE 76 | # define FALSE (0) 77 | #endif 78 | 79 | #ifndef TRUE 80 | # define TRUE (!FALSE) 81 | #endif 82 | 83 | #ifndef _UNSIGNED_INT_64 84 | #define _UNSIGNED_INT_64 85 | #ifdef __WATCOMC__ 86 | typedef unsigned __int64 uint64; 87 | #elif UINT64_MAX == 18446744073709551615ULL 88 | typedef uint64_t uint64; 89 | #elif ULLONG_MAX == 18446744073709551615ULL 90 | typedef unsigned long long uint64; 91 | #elif ULONG_MAX == 18446744073709551615ULL 92 | typedef unsigned long uint64; 93 | #elif UINT_MAX == 18446744073709551615ULL 94 | typedef unsigned int uint64; 95 | #elif USHRT_MAX == 18446744073709551615ULL 96 | typedef unsigned short uint64; 97 | #else 98 | #error "Can't determine the size of uint64" 99 | #endif 100 | #endif 101 | 102 | #ifndef _SIGNED_INT_64 103 | #define _SIGNED_INT_64 104 | #ifdef __WATCOMC__ 105 | typedef signed __int64 int64; 106 | #elif INT64_MAX == 9223372036854775807LL 107 | typedef int64_t int64; 108 | #elif LLONG_MAX == 9223372036854775807LL 109 | typedef signed long long int64; 110 | #elif LONG_MAX == 9223372036854775807LL 111 | typedef signed long int64; 112 | #elif INT_MAX == 9223372036854775807LL 113 | typedef signed int int64; 114 | #elif SHRT_MAX == 9223372036854775807LL 115 | typedef signed short int64; 116 | #else 117 | #error "Can't determine the size of int64" 118 | #endif 119 | #endif 120 | 121 | #ifndef _UNSIGNED_INT_32 122 | #define _UNSIGNED_INT_32 123 | #if ULONG_MAX == 4294967295UL 124 | typedef unsigned long uint32; 125 | #elif UINT_MAX == 4294967295UL 126 | typedef unsigned int uint32; 127 | #elif USHRT_MAX == 4294967295UL 128 | typedef unsigned short uint32; 129 | #else 130 | #error "Can't determine the size of uint32" 131 | #endif 132 | #endif 133 | 134 | #ifndef _SIGNED_INT_32 135 | #define _SIGNED_INT_32 136 | #if LONG_MAX == 2147483647L 137 | typedef signed long int32; 138 | #elif INT_MAX == 2147483647L 139 | typedef signed int int32; 140 | #elif SHRT_MAX == 2147483647L 141 | typedef signed short int32; 142 | #else 143 | #error "Can't determine the size of int32" 144 | #endif 145 | #endif 146 | 147 | #ifndef _UNSIGNED_INT_16 148 | #define _UNSIGNED_INT_16 149 | #if USHRT_MAX == 65535U 150 | typedef unsigned short uint16; 151 | #elif UCHAR_MAX == 65535U 152 | typedef signed char uint16; 153 | #else 154 | #error "Can't determine the size of uint16" 155 | #endif 156 | #endif 157 | 158 | #ifndef _SIGNED_INT_16 159 | #define _SIGNED_INT_16 160 | #if SHRT_MAX == 32767 161 | typedef signed short int16; 162 | #elif SCHAR_MAX == 32767 163 | typedef unsigned char uint16; 164 | #else 165 | #error "Can't determine the size of int16" 166 | #endif 167 | #endif 168 | 169 | #ifndef _UNSIGNED_INT_8 170 | #define _UNSIGNED_INT_8 171 | #if UCHAR_MAX == 255U 172 | typedef unsigned char uint8; 173 | #else 174 | #error "Can't determine the size of uint8" 175 | #endif 176 | #endif 177 | 178 | #ifndef _SIGNED_INT_8 179 | #define _SIGNED_INT_8 180 | #if SCHAR_MAX == 127 181 | typedef signed char int8; 182 | #else 183 | #error "Can't determine the size of int8" 184 | #endif 185 | #endif 186 | 187 | 188 | /* xplutil.h */ 189 | 190 | #if defined __GNUC__ 191 | #define XplFormatString(formatStringIndex, firstToCheck) __attribute__ ((format (printf, formatStringIndex, firstToCheck))) 192 | #else 193 | #define XplFormatString(formatStringIndex, firstToCheck) 194 | #endif 195 | 196 | # define DebugAssert( x ) 197 | 198 | # if defined(_MSC_VER) 199 | # define stricmp(a,b) _stricmp(a,b) 200 | # define strnicmp(a,b,c) _strnicmp(a,b,c) 201 | #else 202 | # ifndef stricmp 203 | # define stricmp(a,b) strcasecmp(a,b) 204 | # endif 205 | # ifndef strnicmp 206 | # define strnicmp(a,b,c) strncasecmp(a,b,c) 207 | # endif 208 | #endif 209 | 210 | EXPORT char *_skipspace( char *source, const char *breakchars ); 211 | #define skipspace(s) _skipspace((s), "\r\n") 212 | EXPORT char *chopspace( char *value ); 213 | 214 | EXPORT size_t vstrcatf( char *buffer, size_t bufferSize, size_t *sizeNeeded, const char *format, va_list args ); 215 | EXPORT size_t strprintf( char *buffer, size_t bufferSize, size_t *sizeNeeded, const char *format, ... ) XplFormatString(4, 5); 216 | EXPORT int stripat(char *str, char *pattern); 217 | EXPORT int stripatn(char *str, char *pattern, size_t len); 218 | 219 | EXPORT char * strspace( char *source ); 220 | 221 | #if defined(_WIN32) 222 | EXPORT char * strndup(char* p, size_t maxlen); 223 | #endif 224 | 225 | #endif 226 | -------------------------------------------------------------------------------- /pkg-config.pc.cmake: -------------------------------------------------------------------------------- 1 | Name: wjelement 2 | Description: ${PROJECT_DESCRIPTION} 3 | Version: ${PROJECT_VERSION} 4 | Requires: ${PKG_CONFIG_REQUIRES} 5 | prefix=${CMAKE_INSTALL_PREFIX} 6 | includedir=${PKG_CONFIG_INCLUDEDIR} 7 | libdir=${PKG_CONFIG_LIBDIR} 8 | Libs: ${PKG_CONFIG_LIBS} 9 | Cflags: ${PKG_CONFIG_CFLAGS} 10 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(lib) 2 | add_subdirectory(wjreader) 3 | add_subdirectory(wjwriter) 4 | add_subdirectory(wjelement) 5 | add_subdirectory(cli) 6 | -------------------------------------------------------------------------------- /src/cli/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(wjecli wjecli.c wjecli.h cmds.c) 2 | 3 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ALL_CFLAGS} ${PTHREAD_CFLAGS} ${OPENSSL_CFLAGS}") 4 | 5 | target_link_libraries(wjecli 6 | wjelement 7 | ) 8 | 9 | install(TARGETS wjecli DESTINATION bin) 10 | install(PROGRAMS wje DESTINATION bin) 11 | 12 | -------------------------------------------------------------------------------- /src/cli/wje: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dir=`dirname $0` 4 | 5 | which rlwrap > /dev/null 6 | if [ $? == 0 ]; then 7 | rlwrap -pred $dir/wjecli $@ 8 | else 9 | $dir/wjecli $@ 10 | fi 11 | -------------------------------------------------------------------------------- /src/cli/wjecli.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | #include "wjecli.h" 19 | #ifdef _WIN32 20 | #include 21 | #else 22 | #include 23 | #endif 24 | 25 | WJECLIGlobals wje; 26 | 27 | extern WJECLIcmd WJECLIcmds[]; 28 | 29 | void usage(char *arg0) 30 | { 31 | WJECLIcmd *cmd; 32 | int i; 33 | 34 | if (arg0) { 35 | printf("Command line JSON document browser\n"); 36 | printf("Usage: %s [json file]\n\n", arg0); 37 | 38 | printf("Commands:\n"); 39 | } 40 | 41 | for (i = 0; (cmd = &WJECLIcmds[i]) && cmd->name; i++) { 42 | if (!cmd->description) { 43 | continue; 44 | } 45 | 46 | printf("\t"); 47 | 48 | if (cmd->letter != '\0') { 49 | printf("%c|", cmd->letter); 50 | } 51 | 52 | printf("%s %s\n", cmd->name, cmd->args ? cmd->args : ""); 53 | printf("\t\t%s\n\n", cmd->description); 54 | } 55 | } 56 | 57 | char * nextfield(char *value, char **end) 58 | { 59 | char *d, *s; 60 | 61 | if (end) { 62 | *end = NULL; 63 | } 64 | 65 | if (!value) { 66 | return(NULL); 67 | } 68 | 69 | value = skipspace(value); 70 | 71 | if (!*value) { 72 | return(NULL); 73 | } 74 | 75 | if ('"' == *value) { 76 | value++; 77 | 78 | d = s = value; 79 | while (s) { 80 | switch (*s) { 81 | case '\0': 82 | case '\n': 83 | case '\r': 84 | *d = '\0'; 85 | return(*value ? value : NULL); 86 | 87 | case '"': 88 | *d = '\0'; 89 | if (end) { 90 | *end = s + 1; 91 | } 92 | return(*value ? value : NULL); 93 | 94 | case '\\': 95 | switch (*(++s)) { 96 | case '"': 97 | case '\\': 98 | *(d++) = *(s++); 99 | break; 100 | 101 | default: 102 | *(d++) = '\\'; 103 | } 104 | break; 105 | 106 | default: 107 | *(d++) = *(s++); 108 | break; 109 | } 110 | } 111 | } else { 112 | if ((d = strspace(value))) { 113 | *d = '\0'; 114 | if (end) { 115 | *end = d + 1; 116 | } 117 | } 118 | 119 | return(*value ? value : NULL); 120 | } 121 | 122 | return(NULL); 123 | } 124 | 125 | int runcmd(WJElement *doc, WJElement *current, char *line) 126 | { 127 | WJECLIcmd *command; 128 | char *cmd = line; 129 | char *args = NULL; 130 | int i; 131 | 132 | // cmd = nextfield(line, &args); 133 | 134 | /* Look for a command using the letter, which does NOT require a space */ 135 | for (i = 0; (command = &WJECLIcmds[i]) && command->name; i++) { 136 | if (command->letter != '\0' && *cmd == command->letter) { 137 | args = skipspace(++cmd); 138 | break; 139 | } 140 | } 141 | 142 | /* Look for a full command */ 143 | if (!command || !command->name) { 144 | cmd = nextfield(line, &args); 145 | 146 | for (i = 0; (command = &WJECLIcmds[i]) && command->name; i++) { 147 | if (!stricmp(cmd, command->name)) { 148 | break; 149 | } 150 | } 151 | } 152 | 153 | if (!*current) { 154 | *current = *doc; 155 | } 156 | 157 | if (command && command->name) { 158 | return(command->cb(doc, current, args)); 159 | } else { 160 | fprintf(stderr, "Unknown command: %s\n", cmd); 161 | return(3); 162 | } 163 | } 164 | 165 | int main(int argc, char **argv) 166 | { 167 | FILE *in = NULL; 168 | WJElement doc = NULL; 169 | WJElement current = NULL; 170 | int r = 0; 171 | WJReader reader; 172 | char *cmd; 173 | char line[1024]; 174 | 175 | /* Print pretty documents by default */ 176 | wje.pretty = TRUE; 177 | 178 | /* Print base 10 by default */ 179 | wje.base = 10; 180 | 181 | if (argc > 2) { 182 | /* Umm, we only allow one argument... a filename */ 183 | usage(argv[0]); 184 | return(1); 185 | } 186 | 187 | MemoryManagerOpen("wje-cli"); 188 | 189 | if (argc == 2) { 190 | if (!stricmp(argv[1], "--help") || !stricmp(argv[1], "-h")) { 191 | usage(argv[0]); 192 | MemoryManagerClose("wje-cli"); 193 | return(0); 194 | } 195 | 196 | if (!(in = fopen(argv[1], "rb"))) { 197 | perror(NULL); 198 | MemoryManagerClose("wje-cli"); 199 | return(2); 200 | } 201 | 202 | /* 203 | A filename was specified on the command line. Does this look 204 | like a script, or a JSON document? 205 | */ 206 | if (fgets(line, sizeof(line), in) && 207 | !strncmp(line, "#!", 2) 208 | ) { 209 | /* This looks like a script, read commands from this file */ 210 | ; 211 | } else { 212 | /* Assume it is a JSON document, rewind back to the start. */ 213 | rewind(in); 214 | 215 | if ((reader = WJROpenFILEDocument(in, NULL, 0))) { 216 | doc = WJEOpenDocument(reader, NULL, NULL, NULL); 217 | WJRCloseDocument(reader); 218 | 219 | wje.filename = MemStrdup(argv[1]); 220 | } 221 | 222 | fclose(in); 223 | in = NULL; 224 | 225 | if (!doc) { 226 | fprintf(stderr, "Could not parse JSON document: %s\n", argv[1]); 227 | MemoryManagerClose("wje-cli"); 228 | return(3); 229 | } 230 | } 231 | } 232 | 233 | if (!in) { 234 | /* Read commands from standard in */ 235 | in = stdin; 236 | } 237 | 238 | if (!doc) { 239 | /* Start with an empty document if one wasn't specified */ 240 | doc = WJEObject(NULL, NULL, WJE_SET); 241 | } 242 | current = doc; 243 | 244 | for (;;) { 245 | /* Read the next command */ 246 | if (in == stdin && isatty(fileno(stdin))) { 247 | fprintf(stdout, "wje"); 248 | 249 | if (r) { 250 | fprintf(stdout, " (%d)", r); 251 | } 252 | 253 | fprintf(stdout, "> "); 254 | fflush(stdout); 255 | } 256 | 257 | if (fgets(line, sizeof(line), in)) { 258 | cmd = _skipspace(line, NULL); 259 | } else { 260 | cmd = NULL; 261 | } 262 | 263 | if (!cmd || !*cmd) { 264 | /* Ignore blank lines */ 265 | } else { 266 | r = runcmd(&doc, ¤t, cmd); 267 | } 268 | cmd = NULL; 269 | 270 | if (feof(in) || wje.exiting) { 271 | break; 272 | } 273 | } 274 | 275 | if (doc) { 276 | WJECloseDocument(doc); 277 | doc = NULL; 278 | } 279 | 280 | if (in && in != stdin) { 281 | fclose(in); 282 | in = NULL; 283 | } 284 | 285 | if (wje.filename) { 286 | MemRelease(&wje.filename); 287 | } 288 | 289 | MemoryManagerClose("wje-cli"); 290 | return(r); 291 | } 292 | 293 | -------------------------------------------------------------------------------- /src/cli/wjecli.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | typedef int (* cmdcb)(WJElement *document, WJElement *current, char *line); 23 | 24 | typedef struct 25 | { 26 | char letter; 27 | char *name; 28 | char *description; 29 | cmdcb cb; 30 | char *args; 31 | } WJECLIcmd; 32 | 33 | typedef struct 34 | { 35 | XplBool pretty; 36 | uint32 flags; 37 | int base; 38 | 39 | char *filename; 40 | 41 | XplBool exiting; 42 | } WJECLIGlobals; 43 | 44 | /* wjecli.c */ 45 | char * nextfield(char *value, char **end); 46 | int runcmd(WJElement *doc, WJElement *current, char *line); 47 | void usage(char *arg0); 48 | 49 | -------------------------------------------------------------------------------- /src/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(xpl 2 | xpl.c 3 | ) 4 | 5 | target_link_libraries(xpl 6 | ${ALL_LIBS} 7 | ) 8 | 9 | SET_TARGET_PROPERTIES( 10 | xpl 11 | PROPERTIES 12 | VERSION 1.0.0 13 | SOVERSION 1 14 | INSTALL_NAME_DIR "${LIB_DEST_DIR}" 15 | ) 16 | 17 | install(TARGETS xpl 18 | LIBRARY DESTINATION ${LIB_DEST_DIR} 19 | ARCHIVE DESTINATION ${LIB_DEST_DIR} 20 | ) 21 | -------------------------------------------------------------------------------- /src/lib/xpl.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | /* hack for aix, windows, and other asprintf-less systems */ 23 | #include 24 | #include 25 | #include "memmgr.h" 26 | #ifndef asprintf 27 | EXPORT int asprintf(char **ret, const char *format, ...) { 28 | va_list ap; 29 | int count; 30 | *ret = NULL; 31 | va_start(ap, format); 32 | count = vsnprintf(NULL, 0, format, ap); 33 | va_end(ap); 34 | if(count >= 0) { 35 | char* buffer = MemMalloc(count + 1); 36 | if(buffer == NULL) { 37 | return -1; 38 | } 39 | va_start(ap, format); 40 | count = vsnprintf(buffer, count + 1, format, ap); 41 | va_end(ap); 42 | 43 | if(count < 0) { 44 | MemFree(buffer); 45 | } else { 46 | *ret = buffer; 47 | } 48 | } 49 | return count; 50 | } 51 | #endif 52 | 53 | EXPORT size_t vstrcatf( char *buffer, size_t bufferSize, size_t *sizeNeeded, const char *format, va_list args ) 54 | { 55 | int needed; /* vsnprintf is prototyped as returning int */ 56 | char *start = NULL; /* where to write if non-NULL */ 57 | size_t used = 0; /* space consumed in buffer */ 58 | size_t space = 0; /* space free in buffer */ 59 | size_t ret = 0; 60 | 61 | /* have buffer with a NUL inside it? */ 62 | if(buffer && bufferSize && (start = memchr(buffer, '\0', bufferSize))) { 63 | used = start - buffer; /* yes, number of used bytes */ 64 | /* available space in buffer */ 65 | space = bufferSize - used; 66 | } 67 | #ifdef _MSC_VER 68 | needed = _vsnprintf(start, space, format, args); 69 | if (-1==needed) { 70 | needed = _vscprintf(format, args); 71 | } 72 | #else 73 | needed = vsnprintf(start, space, format, args); 74 | #endif 75 | if(needed < 0) { 76 | DebugAssert(0); // output error from vsnprintf 77 | } 78 | else if(start) { /* have place to write? */ 79 | if(needed >= space) { 80 | DebugAssert(sizeNeeded);// buffer overflow and size return not provided 81 | *start = '\0'; /* tie off buffer as if vsnprintf never happened */ 82 | } 83 | else { 84 | ret = needed; /* success, return bytes written */ 85 | } 86 | } 87 | else if(buffer) { /* no place to write, did we have a buffer? */ 88 | DebugAssert(0); // no terminating NUL found in buffer 89 | // This may be a bug, as it will delete a byte and will return a size 90 | // count that is short by 1. However, we already overflowed the buffer 91 | // if we got here, so there isn't much hope of goodness anyway. If it 92 | // happens we need to fix the underlying bug, not try to recover here. 93 | used = bufferSize - 1; /* make space for one byte */ 94 | buffer[used] = '\0'; /* put a NUL there */ 95 | } 96 | if(sizeNeeded) { /* need to return size? */ 97 | *sizeNeeded = used + needed; 98 | } 99 | return ret; 100 | } 101 | 102 | EXPORT size_t strprintf( char *buffer, size_t bufferSize, size_t *sizeNeeded, const char *format, ... ) 103 | { 104 | size_t needed; 105 | va_list args; 106 | 107 | if( buffer && bufferSize ) 108 | { 109 | *buffer = '\0'; 110 | } 111 | va_start( args, format ); 112 | needed = vstrcatf( buffer, bufferSize, sizeNeeded, format, args ); 113 | va_end( args ); 114 | return needed; 115 | } 116 | 117 | EXPORT char * strichr(char *str, char c) 118 | { 119 | c = toupper(c); 120 | 121 | if (str) { 122 | char *ptr; 123 | 124 | for (ptr = str; *ptr != '\0'; ptr++) { 125 | if (c == toupper(*ptr)) { 126 | return(ptr); 127 | } 128 | } 129 | } 130 | 131 | return(NULL); 132 | } 133 | 134 | EXPORT char * stristrn(char *haystack, char *needle, size_t len) 135 | { 136 | if (haystack && needle && *haystack && *needle) { 137 | char *ptr; 138 | 139 | for (ptr = strichr(haystack, *needle); ptr; ptr = strichr(ptr + 1, *needle)) { 140 | if (!strnicmp(ptr, needle, len)) { 141 | return(ptr); 142 | } 143 | } 144 | } 145 | 146 | return(NULL); 147 | } 148 | 149 | static int stripat_r(char *str, char *pattern, size_t len, int depth) 150 | { 151 | char *next; 152 | char *match; 153 | char *end = pattern + len; 154 | 155 | if (!str || !pattern || depth > 15) { 156 | return(-1); 157 | } 158 | 159 | for (;;) { 160 | if (pattern >= end || !*pattern) { 161 | if (!*str) { 162 | return(0); 163 | } else { 164 | return(-1); 165 | } 166 | } 167 | 168 | switch (*pattern) { 169 | case '?': 170 | /* A ? must match a single character */ 171 | if (*str) { 172 | str++; 173 | pattern++; 174 | } else { 175 | return(-1); 176 | } 177 | 178 | case '*': 179 | /* 180 | A * may match 0 or more characters. 181 | 182 | Find the next wild card in the pattern, and then search for 183 | the exact value between the two wild cards in the string. 184 | 185 | Example, if pattern points to "*abc*" then "abc" must be 186 | found in the string. 187 | */ 188 | pattern++; 189 | 190 | for (next = pattern; *next && next < end && *next != '*' && *next != '?'; next++); 191 | if (next > pattern) { 192 | match = str - 1; 193 | while ((match = stristrn(match + 1, pattern, next - pattern))) { 194 | if (!stripat_r(match + (next - pattern), next, end - next, depth + 1)) { 195 | return(0); 196 | } 197 | } 198 | 199 | return(-1); 200 | } else if (pattern >= end || !*pattern) { 201 | /* The last character of pattern is a *, so we match. */ 202 | return(0); 203 | } 204 | 205 | break; 206 | 207 | default: 208 | if (isspace(*pattern)) { 209 | /* Any whitespace matches any whitespace */ 210 | if (isspace(*str)) { 211 | for (str++; isspace(*str); str++); 212 | for (pattern++; *pattern && pattern < end && isspace(*pattern); pattern++); 213 | } else { 214 | return(-1); 215 | } 216 | } else if (toupper(*pattern) == toupper(*str)) { 217 | pattern++; 218 | str++; 219 | } else { 220 | return(-1); 221 | } 222 | 223 | break; 224 | } 225 | } 226 | } 227 | 228 | EXPORT int stripatn(char *str, char *pattern, size_t len) 229 | { 230 | if (!pattern) return(-1); 231 | 232 | return(stripat_r(str, pattern, len, 1)); 233 | } 234 | 235 | EXPORT int stripat(char *str, char *pattern) 236 | { 237 | if (!pattern) return(-1); 238 | 239 | return(stripat_r(str, pattern, strlen(pattern), 1)); 240 | } 241 | 242 | EXPORT char *chopspace( char *value ) 243 | { 244 | char *p; 245 | 246 | if( value ) 247 | { 248 | for(p=value+strlen(value);p>value;p--) 249 | { 250 | if( !isspace( *(p-1) ) ) 251 | { 252 | break; 253 | } 254 | } 255 | *p = '\0'; 256 | } 257 | return( skipspace( value ) ); 258 | } 259 | 260 | EXPORT char * _skipspace( char *source, const char *breakchars ) 261 | { 262 | if( source ) 263 | { 264 | while( *source && isspace( *source ) ) 265 | { 266 | #if 0 267 | DebugAssert(*source != '\r'); 268 | DebugAssert(*source != '\n'); 269 | #endif 270 | if (breakchars && strchr(breakchars, *source)) { 271 | break; 272 | } 273 | 274 | source++; 275 | } 276 | } 277 | return source; 278 | } 279 | 280 | EXPORT char * strspace( char *source ) 281 | { 282 | while( source && *source ) 283 | { 284 | if( isspace( *source ) ) 285 | { 286 | return source; 287 | } 288 | source++; 289 | } 290 | return NULL; 291 | } 292 | 293 | #if defined(_WIN32) 294 | EXPORT char * strndup( char *p, size_t maxlen ) 295 | { 296 | if( p ) 297 | { 298 | char *r = malloc( maxlen + 1 ); 299 | if( !r ) 300 | { 301 | return r; 302 | } 303 | strncpy( r, p, maxlen ); 304 | r[maxlen] = '\0'; 305 | return r; 306 | } 307 | 308 | return NULL; 309 | } 310 | #endif 311 | 312 | EXPORT void * MemMallocEx(void *ptr, size_t size, size_t *actual, XplBool wait, XplBool zero) 313 | { 314 | void *result; 315 | 316 | do { 317 | if (ptr) { 318 | result = realloc(ptr, size); 319 | 320 | /* 321 | This implementation doesn't currently have any way to know how 322 | big the existing allocation is, and so it can't zero the new 323 | data without writing over the old data. 324 | */ 325 | zero = FALSE; 326 | } else { 327 | result = malloc(size); 328 | } 329 | 330 | if (result) { 331 | if (actual) { 332 | /* 333 | In this implementation we aren't actually pulling from a 334 | pool so the allocation size will be exactly what the 335 | consumer asked for. 336 | */ 337 | *actual = size; 338 | } 339 | 340 | if (zero) { 341 | memset(result, 0, size); 342 | } 343 | } 344 | } while (wait && !result); 345 | 346 | return(result); 347 | } 348 | 349 | -------------------------------------------------------------------------------- /src/wjelement/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(wjelement 2 | element.c 3 | element.h 4 | search.c 5 | types.c 6 | schema.c 7 | hash.c 8 | ) 9 | 10 | target_link_libraries(wjelement 11 | wjreader 12 | wjwriter 13 | xpl 14 | ${ALL_LIBS} 15 | ) 16 | 17 | SET_TARGET_PROPERTIES( 18 | wjelement 19 | PROPERTIES 20 | VERSION 1.0.0 21 | SOVERSION 1 22 | INSTALL_NAME_DIR "${LIB_DEST_DIR}" 23 | ) 24 | 25 | install(TARGETS wjelement 26 | LIBRARY DESTINATION ${LIB_DEST_DIR} 27 | ARCHIVE DESTINATION ${LIB_DEST_DIR} 28 | ) 29 | 30 | 31 | # unit tests 32 | add_executable(wjeunit 33 | wjeunit.c 34 | ) 35 | 36 | target_link_libraries(wjeunit 37 | wjreader 38 | wjwriter 39 | wjelement 40 | xpl 41 | ${PTHREAD_LIBS} 42 | ${ALL_LIBS} 43 | ) 44 | 45 | # The use of ${EXECUTABLE_OUTPUT_PATH} is required for windows 46 | add_test(WJElement:SelfReference ${EXECUTABLE_OUTPUT_PATH}/wjeunit self ) 47 | add_test(WJElement:ElementNames ${EXECUTABLE_OUTPUT_PATH}/wjeunit names ) 48 | add_test(WJElement:Offsets ${EXECUTABLE_OUTPUT_PATH}/wjeunit offsets ) 49 | add_test(WJElement:Lists ${EXECUTABLE_OUTPUT_PATH}/wjeunit lists ) 50 | add_test(WJElement:Paths ${EXECUTABLE_OUTPUT_PATH}/wjeunit paths ) 51 | add_test(WJElement:GetValues ${EXECUTABLE_OUTPUT_PATH}/wjeunit getvalue ) 52 | add_test(WJElement:GetMultipleValues ${EXECUTABLE_OUTPUT_PATH}/wjeunit getvalues ) 53 | add_test(WJElement:SetValues ${EXECUTABLE_OUTPUT_PATH}/wjeunit setvalue ) 54 | add_test(WJElement:SetMultipleValues ${EXECUTABLE_OUTPUT_PATH}/wjeunit setvalues ) 55 | add_test(WJElement:NewValues ${EXECUTABLE_OUTPUT_PATH}/wjeunit newvalue ) 56 | add_test(WJElement:NewMultipleValues ${EXECUTABLE_OUTPUT_PATH}/wjeunit newvalues ) 57 | add_test(WJElement:PutValues ${EXECUTABLE_OUTPUT_PATH}/wjeunit putvalue ) 58 | add_test(WJElement:PutMultipleValues ${EXECUTABLE_OUTPUT_PATH}/wjeunit putvalues ) 59 | add_test(WJElement:Append ${EXECUTABLE_OUTPUT_PATH}/wjeunit append ) 60 | add_test(WJElement:Conditions ${EXECUTABLE_OUTPUT_PATH}/wjeunit conditions ) 61 | add_test(WJElement:Optionals ${EXECUTABLE_OUTPUT_PATH}/wjeunit optionals ) 62 | add_test(WJElement:Defaults ${EXECUTABLE_OUTPUT_PATH}/wjeunit defaults ) 63 | add_test(WJElement:FormatStr ${EXECUTABLE_OUTPUT_PATH}/wjeunit formatstr ) 64 | add_test(WJElement:BigDoc ${EXECUTABLE_OUTPUT_PATH}/wjeunit bigdoc ) 65 | add_test(WJElement:RealBigDoc ${EXECUTABLE_OUTPUT_PATH}/wjeunit realbigdoc ) 66 | add_test(WJElement:RealBigDoc2 ${EXECUTABLE_OUTPUT_PATH}/wjeunit realbigdoc2 ) 67 | add_test(WJElement:Schema ${EXECUTABLE_OUTPUT_PATH}/wjeunit schema ) 68 | 69 | -------------------------------------------------------------------------------- /src/wjelement/element.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | #include "element.h" 18 | #include 19 | 20 | void WJEChanged(WJElement element) 21 | { 22 | for (; element; element = element->parent) { 23 | element->changes++; 24 | } 25 | } 26 | 27 | _WJElement * _WJENew(_WJElement *parent, char *name, size_t len, const char *file, int line) 28 | { 29 | _WJElement *result; 30 | WJElement prev; 31 | 32 | if (parent) { 33 | _WJEChanged((WJElement) parent); 34 | 35 | if (WJR_TYPE_ARRAY == parent->pub.type) { 36 | /* Children of an array can not have a name */ 37 | name = NULL; 38 | len = 0; 39 | } else if (WJR_TYPE_OBJECT != parent->pub.type || !name || !*name) { 40 | /* 41 | Only arrays and objects can contain children, and elements in an 42 | object MUST be named. 43 | */ 44 | return(NULL); 45 | } 46 | } 47 | 48 | if ((result = MemMalloc(sizeof(_WJElement) + len + 1))) { 49 | memset(result, 0, sizeof(_WJElement)); 50 | 51 | MemUpdateOwner(result, file, line); 52 | 53 | if (name) { 54 | strncpy(result->_name, name, len); 55 | result->pub.name = result->_name; 56 | } 57 | result->_name[len] = '\0'; 58 | 59 | if (parent) { 60 | result->pub.parent = (WJElement) parent; 61 | 62 | if (!parent->pub.child) { 63 | parent->pub.child = (WJElement) result; 64 | } else { 65 | prev = parent->pub.last; 66 | prev->next = (WJElement) result; 67 | result->pub.prev = prev; 68 | } 69 | 70 | parent->pub.last = (WJElement) result; 71 | parent->pub.count++; 72 | } 73 | 74 | result->pub.type = WJR_TYPE_OBJECT; 75 | } 76 | 77 | return(result); 78 | } 79 | 80 | _WJElement * _WJEReset(_WJElement *e, WJRType type) 81 | { 82 | WJElement child; 83 | 84 | if (!e) return(NULL); 85 | 86 | while ((child = e->pub.child)) { 87 | WJEDetach(child); 88 | WJECloseDocument(child); 89 | } 90 | 91 | if (WJR_TYPE_STRING == e->pub.type && e->value.string) { 92 | MemRelease(&(e->value.string)); 93 | } 94 | e->value.string = NULL; 95 | e->pub.length = 0; 96 | e->pub.type = type; 97 | 98 | return(e); 99 | } 100 | 101 | EXPORT XplBool _WJEDetach(WJElement document, const char *file, const int line) 102 | { 103 | if (!document) { 104 | return(FALSE); 105 | } 106 | 107 | MemUpdateOwner(document, file, line); 108 | 109 | /* Remove references to the document */ 110 | if (document->parent) { 111 | WJEChanged(document->parent); 112 | 113 | if (document->parent->child == document) { 114 | document->parent->child = document->next; 115 | } 116 | if (document->parent->last == document) { 117 | document->parent->last = document->prev; 118 | } 119 | document->parent->count--; 120 | document->parent = NULL; 121 | } 122 | 123 | if (document->prev) { 124 | document->prev->next = document->next; 125 | } 126 | 127 | if (document->next) { 128 | document->next->prev = document->prev; 129 | } 130 | 131 | document->prev = NULL; 132 | document->next = NULL; 133 | 134 | return(TRUE); 135 | } 136 | 137 | EXPORT XplBool WJEAttach(WJElement container, WJElement document) 138 | { 139 | WJElement prev; 140 | 141 | if (!document || !container) { 142 | return(FALSE); 143 | } 144 | 145 | if (document->parent == container) { 146 | return(TRUE); 147 | } 148 | 149 | if (document->name) { 150 | while ((prev = WJEChild(container, document->name, WJE_GET))) { 151 | WJEDetach(prev); 152 | WJECloseDocument(prev); 153 | } 154 | } 155 | 156 | WJEDetach(document); 157 | 158 | /* Insert it into the new container */ 159 | document->parent = container; 160 | if (!container->child) { 161 | container->child = document; 162 | } else { 163 | prev = container->last; 164 | prev->next = document; 165 | document->prev = prev; 166 | } 167 | container->last = document; 168 | container->count++; 169 | WJEChanged(container); 170 | 171 | return(TRUE); 172 | } 173 | 174 | EXPORT XplBool WJERename(WJElement document, const char *name) 175 | { 176 | _WJElement *current = (_WJElement *) document; 177 | WJElement e; 178 | 179 | if (!document) { 180 | return(FALSE); 181 | } 182 | 183 | /* Look for any siblings with that name, and fail if found */ 184 | if (name && document->parent) { 185 | for (e = document->parent->child; e; e = e->next) { 186 | if (e != document && !stricmp(e->name, name)) { 187 | return(FALSE); 188 | } 189 | } 190 | } 191 | 192 | /* Free the previous name if needed */ 193 | if (document->name && current->_name != document->name) { 194 | MemRelease(&document->name); 195 | } 196 | 197 | /* Set the new name */ 198 | if (name) { 199 | if (!(document->name = MemStrdup(name))) { 200 | return(FALSE); 201 | } 202 | } else { 203 | document->name = NULL; 204 | } 205 | 206 | return(TRUE); 207 | } 208 | 209 | static WJElement _WJELoad(_WJElement *parent, WJReader reader, char *where, WJELoadCB loadcb, void *data, const char *file, const int line) 210 | { 211 | char *current, *name, *value; 212 | _WJElement *l = NULL; 213 | XplBool complete; 214 | size_t actual, used, len; 215 | 216 | if (!reader) { 217 | return((WJElement) _WJENew(NULL, NULL, 0, file, line)); 218 | } 219 | 220 | if (!where) { 221 | /* 222 | A NULL poisition in a WJReader indicates the root of the document, 223 | so we must read to find the first real object. 224 | */ 225 | where = WJRNext(NULL, 2048, reader); 226 | } 227 | 228 | if (!where) { 229 | /* This appears to be an empty document */ 230 | return(NULL); 231 | } 232 | 233 | name = where[1] ? where + 1 : NULL; 234 | 235 | if (name && (WJEChild((WJElement) parent, name, WJE_GET))) { 236 | /* Do not load duplicate names */ 237 | return(NULL); 238 | } 239 | 240 | if (loadcb && !loadcb((WJElement)parent, name, data, file, line)) { 241 | /* The consumer has rejected this item */ 242 | return(NULL); 243 | } 244 | 245 | if ((l = _WJENew(parent, name, name ? strlen(name) : 0, file, line))) { 246 | switch ((l->pub.type = *where)) { 247 | default: 248 | case WJR_TYPE_UNKNOWN: 249 | case WJR_TYPE_NULL: 250 | break; 251 | 252 | case WJR_TYPE_OBJECT: 253 | case WJR_TYPE_ARRAY: 254 | while (reader && (current = WJRNext(where, 2048, reader))) { 255 | _WJELoad(l, reader, current, loadcb, data, file, line); 256 | } 257 | break; 258 | 259 | case WJR_TYPE_STRING: 260 | actual = 0; 261 | used = 0; 262 | len = 0; 263 | complete = FALSE; 264 | l->value.string = NULL; 265 | l->pub.length = 0; 266 | 267 | do { 268 | if ((value = WJRStringEx(&complete, &len, reader))) { 269 | if (used + len >= actual) { 270 | l->value.string = MemMallocEx(l->value.string, 271 | len + 1 + used, &actual, TRUE, TRUE); 272 | MemUpdateOwner(l->value.string, file, line); 273 | } 274 | 275 | memcpy(l->value.string + used, value, len); 276 | used += len; 277 | l->value.string[used] = '\0'; 278 | l->pub.length = used; 279 | } 280 | } while (!complete); 281 | break; 282 | 283 | case WJR_TYPE_NUMBER: 284 | #ifdef WJE_DISTINGUISH_INTEGER_TYPE 285 | case WJR_TYPE_INTEGER: 286 | #endif 287 | l->value.number.hasDecimalPoint = WJRIntOrDouble(reader, 288 | &l->value.number.i, 289 | &l->value.number.d); 290 | 291 | #ifdef WJE_DISTINGUISH_INTEGER_TYPE 292 | if (l->value.number.hasDecimalPoint) { 293 | l->pub.type = WJR_TYPE_NUMBER; 294 | } else { 295 | l->pub.type = WJR_TYPE_INTEGER; 296 | } 297 | #endif 298 | 299 | if (WJRNegative(reader)) { 300 | /* 301 | Store the number as a positive, but keep track of the 302 | fact that it was negative. 303 | */ 304 | l->value.number.negative = TRUE; 305 | } else { 306 | l->value.number.negative = FALSE; 307 | } 308 | break; 309 | 310 | case WJR_TYPE_TRUE: 311 | l->value.boolean = TRUE; 312 | break; 313 | 314 | case WJR_TYPE_BOOL: 315 | case WJR_TYPE_FALSE: 316 | l->value.boolean = FALSE; 317 | break; 318 | } 319 | } 320 | 321 | return((WJElement) l); 322 | } 323 | 324 | EXPORT WJElement _WJEOpenDocument(WJReader reader, char *where, WJELoadCB loadcb, void *data, const char *file, const int line) 325 | { 326 | WJElement element; 327 | 328 | if ((element = _WJELoad(NULL, reader, where, loadcb, data, file, line))) { 329 | MemUpdateOwner(element, file, line); 330 | } 331 | 332 | return(element); 333 | } 334 | 335 | typedef struct WJEMemArgs 336 | { 337 | char *json; 338 | char quote; 339 | 340 | size_t len; 341 | } WJEMemArgs; 342 | 343 | static size_t WJEMemCallback(char *buffer, size_t length, size_t seen, void *userdata) 344 | { 345 | WJEMemArgs *args = (WJEMemArgs *) userdata; 346 | char *json; 347 | char *q; 348 | size_t len; 349 | 350 | if (!args || !args->json) { 351 | return(0); 352 | } 353 | 354 | len = args->len - seen; 355 | json = args->json + seen; 356 | 357 | if (!len) { 358 | /* Done */ 359 | return(0); 360 | } 361 | 362 | if (len > length) { 363 | len = length; 364 | } 365 | 366 | if (len > 0) { 367 | memcpy(buffer, json, len); 368 | 369 | switch (args->quote) { 370 | case '"': 371 | case '\0': 372 | /* Default behavior, do nothing to quotes */ 373 | break; 374 | 375 | default: 376 | /* Replace quotes in the data we just copied */ 377 | json = buffer; 378 | length = len; 379 | 380 | while (length && (q = memchr(json, args->quote, length))) { 381 | *q = '"'; 382 | 383 | length -= (q - json); 384 | json = q; 385 | } 386 | 387 | break; 388 | } 389 | } 390 | return(len); 391 | } 392 | 393 | /* 394 | Parse a JSON document already in memory directoy without requiring the 395 | consumer to create a WJReader. This is meant as a simple utility function 396 | and allows parsing documents with a non standard quote char for the sake of 397 | embedding documents directly in C code. 398 | */ 399 | EXPORT WJElement __WJEFromString(const char *json, char quote, const char *file, const int line) 400 | { 401 | WJElement doc = NULL; 402 | WJEMemArgs args; 403 | WJReader reader; 404 | 405 | args.json = (char *) json; 406 | args.quote = quote; 407 | 408 | if (json) { 409 | args.len = strlen(json); 410 | } 411 | 412 | if (json && (reader = WJROpenDocument(WJEMemCallback, &args, NULL, 0))) { 413 | doc = _WJEOpenDocument(reader, NULL, NULL, NULL, file, line); 414 | WJRCloseDocument(reader); 415 | } 416 | 417 | return(doc); 418 | } 419 | 420 | EXPORT char * _WJEToString(WJElement document, XplBool pretty, const char *file, const int line) 421 | { 422 | WJWriter writer; 423 | char *mem = NULL; 424 | 425 | if ((writer = WJWOpenMemDocument(pretty, &mem))) { 426 | WJEWriteDocument(document, writer, NULL); 427 | WJWCloseDocument(writer); 428 | } 429 | if (mem) { 430 | MemUpdateOwner(mem, file, line); 431 | } 432 | return(mem); 433 | } 434 | 435 | EXPORT WJElement WJEFromFile(const char *path) 436 | { 437 | WJElement e = NULL; 438 | FILE *f; 439 | WJReader reader; 440 | 441 | if (!path) { 442 | errno = EINVAL; 443 | return(NULL); 444 | } 445 | 446 | if ((f = fopen(path, "rb"))) { 447 | if ((reader = WJROpenFILEDocument(f, NULL, 0))) { 448 | e = WJEOpenDocument(reader, NULL, NULL, NULL); 449 | WJRCloseDocument(reader); 450 | } 451 | 452 | fclose(f); 453 | } 454 | 455 | return(e); 456 | } 457 | 458 | EXPORT XplBool WJEToFile(WJElement document, XplBool pretty, const char *path) 459 | { 460 | FILE *f; 461 | WJWriter writer; 462 | XplBool ret = FALSE; 463 | 464 | if (!document || !path) { 465 | errno = EINVAL; 466 | return(FALSE); 467 | } 468 | 469 | if ((f = fopen(path, "wb"))) { 470 | if ((writer = WJWOpenFILEDocument(pretty, f))) { 471 | ret = WJEWriteDocument(document, writer, NULL); 472 | 473 | WJWCloseDocument(writer); 474 | } 475 | 476 | fclose(f); 477 | } 478 | 479 | return(ret); 480 | } 481 | 482 | static WJElement _WJECopy(_WJElement *parent, WJElement original, WJECopyCB copycb, void *data, const char *file, const int line) 483 | { 484 | _WJElement *l = NULL; 485 | _WJElement *o; 486 | WJElement c; 487 | char *tmp; 488 | 489 | if (!(o = (_WJElement *) original)) { 490 | return(NULL); 491 | } 492 | 493 | if (copycb && !copycb((WJElement) parent, (WJElement) original, data, file, line)) { 494 | /* The consumer has rejected this item */ 495 | return(NULL); 496 | } 497 | 498 | if ((l = _WJENew(parent, original->name, original->name ? strlen(original->name) : 0, file, line))) { 499 | switch ((l->pub.type = original->type)) { 500 | default: 501 | case WJR_TYPE_UNKNOWN: 502 | case WJR_TYPE_NULL: 503 | break; 504 | 505 | case WJR_TYPE_OBJECT: 506 | case WJR_TYPE_ARRAY: 507 | for (c = original->child; c; c = c->next) { 508 | _WJECopy(l, c, copycb, data, file, line); 509 | } 510 | break; 511 | 512 | case WJR_TYPE_STRING: 513 | if ((tmp = WJEString(original, NULL, WJE_GET, ""))) { 514 | l->value.string = MemStrdup(tmp); 515 | l->pub.length = original->length; 516 | } else { 517 | l->value.string = MemStrdup(""); 518 | l->pub.length = 0; 519 | } 520 | break; 521 | 522 | case WJR_TYPE_NUMBER: 523 | #ifdef WJE_DISTINGUISH_INTEGER_TYPE 524 | case WJR_TYPE_INTEGER: 525 | #endif 526 | l->value.number.negative = o->value.number.negative; 527 | l->value.number.i = o->value.number.i; 528 | l->value.number.d = o->value.number.d; 529 | l->value.number.hasDecimalPoint = o->value.number.hasDecimalPoint; 530 | 531 | #ifdef WJE_DISTINGUISH_INTEGER_TYPE 532 | if (l->value.number.hasDecimalPoint) { 533 | l->pub.type = WJR_TYPE_NUMBER; 534 | } else { 535 | l->pub.type = WJR_TYPE_INTEGER; 536 | } 537 | #endif 538 | 539 | break; 540 | 541 | case WJR_TYPE_TRUE: 542 | case WJR_TYPE_BOOL: 543 | case WJR_TYPE_FALSE: 544 | l->value.boolean = WJEBool(original, NULL, WJE_GET, FALSE); 545 | break; 546 | } 547 | } 548 | 549 | return((WJElement) l); 550 | } 551 | 552 | EXPORT WJElement _WJECopyDocument(WJElement to, WJElement from, WJECopyCB copycb, void *data, const char *file, const int line) 553 | { 554 | if (to) { 555 | WJElement c; 556 | 557 | for (c = from->child; c; c = c->next) { 558 | _WJECopy((_WJElement *) to, c, copycb, data, file, line); 559 | } 560 | } else { 561 | if ((to = _WJECopy(NULL, from, copycb, data, file, line))) { 562 | MemUpdateOwner(to, file, line); 563 | } 564 | } 565 | 566 | return(to); 567 | } 568 | 569 | EXPORT XplBool WJEMergeObjects(WJElement to, WJElement from, XplBool overwrite) 570 | { 571 | WJElement a, b; 572 | 573 | if (!to || !from || 574 | WJR_TYPE_OBJECT != to->type || WJR_TYPE_OBJECT != from->type 575 | ) { 576 | return(FALSE); 577 | } 578 | 579 | for (a = from->child; a; a = a->next) { 580 | if ((b = WJEChild(to, a->name, WJE_GET))) { 581 | if (WJR_TYPE_OBJECT == b->type && WJR_TYPE_OBJECT == a->type) { 582 | /* Merge all the children */ 583 | WJEMergeObjects(b, a, overwrite); 584 | 585 | continue; 586 | } else if (overwrite) { 587 | /* Remove the existing value and overwrite it */ 588 | WJECloseDocument(b); 589 | } else { 590 | /* Do nothing with this element */ 591 | continue; 592 | } 593 | } 594 | 595 | /* Copy the object over */ 596 | WJEAttach(to, WJECopyDocument(NULL, a, NULL, NULL)); 597 | } 598 | 599 | return(TRUE); 600 | } 601 | 602 | EXPORT XplBool _WJEWriteDocument(WJElement document, WJWriter writer, char *name, 603 | WJEWriteCB precb, WJEWriteCB postcb, void *data) 604 | { 605 | _WJElement *current = (_WJElement *) document; 606 | WJElement child; 607 | 608 | if (precb && !precb(document, writer, data)) { 609 | return(FALSE); 610 | } 611 | 612 | if (document) { 613 | if (document->writecb) { 614 | return(document->writecb(document, writer, name)); 615 | } 616 | 617 | switch (current->pub.type) { 618 | default: 619 | case WJR_TYPE_UNKNOWN: 620 | break; 621 | 622 | case WJR_TYPE_NULL: 623 | WJWNull(name, writer); 624 | break; 625 | 626 | case WJR_TYPE_OBJECT: 627 | WJWOpenObject(name, writer); 628 | 629 | child = current->pub.child; 630 | do { 631 | _WJEWriteDocument(child, writer, child ? child->name : NULL, 632 | precb, postcb, data); 633 | } while (child && (child = child->next)); 634 | 635 | WJWCloseObject(writer); 636 | break; 637 | 638 | case WJR_TYPE_ARRAY: 639 | WJWOpenArray(name, writer); 640 | 641 | child = current->pub.child; 642 | do { 643 | _WJEWriteDocument(child, writer, NULL, 644 | precb, postcb, data); 645 | } while (child && (child = child->next)); 646 | 647 | WJWCloseArray(writer); 648 | break; 649 | 650 | case WJR_TYPE_STRING: 651 | WJWStringN(name, current->value.string, current->pub.length, TRUE, writer); 652 | break; 653 | 654 | case WJR_TYPE_NUMBER: 655 | #ifdef WJE_DISTINGUISH_INTEGER_TYPE 656 | case WJR_TYPE_INTEGER: 657 | #endif 658 | if (current->value.number.hasDecimalPoint) { 659 | current->pub.type = WJR_TYPE_NUMBER; 660 | if (!current->value.number.negative) { 661 | WJWDouble(name, current->value.number.d, writer); 662 | } else { 663 | WJWDouble(name, -current->value.number.d, writer); 664 | } 665 | } else { 666 | #ifdef WJE_DISTINGUISH_INTEGER_TYPE 667 | current->pub.type = WJR_TYPE_INTEGER; 668 | #endif 669 | if (!current->value.number.negative) { 670 | WJWUInt64(name, current->value.number.i, writer); 671 | } else { 672 | WJWInt64(name, -((int64) current->value.number.i), writer); 673 | } 674 | } 675 | break; 676 | 677 | case WJR_TYPE_TRUE: 678 | case WJR_TYPE_BOOL: 679 | case WJR_TYPE_FALSE: 680 | WJWBoolean(name, current->value.boolean, writer); 681 | break; 682 | } 683 | } 684 | 685 | if (postcb && !postcb(document, writer, data)) { 686 | return(FALSE); 687 | } 688 | 689 | return(TRUE); 690 | } 691 | 692 | EXPORT XplBool _WJECloseDocument(WJElement document, const char *file, const int line) 693 | { 694 | _WJElement *current = (_WJElement *) document; 695 | WJElement child; 696 | 697 | if (!document) { 698 | return(FALSE); 699 | } 700 | 701 | WJEDetach(document); 702 | 703 | if (document->freecb && !document->freecb(document)) { 704 | /* The callback has prevented free'ing the document */ 705 | return(TRUE); 706 | } 707 | 708 | WJEChanged(document); 709 | 710 | /* Remove references to this object */ 711 | if (document->parent) { 712 | if (document->parent->child == document) { 713 | document->parent->child = document->next; 714 | } 715 | if (document->parent->last == document) { 716 | document->parent->last = document->prev; 717 | } 718 | document->parent->count--; 719 | } 720 | 721 | if (document->prev) { 722 | document->prev->next = document->next; 723 | } 724 | 725 | if (document->next) { 726 | document->next->prev = document->prev; 727 | } 728 | 729 | 730 | /* Destroy all children */ 731 | while ((child = document->child)) { 732 | WJEDetach(child); 733 | _WJECloseDocument(child, file, line); 734 | } 735 | 736 | if (current->pub.type == WJR_TYPE_STRING) { 737 | MemFreeEx(current->value.string, file, line); 738 | current->pub.length = 0; 739 | } 740 | 741 | if (document->name && current->_name != document->name) { 742 | MemReleaseEx(&document->name, file, line); 743 | } 744 | 745 | MemFreeEx(current, file, line); 746 | 747 | return(TRUE); 748 | } 749 | 750 | EXPORT void WJEDump(WJElement document) 751 | { 752 | WJEWriteFILE(document, stdout); 753 | } 754 | 755 | EXPORT void WJEWriteFILE(WJElement document, FILE* fd) 756 | { 757 | WJWriter dumpWriter; 758 | 759 | if ((dumpWriter = WJWOpenFILEDocument(TRUE, fd))) { 760 | WJEWriteDocument(document, dumpWriter, NULL); 761 | WJWCloseDocument(dumpWriter); 762 | } 763 | fprintf(fd, "\n"); 764 | fflush(fd); 765 | } 766 | 767 | EXPORT void WJEDumpFile(WJElement document) 768 | { 769 | WJWriter dumpWriter; 770 | FILE *file; 771 | char path[1024]; 772 | 773 | strprintf(path, sizeof(path), NULL, "%08lx.json", (long) time(NULL)); 774 | 775 | if ((file = fopen(path, "wb"))) { 776 | if ((dumpWriter = WJWOpenFILEDocument(TRUE, file))) { 777 | WJEWriteDocument(document, dumpWriter, NULL); 778 | WJWCloseDocument(dumpWriter); 779 | } 780 | fprintf(file, "\n"); 781 | fclose(file); 782 | 783 | printf("Dumped JSON document to %s\n", path); 784 | } 785 | } 786 | 787 | static size_t fileReaderCB( char *data, size_t length, size_t seen, void *client ) 788 | { 789 | DebugAssert(length); 790 | DebugAssert(data); 791 | if(!data) { 792 | return 0; 793 | } 794 | return fread(data, 1, length, client); 795 | } 796 | 797 | EXPORT WJElement WJEReadFILE(FILE* fd) 798 | { 799 | WJReader reader; 800 | WJElement obj = NULL; 801 | 802 | if ((reader = WJROpenDocument(fileReaderCB, fd, NULL, 0))) { 803 | obj = WJEOpenDocument(reader, NULL, NULL, NULL); 804 | WJRCloseDocument(reader); 805 | } 806 | return obj; 807 | } 808 | 809 | EXPORT void WJEMemFree(void *mem) 810 | { 811 | if(mem != NULL) { 812 | MemFree(mem); 813 | } 814 | } 815 | EXPORT void WJEMemRelease(void **mem) 816 | { 817 | if(mem != NULL && *mem != NULL) { 818 | MemRelease(mem); 819 | } 820 | } 821 | -------------------------------------------------------------------------------- /src/wjelement/element.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | #ifndef __WJ_ELEMENT_P_H 19 | #define __WJ_ELEMENT_P_H 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | 30 | typedef struct { 31 | WJElementPublic pub; 32 | WJElementPublic *parent; 33 | 34 | union { 35 | char *string; 36 | XplBool boolean; 37 | 38 | struct { 39 | uint64 i; 40 | double d; 41 | 42 | XplBool hasDecimalPoint; 43 | XplBool negative; 44 | } number; 45 | } value; 46 | 47 | char _name[]; 48 | } _WJElement; 49 | 50 | /* element.c */ 51 | _WJElement * _WJENew(_WJElement *parent, char *name, size_t len, const char *file, int line); 52 | _WJElement * _WJEReset(_WJElement *e, WJRType type); 53 | 54 | /* search.c */ 55 | typedef int (* WJEMatchCB)(WJElement root, WJElement parent, WJElement e, WJEAction action, char *name, size_t len); 56 | WJElement WJESearch(WJElement container, const char *path, WJEAction *action, WJElement last, const char *file, const int line); 57 | 58 | /* 59 | Allow a few extra characters in dot seperated alpha numeric names for the 60 | sake of backwards compatability. 61 | */ 62 | #define isalnumx(c) ( \ 63 | isalnum((c)) || \ 64 | ' ' == (c) || \ 65 | '_' == (c) || \ 66 | '-' == (c) \ 67 | ) 68 | 69 | 70 | /* The upper bits of the action may contain modifier flags */ 71 | #define WJE_ACTION_MASK 0x0000ffff 72 | 73 | /* 74 | Helpers to deal with string comparisons taking into account the 75 | WJE_IGNORE_CASE flag. 76 | */ 77 | #define wstrcmp(a, b, actionval) (((actionval) & WJE_IGNORE_CASE) ? \ 78 | stricmp((a), (b)) : \ 79 | strcmp((a), (b))) 80 | 81 | #define wstrncmp(a, b, l, actionval) (((actionval) & WJE_IGNORE_CASE) ? \ 82 | strnicmp((a), (b), (l)) : \ 83 | strncmp((a), (b), (l))) 84 | 85 | 86 | /* 87 | The following macros allow using many internal functions against a public 88 | WJElement or a private _WJElement * without needing to cast the arguments or 89 | result. 90 | 91 | A function with a leading _ indicates that it uses the private versions, and 92 | without uses the public. 93 | 94 | This convention is not used on exported functions, which use a leading _ to 95 | indicate an advanced version of the function. 96 | */ 97 | #define WJENew(p, n, l, f, ln) (WJElement) _WJENew((_WJElement *) (p), (n), (l), (f), (ln)) 98 | #define WJEReset(e, t) (WJElement) _WJEReset((_WJElement *) (e), t) 99 | #define _WJESearch(c, p, a, l, f, ln) (_WJElement *) WJESearch((c), (p), (a), (l), (f), (ln)) 100 | 101 | void WJEChanged(WJElement element); 102 | #define _WJEChanged(e) WJEChanged((WJElement) (e)) 103 | 104 | #endif // __WJ_ELEMENT_P_H 105 | -------------------------------------------------------------------------------- /src/wjelement/hash.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | #include "element.h" 19 | #include 20 | 21 | static void _WJEHash(WJElement document, int depth, WJEHashCB update, void *context) 22 | { 23 | WJElement child; 24 | char *s; 25 | int32 n; 26 | uint32 b; 27 | 28 | if (!document) { 29 | return; 30 | } 31 | 32 | switch (document->type) { 33 | default: 34 | case WJR_TYPE_UNKNOWN: 35 | break; 36 | 37 | case WJR_TYPE_NULL: 38 | update(context, "", 1); 39 | break; 40 | 41 | case WJR_TYPE_OBJECT: 42 | update(context, &depth, sizeof(depth)); 43 | 44 | for (child = document->child; child; child = child->next) { 45 | if (child->name) { 46 | update(context, child->name, strlen(child->name) + 1); 47 | } 48 | _WJEHash(child, depth + 1, update, context); 49 | } 50 | 51 | update(context, &depth, sizeof(depth)); 52 | break; 53 | 54 | case WJR_TYPE_ARRAY: 55 | update(context, &depth, sizeof(depth)); 56 | 57 | for (child = document->child; child; child = child->next) { 58 | update(context, "", 1); 59 | _WJEHash(child, depth + 1, update, context); 60 | } 61 | 62 | update(context, &depth, sizeof(depth)); 63 | break; 64 | 65 | case WJR_TYPE_STRING: 66 | if ((s = WJEString(document, NULL, WJE_GET, ""))) { 67 | update(context, s, strlen(s) + 1); 68 | } 69 | 70 | break; 71 | 72 | case WJR_TYPE_NUMBER: 73 | #ifdef WJE_DISTINGUISH_INTEGER_TYPE 74 | case WJR_TYPE_INTEGER: 75 | #endif 76 | n = WJENumber(document, NULL, WJE_GET, 0); 77 | update(context, &n, sizeof(n)); 78 | 79 | break; 80 | 81 | case WJR_TYPE_TRUE: 82 | case WJR_TYPE_BOOL: 83 | case WJR_TYPE_FALSE: 84 | b = WJEBool(document, NULL, WJE_GET, FALSE); 85 | update(context, &b, sizeof(b)); 86 | break; 87 | } 88 | } 89 | 90 | EXPORT void WJEHash(WJElement document, WJEHashCB update, void *context) 91 | { 92 | _WJEHash(document, 0, update, context); 93 | } 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/wjreader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(wjreader 2 | wjreader.c 3 | ) 4 | 5 | target_link_libraries(wjreader 6 | xpl 7 | ${ALL_LIBS} 8 | ) 9 | 10 | SET_TARGET_PROPERTIES( 11 | wjreader 12 | PROPERTIES 13 | VERSION 1.0.0 14 | SOVERSION 1 15 | INSTALL_NAME_DIR "${LIB_DEST_DIR}" 16 | ) 17 | 18 | install(TARGETS wjreader 19 | LIBRARY DESTINATION ${LIB_DEST_DIR} 20 | ARCHIVE DESTINATION ${LIB_DEST_DIR} 21 | ) 22 | -------------------------------------------------------------------------------- /src/wjwriter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(wjwriter 2 | wjwriter.c 3 | ) 4 | 5 | target_link_libraries(wjwriter 6 | xpl 7 | ${ALL_LIBS} 8 | ) 9 | #link_directories($(MPLUS_GUARDIAN_BINARY_DIR)/src/libs/wjwriter) 10 | 11 | SET_TARGET_PROPERTIES( 12 | wjwriter 13 | PROPERTIES 14 | VERSION 1.0.0 15 | SOVERSION 1 16 | INSTALL_NAME_DIR "${LIB_DEST_DIR}" 17 | ) 18 | 19 | 20 | install(TARGETS wjwriter 21 | LIBRARY DESTINATION ${LIB_DEST_DIR} 22 | ARCHIVE DESTINATION ${LIB_DEST_DIR} 23 | ) 24 | -------------------------------------------------------------------------------- /src/wjwriter/wjwriter.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of WJElement. 3 | 4 | WJElement is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Lesser General Public License as published 6 | by the Free Software Foundation. 7 | 8 | WJElement is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU Lesser General Public License for more details. 12 | 13 | You should have received a copy of the GNU Lesser General Public License 14 | along with WJElement. If not, see . 15 | */ 16 | 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #if defined(_MSC_VER) 28 | #include 29 | typedef SSIZE_T ssize_t; 30 | #endif 31 | 32 | /* 33 | JSON syntax (http://www.json.org/) 34 | ================================== 35 | object 36 | {} 37 | { members } 38 | 39 | members 40 | pair 41 | pair , members 42 | 43 | pair 44 | string : value 45 | 46 | array 47 | [] 48 | [ elements ] 49 | 50 | elements 51 | value 52 | value , elements 53 | 54 | value 55 | string 56 | number 57 | object 58 | array 59 | true 60 | false 61 | null 62 | 63 | string 64 | "" 65 | "chars" 66 | 67 | chars 68 | char 69 | char chars 70 | 71 | char 72 | any-Unicode-character- except-"-or-\-or- control-character 73 | \" 74 | \\ 75 | \/ 76 | \b 77 | \f 78 | \n 79 | \r 80 | \t 81 | \u four-hex-digits 82 | 83 | number 84 | int 85 | int frac 86 | int exp 87 | int frac exp 88 | 89 | int 90 | digit 91 | digit1-9 digits 92 | - digit 93 | - digit1-9 digits 94 | 95 | frac 96 | . digits 97 | 98 | exp 99 | e digits 100 | digits 101 | digit 102 | digit digits 103 | 104 | e 105 | e 106 | e+ 107 | e- 108 | E 109 | E+ 110 | E- 111 | 112 | Complex JSON Document Example 113 | ============================= 114 | 115 | A complex JSON object: 116 | 117 | { 118 | "string1" : "This is a string", 119 | "bool1" : true, 120 | "bool2" : false, 121 | "object1" : { 122 | "string2" : "This is another string", 123 | "array1" : [ 124 | "one", 125 | false, 126 | 92, 127 | "two" 128 | ], 129 | "array2" : [ 130 | array3 : [ 1, 2, 3 ] 131 | ], 132 | "array4" : [ ] 133 | }, 134 | "tricky":"foo","ugg":{"1":1,"2":2,"3:"3,"four":[1,2,3,4]} 135 | } 136 | */ 137 | 138 | typedef struct { 139 | WJWriterPublic public; 140 | 141 | /* 142 | If the document, or an object, or an array have just been opened then 143 | the next value should not have a comma. All other values must be 144 | preceded with a comma. 145 | */ 146 | XplBool skipcomma; 147 | XplBool skipbreak; 148 | XplBool instring; 149 | int depth; 150 | 151 | size_t size; 152 | size_t used; 153 | char buffer[1]; 154 | } WJIWriter; 155 | 156 | static int WJWrite(WJIWriter *doc, char *data, size_t length) 157 | { 158 | size_t result = 0; 159 | size_t size; 160 | int offset; 161 | 162 | if (doc && !doc->size) { 163 | if (doc->public.write.cb) { 164 | return(doc->public.write.cb(data, length, doc->public.write.data)); 165 | } else { 166 | return(0); 167 | } 168 | } 169 | 170 | if (!doc || !doc->public.write.cb) { 171 | return(0); 172 | } 173 | 174 | DebugAssert(doc->used <= doc->size); 175 | while (length) { 176 | /* Fill our buffer as much as possible */ 177 | if (doc->used < doc->size) { 178 | size = xpl_min(length, doc->size - doc->used); 179 | 180 | memcpy(doc->buffer + doc->used, data, size); 181 | result += size; 182 | doc->used += size; 183 | data += size; 184 | length -= size; 185 | } 186 | 187 | /* Flush the buffer to make room for any data that didn't fit */ 188 | offset = 0; 189 | while (offset < doc->used && 190 | ((doc->size - doc->used) + offset) < length 191 | ) { 192 | size = doc->public.write.cb(doc->buffer + offset, doc->used - offset, 193 | doc->public.write.data); 194 | DebugAssert((signed int) size >= 0 && size <= doc->used - offset); 195 | offset += size; 196 | 197 | if (!size) { 198 | /* The callback failed */ 199 | doc->public.write.cb = NULL; 200 | doc->used -= offset; 201 | 202 | DebugAssert(doc->used <= doc->size); 203 | return(result); 204 | } 205 | } 206 | doc->used -= offset; 207 | 208 | /* Reallign to the begining of the buffer */ 209 | if (doc->used) { 210 | memmove(doc->buffer, doc->buffer + offset, doc->used); 211 | } 212 | 213 | /* 214 | If the data still won't fit in the buffer after flushing as much as 215 | possible then attempt to send it directly. 216 | */ 217 | if (length > (doc->size - doc->used)) { 218 | size = doc->public.write.cb(data, length, doc->public.write.data); 219 | DebugAssert((signed int) size >= 0 && size <= length); 220 | 221 | result += size; 222 | data += size; 223 | length -= size; 224 | } 225 | } 226 | 227 | DebugAssert(doc->used <= doc->size); 228 | doc->buffer[doc->used] = '\0'; 229 | return(result); 230 | } 231 | 232 | EXPORT WJWriter _WJWOpenDocument(XplBool pretty, WJWriteCallback callback, void *writedata, size_t buffersize) 233 | { 234 | WJIWriter *doc = NULL; 235 | size_t size = buffersize; 236 | 237 | if (!callback) { 238 | errno = EINVAL; 239 | return(NULL); 240 | } 241 | 242 | if (size < sizeof(WJIWriter)) { 243 | size = sizeof(WJIWriter); 244 | } 245 | 246 | doc = MemMallocEx(NULL, size, &size, TRUE, FALSE); 247 | memset(doc, 0, sizeof(WJIWriter)); 248 | 249 | doc->public.write.cb = callback; 250 | doc->public.write.data = writedata; 251 | if (buffersize != 0) { 252 | /* 253 | Use the avaliable size returned by MemMallocEx so that the write 254 | buffer is at least buffersize, but may be larger. 255 | */ 256 | doc->size = size - sizeof(WJIWriter); 257 | } else { 258 | /* 259 | Specifying a buffer size of 0 disables WJWriter buffering entirely 260 | which is important when using a callback that writes to a buffered 261 | interface to prevent double buffering. 262 | */ 263 | doc->size = 0; 264 | } 265 | 266 | /* 267 | The first value after opening a document should not be preceded by a 268 | comma. skipcomma will be reset after reading that first value. 269 | */ 270 | doc->public.pretty = pretty; 271 | doc->public.escapeInvalidChars = TRUE; 272 | doc->public.base = 10; 273 | doc->skipcomma = TRUE; 274 | doc->skipbreak = TRUE; 275 | 276 | return((WJWriter) doc); 277 | } 278 | 279 | EXPORT XplBool WJWCloseDocument(WJWriter indoc) 280 | { 281 | WJIWriter *doc = (WJIWriter *)indoc; 282 | XplBool result = FALSE; 283 | 284 | if (doc) { 285 | if (doc->size) { 286 | size_t size; 287 | size_t offset; 288 | 289 | DebugAssert(doc->used <= doc->size); 290 | 291 | /* Write any remaining buffered data */ 292 | offset = 0; 293 | while (doc->public.write.cb && offset < doc->used) { 294 | size = doc->public.write.cb(doc->buffer + offset, doc->used - offset, 295 | doc->public.write.data); 296 | DebugAssert((signed int) size >= 0 && size <= doc->used - offset); 297 | offset += size; 298 | 299 | if (!size) { 300 | /* The callback failed */ 301 | doc->public.write.cb = NULL; 302 | doc->used -= offset; 303 | break; 304 | } 305 | } 306 | doc->used -= offset; 307 | DebugAssert(doc->used <= doc->size); 308 | } 309 | 310 | if (doc->public.user.freecb) { 311 | doc->public.user.freecb(doc->public.user.data); 312 | } 313 | 314 | if (doc->public.write.cb) { 315 | /* If the callback is still set then there where no errors */ 316 | result = TRUE; 317 | } 318 | 319 | MemFree(doc); 320 | } 321 | 322 | return(result); 323 | } 324 | 325 | /* 326 | Helper Open Functions 327 | 328 | Open a JSON document using pre-canned callback functions which can read from 329 | common data sources, such as an open file, or an open connection. 330 | */ 331 | EXPORT size_t WJWFileCallback(char *buffer, size_t length, void *data) 332 | { 333 | if (data) { 334 | return((int)fwrite(buffer, sizeof(char), length, (FILE *)data)); 335 | } 336 | 337 | return(0); 338 | } 339 | 340 | static size_t WJWMemCallback(char *buffer, size_t length, void *data) 341 | { 342 | char **mem = data; 343 | size_t l; 344 | 345 | if (mem) { 346 | if (!*mem) { 347 | *mem = MemMallocWait(length + 1); 348 | memcpy(*mem, buffer, length); 349 | (*mem)[length] = '\0'; 350 | } else { 351 | l = strlen(*mem); 352 | 353 | *mem = MemReallocWait(*mem, l + length + 1); 354 | memcpy(*mem + l, buffer, length); 355 | (*mem)[l + length] = '\0'; 356 | } 357 | 358 | return(length); 359 | } 360 | 361 | return(0); 362 | } 363 | 364 | EXPORT WJWriter WJWOpenMemDocument(XplBool pretty, char **mem) 365 | { 366 | if (!mem) { 367 | return(NULL); 368 | } 369 | 370 | return(_WJWOpenDocument(pretty, WJWMemCallback, mem, 0)); 371 | } 372 | 373 | /* 374 | Verify that str points to a valid UTF8 character, and return the length of 375 | that character in bytes. If the value is not a full valid UTF8 character 376 | then -1 will be returned. 377 | */ 378 | static ssize_t WJWUTF8CharSize(char *str, size_t length) 379 | { 380 | ssize_t r = -1; 381 | unsigned char test; 382 | int i; 383 | 384 | if (!str || !length) { 385 | return(0); 386 | } 387 | 388 | test = (unsigned char) *str; 389 | 390 | if (!(test & 0x80)) { 391 | /* ASCII */ 392 | return(1); 393 | } else if ((test & 0xC0) == 0x80) { 394 | /* 395 | This is not a primary octet of a UTF8 char, but is valid as any 396 | other octet of the UTf8 char. 397 | */ 398 | return(-1); 399 | } else if ((test & 0xE0) == 0xC0) { 400 | if (test == 0xC0 || test == 0xC1) { 401 | /* redundant code point. */ 402 | return(-1); 403 | } 404 | r = 2; 405 | } else if ((test & 0xF0) == 0xE0) { 406 | r = 3; 407 | } else if ((test & 0xF8) == 0xF0) { 408 | if ((test & 0x07) >= 0x05) { 409 | /* undefined character range. RFC 3629 */ 410 | return(-1); 411 | } 412 | 413 | r = 4; 414 | } else { 415 | /* 416 | Originally there was room for (more 4,) 5 and 6 byte characters but 417 | these where outlawed by RFC 3629. 418 | */ 419 | return(-1); 420 | } 421 | 422 | if (r > length) { 423 | r = length; 424 | } 425 | 426 | for (i = 1; i < r; i++) { 427 | if (((unsigned char)(str[i]) & 0xC0) != 0x80) { 428 | /* This value is not valid as a non-primary UTF8 octet */ 429 | return(-1); 430 | } 431 | } 432 | 433 | return(r); 434 | } 435 | 436 | static XplBool WJWriteString(char *value, size_t length, XplBool done, WJIWriter *doc) 437 | { 438 | char *v; 439 | char *e; 440 | ssize_t l; 441 | char esc[3]; 442 | 443 | if (!doc || !doc->public.write.cb) { 444 | return(FALSE); 445 | } 446 | 447 | if (!doc->instring) { 448 | WJWrite(doc, "\"", 1); 449 | } 450 | 451 | *(esc + 0) = '\\'; 452 | *(esc + 1) = '\0'; 453 | *(esc + 2) = '\0'; 454 | 455 | for (v = e = value; e < value + length; e++) { 456 | switch (*e) { 457 | case '\\': *(esc + 1) = '\\'; break; 458 | case '"': *(esc + 1) = '"'; break; 459 | case '\n': *(esc + 1) = 'n'; break; 460 | case '\b': *(esc + 1) = 'b'; break; 461 | case '\t': *(esc + 1) = 't'; break; 462 | case '\f': *(esc + 1) = 'f'; break; 463 | case '\r': *(esc + 1) = 'r'; break; 464 | 465 | default: 466 | l = WJWUTF8CharSize(e, length - (e - value)); 467 | if (l > 1 || (l == 1 && *e >= '\x20')) { 468 | /* 469 | *e is the primary octect of a multi-octet UTF8 470 | character. The remaining characters have been verified 471 | as valid UTF8 and can be skipped. 472 | */ 473 | e += (l - 1); 474 | } else if (l == 1) { 475 | /* 476 | *e is valid UTF8 but is not a printable character, and 477 | will be escaped before being sent, using the 478 | JSON-standard "\u00xx" form 479 | */ 480 | char unicodeHex[sizeof("\\u0000")]; 481 | 482 | WJWrite(doc, v, e - v); 483 | 484 | sprintf(unicodeHex, "\\u00%02x", (unsigned char) *e); 485 | WJWrite(doc, unicodeHex, sizeof(unicodeHex)-1); 486 | 487 | v = e + 1; 488 | } else if (l < 0) { 489 | /* 490 | *e is not valid UTF8 data, and must be escaped before 491 | being sent. But JSON-standard does not give us a 492 | mechanism so we chose "\xhh" format because of its 493 | almost universal comprehension. 494 | */ 495 | char nonUnicodeHex[sizeof("\\x00")]; 496 | 497 | WJWrite(doc, v, e - v); 498 | 499 | if (doc->public.escapeInvalidChars) { 500 | sprintf(nonUnicodeHex, "\\x%02x", (unsigned char) *e); 501 | WJWrite(doc, nonUnicodeHex, sizeof(nonUnicodeHex)-1); 502 | } 503 | 504 | v = e + 1; 505 | } 506 | continue; 507 | } 508 | 509 | WJWrite(doc, v, e - v); 510 | v = e + 1; 511 | 512 | WJWrite(doc, esc, 2); 513 | continue; 514 | } 515 | 516 | WJWrite(doc, v, length - (v - value)); 517 | 518 | if (done) { 519 | WJWrite(doc, "\"", 1); 520 | } 521 | doc->instring = !done; 522 | return(TRUE); 523 | } 524 | 525 | EXPORT XplBool WJWOpenArray(char *name, WJWriter indoc) 526 | { 527 | WJIWriter *doc = (WJIWriter *)indoc; 528 | 529 | if (doc && doc->public.write.cb) { 530 | if (doc->public.pretty) { 531 | int i; 532 | 533 | if (!doc->skipcomma) { 534 | WJWrite(doc, ",", 1); 535 | } 536 | 537 | if (!doc->skipbreak) { 538 | WJWrite(doc, "\n", 1); 539 | } 540 | doc->skipbreak = FALSE; 541 | 542 | for (i = 0; i < doc->depth; i++) { 543 | WJWrite(doc, "\t", 1); 544 | } 545 | } else if (!doc->skipcomma) { 546 | WJWrite(doc, ",", 1); 547 | } 548 | 549 | doc->depth++; 550 | 551 | if (name) { 552 | WJWriteString(name, strlen(name), TRUE, doc); 553 | WJWrite(doc, ":", 1); 554 | } 555 | 556 | doc->skipcomma = TRUE; 557 | return(1 == WJWrite(doc, "[", 1)); 558 | } 559 | 560 | return(FALSE); 561 | } 562 | 563 | EXPORT XplBool WJWCloseArray(WJWriter indoc) 564 | { 565 | WJIWriter *doc = (WJIWriter *)indoc; 566 | 567 | if (doc && doc->public.write.cb) { 568 | if (doc->depth > 0) { 569 | doc->depth--; 570 | } 571 | 572 | if (doc->public.pretty) { 573 | int i; 574 | 575 | WJWrite(doc, "\n", 1); 576 | for (i = 0; i < doc->depth; i++) { 577 | WJWrite(doc, "\t", 1); 578 | } 579 | } 580 | 581 | doc->skipcomma = FALSE; 582 | return(1 == WJWrite(doc, "]", 1)); 583 | } 584 | 585 | return(FALSE); 586 | } 587 | 588 | EXPORT XplBool WJWOpenObject(char *name, WJWriter indoc) 589 | { 590 | WJIWriter *doc = (WJIWriter *)indoc; 591 | 592 | if (doc && doc->public.write.cb) { 593 | if (doc->public.pretty) { 594 | int i; 595 | 596 | if (!doc->skipcomma) { 597 | WJWrite(doc, ",", 1); 598 | } 599 | 600 | if (!doc->skipbreak) { 601 | WJWrite(doc, "\n", 1); 602 | } 603 | doc->skipbreak = FALSE; 604 | for (i = 0; i < doc->depth; i++) { 605 | WJWrite(doc, "\t", 1); 606 | } 607 | } else if (!doc->skipcomma) { 608 | WJWrite(doc, ",", 1); 609 | } 610 | 611 | doc->depth++; 612 | 613 | if (name) { 614 | WJWriteString(name, strlen(name), TRUE, doc); 615 | WJWrite(doc, ":", 1); 616 | } 617 | 618 | doc->skipcomma = TRUE; 619 | return(1 == WJWrite(doc, "{", 1)); 620 | } 621 | 622 | return(FALSE); 623 | } 624 | 625 | EXPORT XplBool WJWCloseObject(WJWriter indoc) 626 | { 627 | WJIWriter *doc = (WJIWriter *)indoc; 628 | 629 | if (doc && doc->public.write.cb) { 630 | if (doc->depth > 0) { 631 | doc->depth--; 632 | } 633 | 634 | if (doc->public.pretty) { 635 | int i; 636 | 637 | WJWrite(doc, "\n", 1); 638 | for (i = 0; i < doc->depth; i++) { 639 | WJWrite(doc, "\t", 1); 640 | } 641 | } 642 | 643 | doc->skipcomma = FALSE; 644 | return(1 == WJWrite(doc, "}", 1)); 645 | } 646 | 647 | return(FALSE); 648 | } 649 | 650 | EXPORT XplBool WJWStringN(char *name, char *value, size_t length, XplBool done, WJWriter indoc) 651 | { 652 | WJIWriter *doc = (WJIWriter *)indoc; 653 | 654 | if (doc && doc->public.write.cb && value) { 655 | if (!doc->instring) { 656 | if (doc->public.pretty) { 657 | int i; 658 | 659 | if (!doc->skipcomma) { 660 | WJWrite(doc, ",", 1); 661 | } 662 | 663 | WJWrite(doc, "\n", 1); 664 | for (i = 0; i < doc->depth; i++) { 665 | WJWrite(doc, "\t", 1); 666 | } 667 | } else if (!doc->skipcomma) { 668 | WJWrite(doc, ",", 1); 669 | } 670 | doc->skipcomma = FALSE; 671 | 672 | if (name) { 673 | WJWriteString(name, strlen(name), TRUE, doc); 674 | WJWrite(doc, ":", 1); 675 | } 676 | } 677 | 678 | return(WJWriteString(value, length, done, doc)); 679 | } 680 | 681 | return(FALSE); 682 | } 683 | 684 | EXPORT XplBool WJWString(char *name, char *value, XplBool done, WJWriter doc) 685 | { 686 | if (value) { 687 | return(WJWStringN(name, value, strlen(value), done, doc)); 688 | } else { 689 | return(WJWStringN(name, "", 0, done, doc)); 690 | } 691 | } 692 | 693 | static XplBool WJWNumber(char *name, char *value, size_t size, WJWriter indoc) 694 | { 695 | WJIWriter *doc = (WJIWriter *)indoc; 696 | 697 | if (doc && doc->public.write.cb) { 698 | if (doc->public.pretty) { 699 | int i; 700 | 701 | if (!doc->skipcomma) { 702 | WJWrite(doc, ",", 1); 703 | } 704 | 705 | WJWrite(doc, "\n", 1); 706 | for (i = 0; i < doc->depth; i++) { 707 | WJWrite(doc, "\t", 1); 708 | } 709 | } else if (!doc->skipcomma) { 710 | WJWrite(doc, ",", 1); 711 | } 712 | 713 | doc->skipcomma = FALSE; 714 | 715 | if (name) { 716 | WJWriteString(name, strlen(name), TRUE, doc); 717 | WJWrite(doc, ":", 1); 718 | } 719 | 720 | if (size > 0) { 721 | size -= WJWrite(doc, value, size); 722 | return(size == 0); 723 | } 724 | } 725 | 726 | return(FALSE); 727 | } 728 | 729 | EXPORT XplBool WJWInt32(char *name, int32 value, WJWriter doc) 730 | { 731 | char v[256]; 732 | size_t s; 733 | 734 | switch (doc->base) { 735 | default: 736 | case 10: 737 | s = strprintf(v, sizeof(v), NULL, "%ld", (long) value); 738 | break; 739 | case 16: 740 | s = strprintf(v, sizeof(v), NULL, "0x%08lx", (long) value); 741 | break; 742 | 743 | case 8: 744 | s = strprintf(v, sizeof(v), NULL, "0%lo", (long) value); 745 | break; 746 | } 747 | 748 | return(WJWNumber(name, v, s, doc)); 749 | } 750 | 751 | EXPORT XplBool WJWUInt32(char *name, uint32 value, WJWriter doc) 752 | { 753 | char v[256]; 754 | size_t s; 755 | 756 | switch (doc->base) { 757 | default: 758 | case 10: 759 | s = strprintf(v, sizeof(v), NULL, "%lu", (unsigned long) value); 760 | break; 761 | 762 | case 16: 763 | s = strprintf(v, sizeof(v), NULL, "0x%08lx", (unsigned long) value); 764 | break; 765 | 766 | case 8: 767 | s = strprintf(v, sizeof(v), NULL, "0%lo", (unsigned long) value); 768 | break; 769 | } 770 | 771 | return(WJWNumber(name, v, s, doc)); 772 | } 773 | 774 | EXPORT XplBool WJWInt64(char *name, int64 value, WJWriter doc) 775 | { 776 | char v[256]; 777 | size_t s; 778 | 779 | switch (doc->base) { 780 | default: 781 | case 10: 782 | s = strprintf(v, sizeof(v), NULL, "%lld", (long long) value); 783 | break; 784 | 785 | case 16: 786 | s = strprintf(v, sizeof(v), NULL, "0x%016llx", (long long) value); 787 | break; 788 | 789 | case 8: 790 | s = strprintf(v, sizeof(v), NULL, "0%llo", (long long) value); 791 | break; 792 | } 793 | 794 | return(WJWNumber(name, v, s, doc)); 795 | } 796 | 797 | EXPORT XplBool WJWUInt64(char *name, uint64 value, WJWriter doc) 798 | { 799 | char v[256]; 800 | size_t s; 801 | 802 | switch (doc->base) { 803 | default: 804 | case 10: 805 | s = strprintf(v, sizeof(v), NULL, "%llu", (unsigned long long) value); 806 | break; 807 | 808 | case 16: 809 | s = strprintf(v, sizeof(v), NULL, "0x%016llx", (unsigned long long) value); 810 | break; 811 | 812 | case 8: 813 | s = strprintf(v, sizeof(v), NULL, "0%llo", (unsigned long long) value); 814 | break; 815 | } 816 | 817 | return(WJWNumber(name, v, s, doc)); 818 | } 819 | 820 | EXPORT XplBool WJWDouble(char *name, double value, WJWriter doc) 821 | { 822 | char v[256]; 823 | size_t s; 824 | 825 | s = strprintf(v, sizeof(v), NULL, "%e", value); 826 | return(WJWNumber(name, v, s, doc)); 827 | } 828 | 829 | EXPORT XplBool WJWBoolean(char *name, XplBool value, WJWriter indoc) 830 | { 831 | WJIWriter *doc = (WJIWriter *)indoc; 832 | 833 | if (doc && doc->public.write.cb) { 834 | if (doc->public.pretty) { 835 | int i; 836 | 837 | if (!doc->skipcomma) { 838 | WJWrite(doc, ",", 1); 839 | } 840 | 841 | WJWrite(doc, "\n", 1); 842 | for (i = 0; i < doc->depth; i++) { 843 | WJWrite(doc, "\t", 1); 844 | } 845 | } else if (!doc->skipcomma) { 846 | WJWrite(doc, ",", 1); 847 | } 848 | 849 | 850 | doc->skipcomma = FALSE; 851 | 852 | if (name) { 853 | WJWriteString(name, strlen(name), TRUE, doc); 854 | WJWrite(doc, ":", 1); 855 | } 856 | 857 | if (value) { 858 | WJWrite(doc, "true", 4); 859 | } else { 860 | WJWrite(doc, "false", 5); 861 | } 862 | 863 | return(TRUE); 864 | } 865 | 866 | return(FALSE); 867 | } 868 | 869 | EXPORT XplBool WJWNull(char *name, WJWriter indoc) 870 | { 871 | WJIWriter *doc = (WJIWriter *)indoc; 872 | 873 | if (doc && doc->public.write.cb) { 874 | if (doc->public.pretty) { 875 | int i; 876 | 877 | if (!doc->skipcomma) { 878 | WJWrite(doc, ",", 1); 879 | } 880 | 881 | WJWrite(doc, "\n", 1); 882 | for (i = 0; i < doc->depth; i++) { 883 | WJWrite(doc, "\t", 1); 884 | } 885 | } else if (!doc->skipcomma) { 886 | WJWrite(doc, ",", 1); 887 | } 888 | 889 | doc->skipcomma = FALSE; 890 | 891 | if (name) { 892 | WJWriteString(name, strlen(name), TRUE, doc); 893 | return(6 == WJWrite(doc, ":null", 5)); 894 | } else { 895 | return(4 == WJWrite(doc, "null", 4)); 896 | } 897 | } 898 | 899 | return(FALSE); 900 | } 901 | 902 | EXPORT XplBool WJWRawValue(char *name, char *value, XplBool done, WJWriter indoc) 903 | { 904 | WJIWriter *doc = (WJIWriter *)indoc; 905 | 906 | if (doc && doc->public.write.cb) { 907 | if (!doc->instring) { 908 | if (doc->public.pretty) { 909 | if (!doc->skipcomma) { 910 | WJWrite(doc, ",", 1); 911 | } 912 | 913 | WJWrite(doc, "\n", 1); 914 | /* 915 | Don't indent, because the raw value will not be indented to 916 | match. Its up to the caller to prettify their JSON 917 | */ 918 | } else if (!doc->skipcomma) { 919 | WJWrite(doc, ",", 1); 920 | } 921 | 922 | doc->skipcomma = FALSE; 923 | 924 | if (name) { 925 | WJWriteString(name, strlen(name), TRUE, doc); 926 | WJWrite(doc, ":", 1); 927 | } 928 | } 929 | 930 | doc->instring = !done; 931 | return(strlen(value) == WJWrite(doc, value, strlen(value))); 932 | } 933 | 934 | return(FALSE); 935 | } 936 | 937 | -------------------------------------------------------------------------------- /windows/wjelement-VC100.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C++ Express 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wjelement", "wjelement-VC100.vcxproj", "{978C7161-A255-4C13-8B2B-910F9A7FA557}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Debug|Win32.Build.0 = Debug|Win32 16 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Debug|x64.ActiveCfg = Debug|x64 17 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Debug|x64.Build.0 = Debug|x64 18 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Release|Win32.ActiveCfg = Release|Win32 19 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Release|Win32.Build.0 = Release|Win32 20 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Release|x64.ActiveCfg = Release|x64 21 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /windows/wjelement-VC100.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | wjelement 23 | {978C7161-A255-4C13-8B2B-910F9A7FA557} 24 | wjelement 25 | Win32Proj 26 | 27 | 28 | 29 | StaticLibrary 30 | NotSet 31 | true 32 | 33 | 34 | StaticLibrary 35 | NotSet 36 | 37 | 38 | StaticLibrary 39 | Windows7.1SDK 40 | 41 | 42 | StaticLibrary 43 | Windows7.1SDK 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | <_ProjectFileVersion>10.0.40219.1 63 | $(ProjDir)VC100\$(Platform)\$(Configuration)\ 64 | $(OutDir) 65 | $(ProjDir)VC100\$(Platform)\$(Configuration)\ 66 | $(OutDir) 67 | $(ProjectName)d 68 | $(ProjectName)d 69 | $(ProjDir)VC100\$(Platform)\$(Configuration)\ 70 | $(OutDir) 71 | $(ProjDir)VC100\$(Platform)\$(Configuration)\ 72 | $(OutDir) 73 | 74 | 75 | 76 | Disabled 77 | ../include;%(AdditionalIncludeDirectories) 78 | WIN32;_DEBUG;_LIB;WJE_DISTINGUISH_INTEGER_TYPE;%(PreprocessorDefinitions) 79 | true 80 | EnableFastChecks 81 | MultiThreadedDebugDLL 82 | NotUsing 83 | Level3 84 | EditAndContinue 85 | 4018;4244;4996;%(DisableSpecificWarnings) 86 | 87 | 88 | $(IntDir)$(TargetName)$(TargetExt) 89 | 90 | 91 | 92 | 93 | MaxSpeed 94 | true 95 | false 96 | ../include;%(AdditionalIncludeDirectories) 97 | WIN32;NDEBUG;_LIB;WJE_DISTINGUISH_INTEGER_TYPE;%(PreprocessorDefinitions) 98 | MultiThreadedDLL 99 | true 100 | NotUsing 101 | Level3 102 | ProgramDatabase 103 | 4018;4244;4996;%(DisableSpecificWarnings) 104 | 105 | 106 | $(IntDir)$(TargetName)$(TargetExt) 107 | 108 | 109 | 110 | 111 | WIN32;_DEBUG;_LIB;WJE_DISTINGUISH_INTEGER_TYPE;%(PreprocessorDefinitions) 112 | ../include;%(AdditionalIncludeDirectories) 113 | 4267;4018;4244;4996;%(DisableSpecificWarnings) 114 | Level3 115 | false 116 | Disabled 117 | true 118 | MultiThreadedDebugDLL 119 | EnableFastChecks 120 | 121 | 122 | $(IntDir)$(ProjectName)d.lib 123 | 124 | 125 | $(IntDir)$(TargetName)$(TargetExt) 126 | 127 | 128 | 129 | 130 | 4267;4018;4244;4996;%(DisableSpecificWarnings) 131 | ../include;%(AdditionalIncludeDirectories) 132 | WIN32;NDEBUG;_LIB;WJE_DISTINGUISH_INTEGER_TYPE;%(PreprocessorDefinitions) 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /windows/wjelement.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wjelement", "wjelement.vcproj", "{978C7161-A255-4C13-8B2B-910F9A7FA557}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Debug|x64 = Debug|x64 10 | Release|Win32 = Release|Win32 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Debug|Win32.ActiveCfg = Debug|Win32 15 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Debug|Win32.Build.0 = Debug|Win32 16 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Debug|x64.ActiveCfg = Debug|x64 17 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Debug|x64.Build.0 = Debug|x64 18 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Release|Win32.ActiveCfg = Release|Win32 19 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Release|Win32.Build.0 = Release|Win32 20 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Release|x64.ActiveCfg = Release|x64 21 | {978C7161-A255-4C13-8B2B-910F9A7FA557}.Release|x64.Build.0 = Release|x64 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /windows/wjelement.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 57 | 60 | 63 | 66 | 70 | 73 | 76 | 79 | 82 | 85 | 86 | 93 | 96 | 99 | 102 | 105 | 109 | 122 | 125 | 128 | 131 | 135 | 138 | 141 | 144 | 147 | 150 | 151 | 159 | 162 | 165 | 168 | 171 | 174 | 188 | 191 | 194 | 197 | 201 | 204 | 207 | 210 | 213 | 216 | 217 | 225 | 228 | 231 | 234 | 237 | 241 | 255 | 258 | 261 | 264 | 268 | 271 | 274 | 277 | 280 | 283 | 284 | 285 | 286 | 287 | 288 | 293 | 296 | 297 | 300 | 301 | 304 | 305 | 308 | 309 | 312 | 313 | 316 | 317 | 320 | 321 | 324 | 325 | 328 | 329 | 330 | 335 | 338 | 339 | 342 | 343 | 346 | 347 | 350 | 351 | 354 | 355 | 358 | 359 | 362 | 363 | 364 | 369 | 370 | 373 | 374 | 375 | 376 | 377 | 378 | --------------------------------------------------------------------------------