Merge pull request #577

32a2633 no longer need to pass the size to rapidjson (Riccardo Spagni)
bd8e0fd add missing miniupnpc files, modify cmake to not build miniupnpc tests and to fix an issue with finding miniupnpcstrings (Riccardo Spagni)
7da9905 updated miniupnpc (Riccardo Spagni)
This commit is contained in:
Riccardo Spagni 2015-12-30 12:28:03 +02:00
commit 7223eebbe7
No known key found for this signature in database
GPG key ID: 55432DF31CCD4FCD
85 changed files with 6441 additions and 2596 deletions

View file

@ -23,3 +23,10 @@ jnaerator-*.jar
miniupnpc.h.bak miniupnpc.h.bak
testupnpreplyparse testupnpreplyparse
validateupnpreplyparse validateupnpreplyparse
testportlistingparse
validateportlistingparse
listdevices
testigddescparse
validateigddescparse
dist/
miniupnpc.egg-info/

View file

@ -2,29 +2,66 @@ cmake_minimum_required (VERSION 2.6)
project (miniupnpc C) project (miniupnpc C)
set (MINIUPNPC_VERSION 1.9) set (MINIUPNPC_VERSION 1.9)
set (MINIUPNPC_API_VERSION 10) set (MINIUPNPC_API_VERSION 15)
if (NOT CMAKE_BUILD_TYPE)
if (WIN32)
set (DEFAULT_BUILD_TYPE MinSizeRel)
else (WIN32)
set (DEFAULT_BUILD_TYPE RelWithDebInfo)
endif(WIN32)
set (CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE} CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()
option (UPNPC_BUILD_STATIC "Build static library" TRUE) option (UPNPC_BUILD_STATIC "Build static library" TRUE)
option (UPNPC_BUILD_SHARED "Build shared library" TRUE) option (UPNPC_BUILD_SHARED "Build shared library" TRUE)
if (NOT WIN32)
option (UPNPC_BUILD_TESTS "Build test executables" FALSE)
endif (NOT WIN32)
option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE) option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE)
mark_as_advanced (NO_GETADDRINFO) mark_as_advanced (NO_GETADDRINFO)
if (NO_GETADDRINFO) if (NO_GETADDRINFO)
add_definitions (-DNO_GETADDRINFO) add_definitions (-DNO_GETADDRINFO)
endif () endif (NO_GETADDRINFO)
if (NOT WIN32) if (NOT WIN32)
add_definitions (-DMINIUPNPC_SET_SOCKET_TIMEOUT) add_definitions (-DMINIUPNPC_SET_SOCKET_TIMEOUT)
add_definitions (-D_BSD_SOURCE -D_POSIX_C_SOURCE=201112) add_definitions (-D_BSD_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200112L)
else () else (NOT WIN32)
add_definitions (-D_WIN32_WINNT=0x0501) # XP or higher for getnameinfo and friends add_definitions (-D_WIN32_WINNT=0x0501) # XP or higher for getnameinfo and friends
endif () endif (NOT WIN32)
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_definitions (-D_DARWIN_C_SOURCE) add_definitions (-D_DARWIN_C_SOURCE)
endif () endif ()
# Set compiler specific build flags
if (CMAKE_COMPILER_IS_GNUC)
# Set our own default flags at first run.
if (NOT CONFIGURED)
if (NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
set (_PIC -fPIC)
endif (CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
set (CMAKE_C_FLAGS "${_PIC} -Wall $ENV{CFLAGS}" # CMAKE_C_FLAGS gets appended to the other C flags
CACHE STRING "Flags used by the C compiler during normal builds." FORCE)
set (CMAKE_C_FLAGS_DEBUG "-g -DDDEBUG"
CACHE STRING "Flags used by the C compiler during debug builds." FORCE)
set (CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG"
CACHE STRING "Flags used by the C compiler during release builds." FORCE)
set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG"
CACHE STRING "Flags used by the C compiler during release builds." FORCE)
set (CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG"
CACHE STRING "Flags used by the C compiler during release builds." FORCE)
endif (NOT CONFIGURED)
endif ()
configure_file (miniupnpcstrings.h.cmake ${CMAKE_BINARY_DIR}/miniupnpcstrings.h) configure_file (miniupnpcstrings.h.cmake ${CMAKE_BINARY_DIR}/miniupnpcstrings.h)
include_directories (${CMAKE_BINARY_DIR}) include_directories (${CMAKE_BINARY_DIR})
@ -33,9 +70,11 @@ set (MINIUPNPC_SOURCES
miniupnpc.c miniupnpc.c
minixml.c minixml.c
minisoap.c minisoap.c
minissdpc.c
miniwget.c miniwget.c
upnpc.c upnpc.c
upnpcommands.c upnpcommands.c
upnpdev.c
upnpreplyparse.c upnpreplyparse.c
upnperrors.c upnperrors.c
connecthostport.c connecthostport.c
@ -43,48 +82,77 @@ set (MINIUPNPC_SOURCES
receivedata.c receivedata.c
) )
if (NOT WIN32) if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
set (MINIUPNPC_SOURCES ${MINIUPNPC_SOURCES} minissdpc.c) set (MINIUPNPC_SOURCES ${MINIUPNPC_SOURCES} minissdpc.c)
endif () endif (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "AmigaOS")
if (WIN32) if (WIN32)
set_source_files_properties (${MINIUPNPC_SOURCES} PROPERTIES set_source_files_properties (${MINIUPNPC_SOURCES} PROPERTIES
COMPILE_DEFINITIONS MINIUPNP_STATICLIB COMPILE_DEFINITIONS "MINIUPNP_STATICLIB;MINIUPNP_EXPORTS"
COMPILE_DEFINITIONS MINIUPNP_EXPORTS
) )
endif () endif (WIN32)
if (WIN32) if (WIN32)
# find_library (WINSOCK2_LIBRARY NAMES ws2_32 WS2_32 Ws2_32) find_library (WINSOCK2_LIBRARY NAMES ws2_32 WS2_32 Ws2_32)
# find_library (IPHLPAPI_LIBRARY NAMES iphlpapi) find_library (IPHLPAPI_LIBRARY NAMES iphlpapi)
set(WINSOCK2_LIBRARY ws2_32)
set(IPHLPAPI_LIBRARY iphlpapi)
set (LDLIBS ${WINSOCK2_LIBRARY} ${IPHLPAPI_LIBRARY} ${LDLIBS}) set (LDLIBS ${WINSOCK2_LIBRARY} ${IPHLPAPI_LIBRARY} ${LDLIBS})
endif () #elseif (CMAKE_SYSTEM_NAME STREQUAL "Solaris")
# find_library (SOCKET_LIBRARY NAMES socket)
# find_library (NSL_LIBRARY NAMES nsl)
# find_library (RESOLV_LIBRARY NAMES resolv)
# set (LDLIBS ${SOCKET_LIBRARY} ${NSL_LIBRARY} ${RESOLV_LIBRARY} ${LDLIBS})
endif (WIN32)
if (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED) if (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED)
message (FATAL "Both shared and static libraries are disabled!") message (FATAL "Both shared and static libraries are disabled!")
endif () endif (NOT UPNPC_BUILD_STATIC AND NOT UPNPC_BUILD_SHARED)
if (UPNPC_BUILD_STATIC) if (UPNPC_BUILD_STATIC)
add_library (upnpc-static STATIC ${MINIUPNPC_SOURCES}) add_library (upnpc-static STATIC ${MINIUPNPC_SOURCES})
set_target_properties (upnpc-static PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
set_target_properties (upnpc-static PROPERTIES OUTPUT_NAME "miniupnpc") set_target_properties (upnpc-static PROPERTIES OUTPUT_NAME "miniupnpc")
target_link_libraries (upnpc-static ${LDLIBS}) target_link_libraries (upnpc-static ${LDLIBS})
set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-static) set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-static)
set (UPNPC_LIBRARY_TARGET upnpc-static) set (UPNPC_LIBRARY_TARGET upnpc-static)
endif () endif (UPNPC_BUILD_STATIC)
if (UPNPC_BUILD_SHARED) if (UPNPC_BUILD_SHARED)
add_library (upnpc-shared SHARED ${MINIUPNPC_SOURCES}) add_library (upnpc-shared SHARED ${MINIUPNPC_SOURCES})
set_target_properties (upnpc-shared PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
set_target_properties (upnpc-shared PROPERTIES OUTPUT_NAME "miniupnpc") set_target_properties (upnpc-shared PROPERTIES OUTPUT_NAME "miniupnpc")
set_target_properties (upnpc-shared PROPERTIES VERSION ${MINIUPNPC_VERSION}) set_target_properties (upnpc-shared PROPERTIES VERSION ${MINIUPNPC_VERSION})
set_target_properties (upnpc-shared PROPERTIES SOVERSION ${MINIUPNPC_API_VERSION}) set_target_properties (upnpc-shared PROPERTIES SOVERSION ${MINIUPNPC_API_VERSION})
target_link_libraries (upnpc-shared ${LDLIBS}) target_link_libraries (upnpc-shared ${LDLIBS})
set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-shared) set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} upnpc-shared)
set (UPNPC_LIBRARY_TARGET upnpc-shared) set (UPNPC_LIBRARY_TARGET upnpc-shared)
endif () endif (UPNPC_BUILD_SHARED)
if (UPNPC_BUILD_TESTS)
add_executable (testminixml testminixml.c minixml.c igd_desc_parse.c)
target_link_libraries (testminixml ${LDLIBS})
add_executable (minixmlvalid minixmlvalid.c minixml.c)
target_link_libraries (minixmlvalid ${LDLIBS})
add_executable (testupnpreplyparse testupnpreplyparse.c
minixml.c upnpreplyparse.c)
target_link_libraries (testupnpreplyparse ${LDLIBS})
add_executable (testigddescparse testigddescparse.c
igd_desc_parse.c minixml.c miniupnpc.c miniwget.c minissdpc.c
upnpcommands.c upnpreplyparse.c minisoap.c connecthostport.c
portlistingparse.c receivedata.c
)
target_link_libraries (testigddescparse ${LDLIBS})
add_executable (testminiwget testminiwget.c
miniwget.c miniupnpc.c minisoap.c upnpcommands.c minissdpc.c
upnpreplyparse.c minixml.c igd_desc_parse.c connecthostport.c
portlistingparse.c receivedata.c
)
target_link_libraries (testminiwget ${LDLIBS})
# set (UPNPC_INSTALL_TARGETS ${UPNPC_INSTALL_TARGETS} testminixml minixmlvalid testupnpreplyparse testigddescparse testminiwget)
endif (UPNPC_BUILD_TESTS)
install (TARGETS ${UPNPC_INSTALL_TARGETS} install (TARGETS ${UPNPC_INSTALL_TARGETS}
RUNTIME DESTINATION bin RUNTIME DESTINATION bin
@ -92,16 +160,19 @@ install (TARGETS ${UPNPC_INSTALL_TARGETS}
ARCHIVE DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX}
) )
install (FILES install (FILES
miniupnpc.h miniupnpc.h
miniwget.h miniwget.h
upnpcommands.h upnpcommands.h
igd_desc_parse.h igd_desc_parse.h
upnpreplyparse.h upnpreplyparse.h
upnperrors.h upnperrors.h
upnpdev.h
miniupnpctypes.h miniupnpctypes.h
portlistingparse.h portlistingparse.h
declspec.h miniupnpc_declspec.h
DESTINATION include/miniupnpc DESTINATION include/miniupnpc
) )
set (CONFIGURED YES CACHE INTERNAL "")
# vim: ts=2:sw=2 # vim: ts=2:sw=2

View file

@ -1,6 +1,73 @@
$Id: Changelog.txt,v 1.198 2014/09/11 14:13:31 nanard Exp $ $Id: Changelog.txt,v 1.219 2015/10/26 17:05:06 nanard Exp $
miniUPnP client Changelog. miniUPnP client Changelog.
2015/10/26:
snprintf() overflow check. check overflow in simpleUPnPcommand2()
2015/10/25:
fix compilation with old macs
fix compilation with mingw32 (for Appveyor)
fix python module for python <= 2.3
2015/10/08:
Change sameport to localport
see https://github.com/miniupnp/miniupnp/pull/120
increments API_VERSION to 15
2015/09/15:
Fix buffer overflow in igd_desc_parse.c/IGDstartelt()
Discovered by Aleksandar Nikolic of Cisco Talos
2015/08/28:
move ssdpDiscoverDevices() to minissdpc.c
2015/08/27:
avoid unix socket leak in getDevicesFromMiniSSDPD()
2015/08/16:
Also accept "Up" as ConnectionStatus value
2015/07/23:
split getDevicesFromMiniSSDPD
add ttl argument to upnpDiscover() functions
increments API_VERSION to 14
2015/07/22:
Read USN from SSDP messages.
2015/07/15:
Check malloc/calloc
2015/06/16:
update getDevicesFromMiniSSDPD() to process longer minissdpd
responses
2015/05/22:
add searchalltypes param to upnpDiscoverDevices()
increments API_VERSION to 13
2015/04/30:
upnpc: output version on the terminal
2015/04/27:
_BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE
fix CMakeLists.txt COMPILE_DEFINITIONS
fix getDevicesFromMiniSSDPD() not setting scope_id
improve -r command of upnpc command line tool
2014/11/17:
search all :
upnpDiscoverDevices() / upnpDiscoverAll() functions
listdevices executable
increment API_VERSION to 12
validate igd_desc_parse
2014/11/13:
increment API_VERSION to 11
2014/11/05:
simplified function GetUPNPUrls()
2014/09/11: 2014/09/11:
use remoteHost arg of DeletePortMapping use remoteHost arg of DeletePortMapping

View file

@ -1,5 +1,5 @@
MiniUPnPc MiniUPnPc
Copyright (c) 2005-2014, Thomas BERNARD Copyright (c) 2005-2015, Thomas BERNARD
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View file

@ -1,9 +1,9 @@
# $Id: Makefile,v 1.110 2014/09/06 08:24:12 nanard Exp $ # $Id: Makefile,v 1.126 2015/08/28 12:14:18 nanard Exp $
# MiniUPnP Project # MiniUPnP Project
# http://miniupnp.free.fr/ # http://miniupnp.free.fr/
# http://miniupnp.tuxfamily.org/ # http://miniupnp.tuxfamily.org/
# https://github.com/miniupnp/miniupnp # https://github.com/miniupnp/miniupnp
# (c) 2005-2014 Thomas Bernard # (c) 2005-2015 Thomas Bernard
# to install use : # to install use :
# $ make DESTDIR=/tmp/dummylocation install # $ make DESTDIR=/tmp/dummylocation install
# or # or
@ -15,6 +15,7 @@ VERSION = $(shell cat VERSION)
ifeq ($(OS), Darwin) ifeq ($(OS), Darwin)
JARSUFFIX=mac JARSUFFIX=mac
LIBTOOL ?= $(shell which libtool)
endif endif
ifeq ($(OS), Linux) ifeq ($(OS), Linux)
JARSUFFIX=linux JARSUFFIX=linux
@ -35,8 +36,15 @@ CFLAGS += -W -Wstrict-prototypes
CFLAGS += -fno-common CFLAGS += -fno-common
CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT
CFLAGS += -DMINIUPNPC_GET_SRC_ADDR CFLAGS += -DMINIUPNPC_GET_SRC_ADDR
CFLAGS += -D_BSD_SOURCE -D_POSIX_C_SOURCE=1 CFLAGS += -D_BSD_SOURCE
CFLAGS += -ansi CFLAGS += -D_DEFAULT_SOURCE
ifneq ($(OS), FreeBSD)
ifneq ($(OS), Darwin)
#CFLAGS += -D_POSIX_C_SOURCE=200112L
CFLAGS += -D_XOPEN_SOURCE=600
endif
endif
#CFLAGS += -ansi
# -DNO_GETADDRINFO # -DNO_GETADDRINFO
INSTALL = install INSTALL = install
SH = /bin/sh SH = /bin/sh
@ -46,26 +54,32 @@ JAVA = java
#JNAERATOR = jnaerator-0.9.8-shaded.jar #JNAERATOR = jnaerator-0.9.8-shaded.jar
#JNAERATORARGS = -library miniupnpc #JNAERATORARGS = -library miniupnpc
#JNAERATOR = jnaerator-0.10-shaded.jar #JNAERATOR = jnaerator-0.10-shaded.jar
JNAERATOR = jnaerator-0.11-shaded.jar #JNAERATOR = jnaerator-0.11-shaded.jar
# https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12/jnaerator-0.12-shaded.jar
JNAERATOR = jnaerator-0.12-shaded.jar
JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc JNAERATORARGS = -mode StandaloneJar -runtime JNAerator -library miniupnpc
JNAERATORBASEURL = http://jnaerator.googlecode.com/files/ #JNAERATORBASEURL = http://jnaerator.googlecode.com/files/
JNAERATORBASEURL = https://repo1.maven.org/maven2/com/nativelibs4java/jnaerator/0.12
ifeq (SunOS, $(OS)) ifeq (SunOS, $(OS))
LDFLAGS=-lsocket -lnsl -lresolv LDFLAGS=-lsocket -lnsl -lresolv
endif endif
# APIVERSION is used to build SONAME # APIVERSION is used to build SONAME
APIVERSION = 10 APIVERSION = 15
SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \ SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \
upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \ upnpc.c upnpcommands.c upnpreplyparse.c testminixml.c \
minixmlvalid.c testupnpreplyparse.c minissdpc.c \ minixmlvalid.c testupnpreplyparse.c minissdpc.c \
upnperrors.c testigddescparse.c testminiwget.c \ upnperrors.c testigddescparse.c testminiwget.c \
connecthostport.c portlistingparse.c receivedata.c connecthostport.c portlistingparse.c receivedata.c \
upnpdev.c testportlistingparse.c miniupnpcmodule.c \
minihttptestserver.c \
listdevices.c
LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \ LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
connecthostport.o portlistingparse.o receivedata.o connecthostport.o portlistingparse.o receivedata.o upnpdev.o
ifneq ($(OS), AmigaOS) ifneq ($(OS), AmigaOS)
CFLAGS := -fPIC $(CFLAGS) CFLAGS := -fPIC $(CFLAGS)
@ -78,7 +92,8 @@ OBJS = $(patsubst %.c,%.o,$(SRCS))
HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \ HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \
upnpreplyparse.h upnperrors.h miniupnpctypes.h \ upnpreplyparse.h upnperrors.h miniupnpctypes.h \
portlistingparse.h \ portlistingparse.h \
declspec.h upnpdev.h \
miniupnpc_declspec.h
# library names # library names
LIBRARY = libminiupnpc.a LIBRARY = libminiupnpc.a
@ -96,9 +111,9 @@ else
endif endif
endif endif
EXECUTABLES = upnpc-static EXECUTABLES = upnpc-static listdevices
EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \ EXECUTABLES_ADDTESTS = testminixml minixmlvalid testupnpreplyparse \
testigddescparse testminiwget testigddescparse testminiwget testportlistingparse
TESTMINIXMLOBJS = minixml.o igd_desc_parse.o testminixml.o TESTMINIXMLOBJS = minixml.o igd_desc_parse.o testminixml.o
@ -106,6 +121,8 @@ TESTMINIWGETOBJS = miniwget.o testminiwget.o connecthostport.o receivedata.o
TESTUPNPREPLYPARSE = testupnpreplyparse.o minixml.o upnpreplyparse.o TESTUPNPREPLYPARSE = testupnpreplyparse.o minixml.o upnpreplyparse.o
TESTPORTLISTINGPARSE = testportlistingparse.o minixml.o portlistingparse.o
TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \ TESTIGDDESCPARSE = testigddescparse.o igd_desc_parse.o minixml.o \
miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \ miniupnpc.o miniwget.o upnpcommands.o upnpreplyparse.o \
minisoap.o connecthostport.o receivedata.o \ minisoap.o connecthostport.o receivedata.o \
@ -139,7 +156,8 @@ all: $(LIBRARY) $(EXECUTABLES)
test: check test: check
check: validateminixml validateminiwget validateupnpreplyparse check: validateminixml validateminiwget validateupnpreplyparse \
validateportlistingparse validateigddescparse
everything: all $(EXECUTABLES_ADDTESTS) everything: all $(EXECUTABLES_ADDTESTS)
@ -172,13 +190,25 @@ validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh
./testupnpreplyparse.sh ./testupnpreplyparse.sh
touch $@ touch $@
validateportlistingparse: testportlistingparse
@echo "portlistingparse validation test"
./testportlistingparse
touch $@
validateigddescparse: testigddescparse
@echo "igd desc parse validation test"
./testigddescparse testdesc/new_LiveBox_desc.xml testdesc/new_LiveBox_desc.values
./testigddescparse testdesc/linksys_WAG200G_desc.xml testdesc/linksys_WAG200G_desc.values
touch $@
clean: clean:
$(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h $(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h
$(RM) $(EXECUTABLES_ADDTESTS) $(RM) $(EXECUTABLES_ADDTESTS)
# clean python stuff # clean python stuff
$(RM) pythonmodule pythonmodule3 $(RM) pythonmodule pythonmodule3
$(RM) validateminixml validateminiwget validateupnpreplyparse $(RM) validateminixml validateminiwget validateupnpreplyparse
$(RM) minihttptestserver minihttptestserver.o $(RM) validateigddescparse
$(RM) minihttptestserver
$(RM) -r build/ dist/ $(RM) -r build/ dist/
#python setup.py clean #python setup.py clean
# clean jnaerator stuff # clean jnaerator stuff
@ -209,12 +239,19 @@ endif
$(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
ifneq ($(OS), AmigaOS) ifneq ($(OS), AmigaOS)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3 $(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3
$(INSTALL) man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 $(INSTALL) -m 644 man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
ifeq ($(OS), Linux) ifeq ($(OS), Linux)
gzip $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 gzip -f $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3
endif endif
endif endif
install-static: updateversion $(FILESTOINSTALL)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC)
$(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB)
$(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB)
$(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN)
$(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip
cleaninstall: cleaninstall:
$(RM) -r $(DESTDIR)$(INSTALLDIRINC) $(RM) -r $(DESTDIR)$(INSTALLDIRINC)
@ -225,7 +262,11 @@ depend:
makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null
$(LIBRARY): $(LIBOBJS) $(LIBRARY): $(LIBOBJS)
ifeq ($(OS), Darwin)
$(LIBTOOL) -static -o $@ $?
else
$(AR) crs $@ $? $(AR) crs $@ $?
endif
$(SHAREDLIBRARY): $(LIBOBJS) $(SHAREDLIBRARY): $(LIBOBJS)
ifeq ($(OS), Darwin) ifeq ($(OS), Darwin)
@ -236,10 +277,12 @@ else
endif endif
upnpc-static: upnpc.o $(LIBRARY) upnpc-static: upnpc.o $(LIBRARY)
$(CC) $(LDFLAGS) -o $@ $^ $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
upnpc-shared: upnpc.o $(SHAREDLIBRARY) upnpc-shared: upnpc.o $(SHAREDLIBRARY)
$(CC) $(LDFLAGS) -o $@ $^ $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS)
listdevices: listdevices.o $(LIBRARY)
testminixml: $(TESTMINIXMLOBJS) testminixml: $(TESTMINIXMLOBJS)
@ -251,6 +294,8 @@ testupnpreplyparse: $(TESTUPNPREPLYPARSE)
testigddescparse: $(TESTIGDDESCPARSE) testigddescparse: $(TESTIGDDESCPARSE)
testportlistingparse: $(TESTPORTLISTINGPARSE)
miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION
$(SH) updateminiupnpcstrings.sh $(SH) updateminiupnpcstrings.sh
@ -262,7 +307,7 @@ jnaerator-%.jar:
jar: $(SHAREDLIBRARY) $(JNAERATOR) jar: $(SHAREDLIBRARY) $(JNAERATOR)
$(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \ $(JAVA) -jar $(JNAERATOR) $(JNAERATORARGS) \
miniupnpc.h declspec.h upnpcommands.h upnpreplyparse.h \ miniupnpc.h miniupnpc_declspec.h upnpcommands.h upnpreplyparse.h \
igd_desc_parse.h miniwget.h upnperrors.h $(SHAREDLIBRARY) \ igd_desc_parse.h miniwget.h upnperrors.h $(SHAREDLIBRARY) \
-package fr.free.miniupnp -o . -jar java/miniupnpc_$(JARSUFFIX).jar -v -package fr.free.miniupnp -o . -jar java/miniupnpc_$(JARSUFFIX).jar -v
@ -295,27 +340,40 @@ minihttptestserver: minihttptestserver.o
# DO NOT DELETE THIS LINE -- make depend depends on it. # DO NOT DELETE THIS LINE -- make depend depends on it.
igd_desc_parse.o: igd_desc_parse.h igd_desc_parse.o: igd_desc_parse.h
miniupnpc.o: miniupnpc.h declspec.h igd_desc_parse.h minissdpc.h miniwget.h miniupnpc.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h
miniupnpc.o: minisoap.h minixml.h upnpcommands.h upnpreplyparse.h miniupnpc.o: minissdpc.h miniwget.h minisoap.h minixml.h upnpcommands.h
miniupnpc.o: portlistingparse.h miniupnpctypes.h connecthostport.h miniupnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
miniupnpc.o: receivedata.h miniupnpc.o: connecthostport.h
minixml.o: minixml.h minixml.o: minixml.h
minisoap.o: minisoap.h miniupnpcstrings.h minisoap.o: minisoap.h miniupnpcstrings.h
miniwget.o: miniupnpcstrings.h miniwget.h declspec.h connecthostport.h miniwget.o: miniupnpcstrings.h miniwget.h miniupnpc_declspec.h
miniwget.o: receivedata.h miniwget.o: connecthostport.h receivedata.h
upnpc.o: miniwget.h declspec.h miniupnpc.h igd_desc_parse.h upnpcommands.h upnpc.o: miniwget.h miniupnpc_declspec.h miniupnpc.h igd_desc_parse.h
upnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h upnperrors.h upnpc.o: upnpdev.h upnpcommands.h upnpreplyparse.h portlistingparse.h
upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h declspec.h upnpc.o: miniupnpctypes.h upnperrors.h miniupnpcstrings.h
upnpcommands.o: miniupnpctypes.h miniupnpc.h igd_desc_parse.h upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h
upnpcommands.o: miniupnpc_declspec.h miniupnpctypes.h miniupnpc.h
upnpcommands.o: igd_desc_parse.h upnpdev.h
upnpreplyparse.o: upnpreplyparse.h minixml.h upnpreplyparse.o: upnpreplyparse.h minixml.h
testminixml.o: minixml.h igd_desc_parse.h testminixml.o: minixml.h igd_desc_parse.h
minixmlvalid.o: minixml.h minixmlvalid.o: minixml.h
testupnpreplyparse.o: upnpreplyparse.h testupnpreplyparse.o: upnpreplyparse.h
minissdpc.o: minissdpc.h miniupnpc.h declspec.h igd_desc_parse.h codelength.h minissdpc.o: minissdpc.h miniupnpc_declspec.h upnpdev.h miniupnpc.h
upnperrors.o: upnperrors.h declspec.h upnpcommands.h upnpreplyparse.h minissdpc.o: igd_desc_parse.h receivedata.h codelength.h
upnperrors.o: portlistingparse.h miniupnpctypes.h miniupnpc.h upnperrors.o: upnperrors.h miniupnpc_declspec.h upnpcommands.h
upnperrors.o: igd_desc_parse.h upnperrors.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h
testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h declspec.h upnperrors.o: miniupnpc.h igd_desc_parse.h upnpdev.h
testminiwget.o: miniwget.h declspec.h testigddescparse.o: igd_desc_parse.h minixml.h miniupnpc.h
testigddescparse.o: miniupnpc_declspec.h upnpdev.h
testminiwget.o: miniwget.h miniupnpc_declspec.h
connecthostport.o: connecthostport.h connecthostport.o: connecthostport.h
portlistingparse.o: portlistingparse.h miniupnpc_declspec.h miniupnpctypes.h
portlistingparse.o: minixml.h
receivedata.o: receivedata.h receivedata.o: receivedata.h
upnpdev.o: upnpdev.h miniupnpc_declspec.h
testportlistingparse.o: portlistingparse.h miniupnpc_declspec.h
testportlistingparse.o: miniupnpctypes.h
miniupnpcmodule.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h
miniupnpcmodule.o: upnpdev.h upnpcommands.h upnpreplyparse.h
miniupnpcmodule.o: portlistingparse.h miniupnpctypes.h upnperrors.h
listdevices.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h

View file

@ -1,10 +1,10 @@
# $Id: Makefile.mingw,v 1.18 2014/01/17 09:04:01 nanard Exp $ # $Id: Makefile.mingw,v 1.21 2015/09/18 12:45:16 nanard Exp $
# Miniupnp project. # Miniupnp project.
# http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ # http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
# (c) 2005-2014 Thomas Bernard # (c) 2005-2015 Thomas Bernard
# This Makefile is made for MinGW # This Makefile is made for MinGW
# #
CC = gcc CC ?= gcc
#CFLAGS = -Wall -g -DDEBUG -D_WIN32_WINNT=0X501 #CFLAGS = -Wall -g -DDEBUG -D_WIN32_WINNT=0X501
CFLAGS = -Wall -Os -DNDEBUG -D_WIN32_WINNT=0X501 CFLAGS = -Wall -Os -DNDEBUG -D_WIN32_WINNT=0X501
LDLIBS = -lws2_32 -liphlpapi LDLIBS = -lws2_32 -liphlpapi
@ -12,8 +12,10 @@ LDLIBS = -lws2_32 -liphlpapi
# -liphlpapi is needed for GetBestRoute() and GetIpAddrTable() # -liphlpapi is needed for GetBestRoute() and GetIpAddrTable()
PYTHON=\utils\python25\python PYTHON=\utils\python25\python
OBJS=miniwget.o minixml.o igd_desc_parse.o minisoap.o \ OBJS=miniwget.o minixml.o igd_desc_parse.o minisoap.o \
minissdpc.o \
miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \
connecthostport.o portlistingparse.o receivedata.o connecthostport.o portlistingparse.o receivedata.o \
upnpdev.o
OBJSDLL=$(addprefix dll/, $(OBJS)) OBJSDLL=$(addprefix dll/, $(OBJS))
all: init upnpc-static upnpc-shared testminixml libminiupnpc.a miniupnpc.dll all: init upnpc-static upnpc-shared testminixml libminiupnpc.a miniupnpc.dll
@ -44,16 +46,16 @@ miniupnpc.dll: libminiupnpc.a $(OBJSDLL)
$(OBJSDLL) $(LDLIBS) $(OBJSDLL) $(LDLIBS)
miniupnpc.lib: miniupnpc.dll miniupnpc.lib: miniupnpc.dll
echo $@ generated with $< # echo $@ generated with $<
dll/upnpc.o: upnpc.o dll/upnpc.o: upnpc.o
echo $@ generated with $< # echo $@ generated with $<
.c.o: .c.o:
$(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $< $(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $<
$(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $< $(CC) $(CFLAGS) -DMINIUPNP_EXPORTS -c -o dll/$@ $<
upnpc.o: upnpc.o: upnpc.c
$(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $< $(CC) $(CFLAGS) -DMINIUPNP_STATICLIB -c -o $@ $<
$(CC) $(CFLAGS) -c -o dll/$@ $< $(CC) $(CFLAGS) -c -o dll/$@ $<
@ -71,9 +73,10 @@ wingenminiupnpcstrings.o: wingenminiupnpcstrings.c
miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings miniupnpcstrings.h: miniupnpcstrings.h.in wingenminiupnpcstrings
wingenminiupnpcstrings $< $@ wingenminiupnpcstrings $< $@
minixml.o: minixml.c minixml.h miniupnpcstrings.h minixml.o: minixml.c minixml.h
upnpc.o: upnpc.c miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h upnpreplyparse.h upnpcommands.h upnperrors.h upnpc.o: miniwget.h minisoap.h miniupnpc.h igd_desc_parse.h
upnpc.o: upnpreplyparse.h upnpcommands.h upnperrors.h miniupnpcstrings.h
miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h miniwget.o: miniwget.c miniwget.h miniupnpcstrings.h connecthostport.h
@ -89,3 +92,7 @@ upnpreplyparse.o: upnpreplyparse.c upnpreplyparse.h minixml.h
upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h portlistingparse.h upnpcommands.o: upnpcommands.c upnpcommands.h upnpreplyparse.h miniupnpc.h portlistingparse.h
minissdpc.o: minissdpc.c minissdpc.h receivedata.h
upnpdev.o: upnpdev.c upnpdev.h

View file

@ -3,16 +3,11 @@ Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
github: https://github.com/miniupnp/miniupnp github: https://github.com/miniupnp/miniupnp
freecode: http://freecode.com/projects/miniupnp freecode: http://freecode.com/projects/miniupnp
Author: Thomas Bernard Author: Thomas Bernard
Copyright (c) 2005-2012 Thomas Bernard Copyright (c) 2005-2014 Thomas Bernard
This software is subject to the conditions detailed in the This software is subject to the conditions detailed in the
LICENSE file provided within this distribution. LICENSE file provided within this distribution.
For the comfort of Win32 users, bsdqueue.h is included in the distribution.
Its licence is included in the header of the file.
bsdqueue.h is a copy of the sys/queue.h of an OpenBSD system.
* miniUPnP Client - miniUPnPc * * miniUPnP Client - miniUPnPc *
To compile, simply run 'gmake' (could be 'make' on your system). To compile, simply run 'gmake' (could be 'make' on your system).

View file

@ -1,7 +1,47 @@
$Id: apiversions.txt,v 1.3 2014/01/31 13:14:32 nanard Exp $ $Id: apiversions.txt,v 1.7 2015/07/23 20:40:08 nanard Exp $
Differences in API between miniUPnPc versions Differences in API between miniUPnPc versions
API version 15
changed "sameport" argument of upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice()
to "localport". When 0 or 1, behaviour is not changed, but it can take
any other value between 2 and 65535
Existing programs should be compatible
updated macro :
#define MINIUPNPC_API_VERSION 15
API version 14
miniupnpc.h
add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice()
upnpDiscoverDevices()
getDevicesFromMiniSSDPD() :
connectToMiniSSDPD() / disconnectFromMiniSSDPD()
requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD()
updated macro :
#define MINIUPNPC_API_VERSION 14
API version 13
miniupnpc.h:
add searchalltype param to upnpDiscoverDevices() function
updated macro :
#define MINIUPNPC_API_VERSION 13
API version 12
miniupnpc.h :
add upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices()
functions
updated macros :
#define MINIUPNPC_API_VERSION 12
API version 11
upnpreplyparse.h / portlistingparse.h :
removed usage of sys/queue.h / bsdqueue.h
miniupnpc.h:
updated macros :
#define MINIUPNPC_API_VERSION 11
====================== miniUPnPc version 1.9 ====================== ====================== miniUPnPc version 1.9 ======================
API version 10 API version 10

View file

@ -1,531 +0,0 @@
/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#ifdef QUEUE_MACRO_DEBUG
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#ifdef SLIST_ENTRY
#undef SLIST_ENTRY
#endif
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != SLIST_END(head); \
(varp) = &SLIST_NEXT((var), field))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_NEXT(head, elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
\
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
_Q_INVALIDATE((elm)->field.sle_next); \
} \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* tail queue access methods
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue access methods
*/
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_END(head) ((void *)(head))
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_EMPTY(head) \
(CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
#define CIRCLEQ_FOREACH(var, head, field) \
for((var) = CIRCLEQ_FIRST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_NEXT(var, field))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for((var) = CIRCLEQ_LAST(head); \
(var) != CIRCLEQ_END(head); \
(var) = CIRCLEQ_PREV(var, field))
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = CIRCLEQ_END(head); \
(head)->cqh_last = CIRCLEQ_END(head); \
} while (0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = CIRCLEQ_END(head); \
if ((head)->cqh_last == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = CIRCLEQ_END(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
CIRCLEQ_END(head)) \
(head).cqh_last = (elm2); \
else \
(elm2)->field.cqe_next->field.cqe_prev = (elm2); \
if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
CIRCLEQ_END(head)) \
(head).cqh_first = (elm2); \
else \
(elm2)->field.cqe_prev->field.cqe_next = (elm2); \
_Q_INVALIDATE((elm)->field.cqe_prev); \
_Q_INVALIDATE((elm)->field.cqe_next); \
} while (0)
#endif /* !_SYS_QUEUE_H_ */

View file

@ -1,7 +1,7 @@
/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */ /* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas BERNARD * Author : Thomas BERNARD
* copyright (c) 2005-2011 Thomas Bernard * copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the * This software is subjet to the conditions detailed in the
* provided LICENCE file. */ * provided LICENCE file. */
#ifndef CODELENGTH_H_INCLUDED #ifndef CODELENGTH_H_INCLUDED
@ -10,10 +10,30 @@
/* Encode length by using 7bit per Byte : /* Encode length by using 7bit per Byte :
* Most significant bit of each byte specifies that the * Most significant bit of each byte specifies that the
* following byte is part of the code */ * following byte is part of the code */
/* n : unsigned
* p : unsigned char *
*/
#define DECODELENGTH(n, p) n = 0; \ #define DECODELENGTH(n, p) n = 0; \
do { n = (n << 7) | (*p & 0x7f); } \ do { n = (n << 7) | (*p & 0x7f); } \
while((*(p++)&0x80) && (n<(1<<25))); while((*(p++)&0x80) && (n<(1<<25)));
/* n : unsigned
* READ : function/macro to read one byte (unsigned char)
*/
#define DECODELENGTH_READ(n, READ) \
n = 0; \
do { \
unsigned char c; \
READ(c); \
n = (n << 7) | (c & 0x07f); \
if(!(c&0x80)) break; \
} while(n<(1<<25));
/* n : unsigned
* p : unsigned char *
* p_limit : unsigned char *
*/
#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ #define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \
n = 0; \ n = 0; \
do { \ do { \
@ -21,11 +41,14 @@
n = (n << 7) | (*(p) & 0x7f); \ n = (n << 7) | (*(p) & 0x7f); \
} while((*((p)++)&0x80) && (n<(1<<25))); } while((*((p)++)&0x80) && (n<(1<<25)));
/* n : unsigned
* p : unsigned char *
*/
#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ #define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \
if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ if(n>=2097152) *(p++) = (n >> 21) | 0x80; \
if(n>=16384) *(p++) = (n >> 14) | 0x80; \ if(n>=16384) *(p++) = (n >> 14) | 0x80; \
if(n>=128) *(p++) = (n >> 7) | 0x80; \ if(n>=128) *(p++) = (n >> 7) | 0x80; \
*(p++) = n & 0x7f; *(p++) = n & 0x7f;
#endif #endif /* CODELENGTH_H_INCLUDED */

View file

@ -1,7 +1,7 @@
/* $Id: connecthostport.c,v 1.12 2014/02/05 17:26:46 nanard Exp $ */ /* $Id: connecthostport.c,v 1.15 2015/10/09 16:26:19 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2010-2014 Thomas Bernard * Copyright (c) 2010-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
@ -23,6 +23,10 @@
#define socklen_t int #define socklen_t int
#else /* #ifdef _WIN32 */ #else /* #ifdef _WIN32 */
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
#include <sys/time.h>
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
#include <sys/param.h> #include <sys/param.h>
#include <sys/select.h> #include <sys/select.h>
#include <errno.h> #include <errno.h>
@ -33,8 +37,8 @@
* during the connect() call */ * during the connect() call */
#define MINIUPNPC_IGNORE_EINTR #define MINIUPNPC_IGNORE_EINTR
#ifndef USE_GETHOSTBYNAME #ifndef USE_GETHOSTBYNAME
#include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/select.h>
#endif /* #ifndef USE_GETHOSTBYNAME */ #endif /* #ifndef USE_GETHOSTBYNAME */
#endif /* #else _WIN32 */ #endif /* #else _WIN32 */
@ -112,7 +116,7 @@ int connecthostport(const char * host, unsigned short port,
/* EINTR The system call was interrupted by a signal that was caught /* EINTR The system call was interrupted by a signal that was caught
* EINPROGRESS The socket is nonblocking and the connection cannot * EINPROGRESS The socket is nonblocking and the connection cannot
* be completed immediately. */ * be completed immediately. */
while(n < 0 && (errno == EINTR || errno = EINPROGRESS)) while(n < 0 && (errno == EINTR || errno == EINPROGRESS))
{ {
socklen_t len; socklen_t len;
fd_set wset; fd_set wset;

View file

@ -1,8 +1,8 @@
/* $Id: igd_desc_parse.c,v 1.15 2014/07/01 13:01:17 nanard Exp $ */ /* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* http://miniupnp.free.fr/ * http://miniupnp.free.fr/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
@ -15,11 +15,9 @@
void IGDstartelt(void * d, const char * name, int l) void IGDstartelt(void * d, const char * name, int l)
{ {
struct IGDdatas * datas = (struct IGDdatas *)d; struct IGDdatas * datas = (struct IGDdatas *)d;
if (l >= MINIUPNPC_URL_MAXSIZE) { if(l >= MINIUPNPC_URL_MAXSIZE)
printf("Attempt to exploit miniupnpc buffer overflow\n"); l = MINIUPNPC_URL_MAXSIZE-1;
l = MINIUPNPC_URL_MAXSIZE - 1; memcpy(datas->cureltname, name, l);
}
memcpy( datas->cureltname, name, l);
datas->cureltname[l] = '\0'; datas->cureltname[l] = '\0';
datas->level++; datas->level++;
if( (l==7) && !memcmp(name, "service", l) ) { if( (l==7) && !memcmp(name, "service", l) ) {
@ -92,6 +90,7 @@ void IGDdata(void * d, const char * data, int l)
} }
} }
#ifdef DEBUG
void printIGD(struct IGDdatas * d) void printIGD(struct IGDdatas * d)
{ {
printf("urlbase = '%s'\n", d->urlbase); printf("urlbase = '%s'\n", d->urlbase);
@ -120,5 +119,5 @@ void printIGD(struct IGDdatas * d)
printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl);
printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl);
} }
#endif /* DEBUG */

View file

@ -1,8 +1,8 @@
/* $Id: igd_desc_parse.h,v 1.10 2011/04/11 09:19:24 nanard Exp $ */ /* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* http://miniupnp.free.fr/ * http://miniupnp.free.fr/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2010 Thomas Bernard * Copyright (c) 2005-2014 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
@ -42,7 +42,8 @@ struct IGDdatas {
void IGDstartelt(void *, const char *, int); void IGDstartelt(void *, const char *, int);
void IGDendelt(void *, const char *, int); void IGDendelt(void *, const char *, int);
void IGDdata(void *, const char *, int); void IGDdata(void *, const char *, int);
#ifdef DEBUG
void printIGD(struct IGDdatas *); void printIGD(struct IGDdatas *);
#endif /* DEBUG */
#endif #endif /* IGD_DESC_PARSE_H_INCLUDED */

View file

@ -29,7 +29,7 @@ public class JavaBridgeTest {
return; return;
} }
devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, IntBuffer.allocate(1)); devlist = miniupnpc.upnpDiscover(UPNP_DELAY, (String) null, (String) null, 0, 0, (byte)2, IntBuffer.allocate(1));
if (devlist != null) { if (devlist != null) {
System.out.println("List of UPNP devices found on the network :"); System.out.println("List of UPNP devices found on the network :");
for (UPNPDev device = devlist; device != null; device = device.pNext) { for (UPNPDev device = devlist; device != null; device = device.pNext) {

110
external/miniupnpc/listdevices.c vendored Normal file
View file

@ -0,0 +1,110 @@
/* $Id: listdevices.c,v 1.6 2015/07/23 20:40:08 nanard Exp $ */
/* Project : miniupnp
* Author : Thomas Bernard
* Copyright (c) 2013-2015 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
#include <winsock2.h>
#endif /* _WIN32 */
#include "miniupnpc.h"
int main(int argc, char * * argv)
{
const char * searched_device = NULL;
const char * * searched_devices = NULL;
const char * multicastif = 0;
const char * minissdpdpath = 0;
int ipv6 = 0;
unsigned char ttl = 2;
int error = 0;
struct UPNPDev * devlist = 0;
struct UPNPDev * dev;
int i;
#ifdef _WIN32
WSADATA wsaData;
int nResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if(nResult != NO_ERROR)
{
fprintf(stderr, "WSAStartup() failed.\n");
return -1;
}
#endif
for(i = 1; i < argc; i++) {
if(strcmp(argv[i], "-6") == 0)
ipv6 = 1;
else if(strcmp(argv[i], "-d") == 0) {
if(++i >= argc) {
fprintf(stderr, "%s option needs one argument\n", "-d");
return 1;
}
searched_device = argv[i];
} else if(strcmp(argv[i], "-t") == 0) {
if(++i >= argc) {
fprintf(stderr, "%s option needs one argument\n", "-t");
return 1;
}
ttl = (unsigned char)atoi(argv[i]);
} else if(strcmp(argv[i], "-l") == 0) {
if(++i >= argc) {
fprintf(stderr, "-l option needs at least one argument\n");
return 1;
}
searched_devices = (const char * *)(argv + i);
break;
} else if(strcmp(argv[i], "-m") == 0) {
if(++i >= argc) {
fprintf(stderr, "-m option needs one argument\n");
return 1;
}
multicastif = argv[i];
} else {
printf("usage : %s [options] [-l <device1> <device2> ...]\n", argv[0]);
printf("options :\n");
printf(" -6 : use IPv6\n");
printf(" -m address/ifname : network interface to use for multicast\n");
printf(" -d <device string> : search only for this type of device\n");
printf(" -l <device1> <device2> ... : search only for theses types of device\n");
printf(" -t ttl : set multicast TTL. Default value is 2.\n");
printf(" -h : this help\n");
return 1;
}
}
if(searched_device) {
printf("searching UPnP device type %s\n", searched_device);
devlist = upnpDiscoverDevice(searched_device,
2000, multicastif, minissdpdpath,
0/*localport*/, ipv6, ttl, &error);
} else if(searched_devices) {
printf("searching UPnP device types :\n");
for(i = 0; searched_devices[i]; i++)
printf("\t%s\n", searched_devices[i]);
devlist = upnpDiscoverDevices(searched_devices,
2000, multicastif, minissdpdpath,
0/*localport*/, ipv6, ttl, &error, 1);
} else {
printf("searching all UPnP devices\n");
devlist = upnpDiscoverAll(2000, multicastif, minissdpdpath,
0/*localport*/, ipv6, ttl, &error);
}
if(devlist) {
for(dev = devlist, i = 1; dev != NULL; dev = dev->pNext, i++) {
printf("%3d: %-48s\n", i, dev->st);
printf(" %s\n", dev->descURL);
printf(" %s\n", dev->usn);
}
freeUPNPDevlist(devlist);
} else {
printf("no device found.\n");
}
return 0;
}

View file

@ -25,13 +25,16 @@ through the miniupnpc API. The name of the C functions are matching
the UPnP methods names. ie: GetGenericPortMappingEntry is the UPnP methods names. ie: GetGenericPortMappingEntry is
UPNP_GetGenericPortMappingEntry. UPNP_GetGenericPortMappingEntry.
.SH "API FUNCTIONS" .SH "API FUNCTIONS"
.IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int sameport, int ipv6, int * error);" .IP "struct UPNPDev * upnpDiscover(int delay, const char * multicastif, const char * minissdpdsock, int localport, int ipv6, int * error);"
execute the discovery process. execute the discovery process.
delay (in millisecond) is the maximum time for waiting any device response. delay (in millisecond) is the maximum time for waiting any device response.
If available, device list will be obtained from MiniSSDPd. If available, device list will be obtained from MiniSSDPd.
Default path for minissdpd socket will be used if minissdpdsock argument is NULL. Default path for minissdpd socket will be used if minissdpdsock argument is NULL.
If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets. If multicastif is not NULL, it will be used instead of the default multicast interface for sending SSDP discover packets.
If sameport is not null, SSDP packets will be sent from the source port 1900 (same as destination port) otherwise system assign a source port. If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
from the source port 1900 (same as destination port), if set to
UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
be attempted as the source port.
If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process. If ipv6 is not 0, IPv6 is used instead of IPv4 for the discovery process.
.IP "void freeUPNPDevlist(struct UPNPDev * devlist);" .IP "void freeUPNPDevlist(struct UPNPDev * devlist);"
free the list returned by upnpDiscover(). free the list returned by upnpDiscover().

View file

@ -1,7 +1,7 @@
/* $Id: minihttptestserver.c,v 1.16 2014/04/01 15:08:28 nanard Exp $ */ /* $Id: minihttptestserver.c,v 1.19 2015/11/17 09:07:17 nanard Exp $ */
/* Project : miniUPnP /* Project : miniUPnP
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2011-2014 Thomas Bernard * Copyright (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
@ -18,6 +18,10 @@
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x7f000001
#endif
#define CRAP_LENGTH (2048) #define CRAP_LENGTH (2048)
volatile sig_atomic_t quit = 0; volatile sig_atomic_t quit = 0;
@ -104,6 +108,8 @@ char * build_chunked_response(int content_length, int * response_len)
/* allocate to have some margin */ /* allocate to have some margin */
buffer_length = 256 + content_length + (content_length >> 4); buffer_length = 256 + content_length + (content_length >> 4);
response_buffer = malloc(buffer_length); response_buffer = malloc(buffer_length);
if(response_buffer == NULL)
return NULL;
*response_len = snprintf(response_buffer, buffer_length, *response_len = snprintf(response_buffer, buffer_length,
"HTTP/1.1 200 OK\r\n" "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n" "Content-Type: text/plain\r\n"
@ -112,6 +118,10 @@ char * build_chunked_response(int content_length, int * response_len)
/* build the content */ /* build the content */
content_buffer = malloc(content_length); content_buffer = malloc(content_length);
if(content_buffer == NULL) {
free(response_buffer);
return NULL;
}
build_content(content_buffer, content_length); build_content(content_buffer, content_length);
/* chunk it */ /* chunk it */
@ -414,7 +424,14 @@ void handle_http_connection(int c)
"Content-Length: %d\r\n" "Content-Length: %d\r\n"
"\r\n", content_length); "\r\n", content_length);
response_len = content_length+n+CRAP_LENGTH; response_len = content_length+n+CRAP_LENGTH;
response_buffer = realloc(response_buffer, response_len); p = realloc(response_buffer, response_len);
if(p == NULL) {
/* error 500 */
free(response_buffer);
response_buffer = NULL;
break;
}
response_buffer = p;
build_content(response_buffer + n, content_length); build_content(response_buffer + n, content_length);
build_crap(response_buffer + n + content_length, CRAP_LENGTH); build_crap(response_buffer + n + content_length, CRAP_LENGTH);
break; break;
@ -445,7 +462,14 @@ void handle_http_connection(int c)
"Content-Type: text/plain\r\n" "Content-Type: text/plain\r\n"
"\r\n"); "\r\n");
response_len = content_length+n; response_len = content_length+n;
response_buffer = realloc(response_buffer, response_len); p = realloc(response_buffer, response_len);
if(p == NULL) {
/* Error 500 */
free(response_buffer);
response_buffer = NULL;
break;
}
response_buffer = p;
build_content(response_buffer + n, response_len - n); build_content(response_buffer + n, response_len - n);
} }
@ -564,12 +588,16 @@ int main(int argc, char * * argv) {
if(f) { if(f) {
char * buffer; char * buffer;
buffer = malloc(16*1024); buffer = malloc(16*1024);
build_content(buffer, 16*1024); if(buffer == NULL) {
i = fwrite(buffer, 1, 16*1024, f); fprintf(stderr, "memory allocation error\n");
if(i != 16*1024) { } else {
fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024); build_content(buffer, 16*1024);
i = fwrite(buffer, 1, 16*1024, f);
if(i != 16*1024) {
fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024);
}
free(buffer);
} }
free(buffer);
fclose(f); fclose(f);
} else { } else {
fprintf(stderr, "error opening file %s for writing\n", expected_file_name); fprintf(stderr, "error opening file %s for writing\n", expected_file_name);

View file

@ -1,7 +1,7 @@
/* $Id: minisoap.c,v 1.22 2012/01/21 13:30:31 nanard Exp $ */ /* $Id: minisoap.c,v 1.23 2014/11/04 22:31:55 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* *
@ -43,10 +43,10 @@ httpWrite(int fd, const char * body, int bodysize,
/* Note : my old linksys router only took into account /* Note : my old linksys router only took into account
* soap request that are sent into only one packet */ * soap request that are sent into only one packet */
char * p; char * p;
/* TODO: AVOID MALLOC */ /* TODO: AVOID MALLOC, we could use writev() for that */
p = malloc(headerssize+bodysize); p = malloc(headerssize+bodysize);
if(!p) if(!p)
return 0; return -1;
memcpy(p, headers, headerssize); memcpy(p, headers, headerssize);
memcpy(p+headerssize, body, bodysize); memcpy(p+headerssize, body, bodysize);
/*n = write(fd, p, headerssize+bodysize);*/ /*n = write(fd, p, headerssize+bodysize);*/
@ -96,7 +96,7 @@ int soapPostSubmit(int fd,
headerssize = snprintf(headerbuf, sizeof(headerbuf), headerssize = snprintf(headerbuf, sizeof(headerbuf),
"POST %s HTTP/%s\r\n" "POST %s HTTP/%s\r\n"
"Host: %s%s\r\n" "Host: %s%s\r\n"
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"Content-Length: %d\r\n" "Content-Length: %d\r\n"
"Content-Type: text/xml\r\n" "Content-Type: text/xml\r\n"
"SOAPAction: \"%s\"\r\n" "SOAPAction: \"%s\"\r\n"
@ -105,6 +105,8 @@ int soapPostSubmit(int fd,
"Pragma: no-cache\r\n" "Pragma: no-cache\r\n"
"\r\n", "\r\n",
url, httpversion, host, portstr, bodysize, action); url, httpversion, host, portstr, bodysize, action);
if ((unsigned int)headerssize >= sizeof(headerbuf))
return -1;
#ifdef DEBUG #ifdef DEBUG
/*printf("SOAP request : headersize=%d bodysize=%d\n", /*printf("SOAP request : headersize=%d bodysize=%d\n",
headerssize, bodysize); headerssize, bodysize);

View file

@ -1,67 +1,194 @@
/* $Id: minissdpc.c,v 1.15 2012/01/21 13:30:31 nanard Exp $ */ /* $Id: minissdpc.c,v 1.28 2015/09/18 13:05:39 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Web : http://miniupnp.free.fr/ * Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD * Author : Thomas BERNARD
* copyright (c) 2005-2012 Thomas Bernard * copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the * This software is subjet to the conditions detailed in the
* provided LICENCE file. */ * provided LICENCE file. */
/*#include <syslog.h>*/ /*#include <syslog.h>*/
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) #if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <io.h> #include <io.h>
#include <iphlpapi.h>
#include <winsock.h> #include <winsock.h>
#define snprintf _snprintf
#if !defined(_MSC_VER)
#include <stdint.h> #include <stdint.h>
#endif #else /* !defined(_MSC_VER) */
typedef unsigned short uint16_t;
#endif /* !defined(_MSC_VER) */
#ifndef strncasecmp
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#define strncasecmp _memicmp
#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
#define strncasecmp memicmp
#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */
#endif /* #ifndef strncasecmp */
#endif /* _WIN32 */
#if defined(__amigaos__) || defined(__amigaos4__) #if defined(__amigaos__) || defined(__amigaos4__)
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif /* defined(__amigaos__) || defined(__amigaos4__) */
#if defined(__amigaos__) #if defined(__amigaos__)
#define uint16_t unsigned short #define uint16_t unsigned short
#endif #endif /* defined(__amigaos__) */
/* Hack */ /* Hack */
#define UNIX_PATH_LEN 108 #define UNIX_PATH_LEN 108
struct sockaddr_un { struct sockaddr_un {
uint16_t sun_family; uint16_t sun_family;
char sun_path[UNIX_PATH_LEN]; char sun_path[UNIX_PATH_LEN];
}; };
#else #else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */
#include <strings.h>
#include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/un.h> #include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#define closesocket close
#endif
#ifdef _WIN32
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
#else
#define PRINT_SOCKET_ERROR(x) perror(x)
#endif
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
#define HAS_IP_MREQN
#endif
#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
/* Several versions of glibc don't define this structure,
* define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
struct ip_mreqn
{
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_address; /* local IP address of interface */
int imr_ifindex; /* Interface index */
};
#endif
#if defined(__amigaos__) || defined(__amigaos4__)
/* Amiga OS specific stuff */
#define TIMEVAL struct timeval
#endif #endif
#include "minissdpc.h" #include "minissdpc.h"
#include "miniupnpc.h" #include "miniupnpc.h"
#include "receivedata.h"
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
#include "codelength.h" #include "codelength.h"
struct UPNPDev * struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error)
{ {
struct UPNPDev * tmp;
struct UPNPDev * devlist = NULL; struct UPNPDev * devlist = NULL;
unsigned char buffer[4*1024]; /* is that enough ? */ int s;
ssize_t n; int res;
unsigned char * p;
unsigned char * url; s = connectToMiniSSDPD(socketpath);
unsigned int i; if (s < 0) {
unsigned int urlsize, stsize, usnsize, l; if (error)
*error = s;
return NULL;
}
res = requestDevicesFromMiniSSDPD(s, devtype);
if (res < 0) {
if (error)
*error = res;
} else {
devlist = receiveDevicesFromMiniSSDPD(s, error);
}
disconnectFromMiniSSDPD(s);
return devlist;
}
/* macros used to read from unix socket */
#define READ_BYTE_BUFFER(c) \
if((int)bufferindex >= n) { \
n = read(s, buffer, sizeof(buffer)); \
if(n<=0) break; \
bufferindex = 0; \
} \
c = buffer[bufferindex++];
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif /* MIN */
#define READ_COPY_BUFFER(dst, len) \
for(l = len, p = (unsigned char *)dst; l > 0; ) { \
unsigned int lcopy; \
if((int)bufferindex >= n) { \
n = read(s, buffer, sizeof(buffer)); \
if(n<=0) break; \
bufferindex = 0; \
} \
lcopy = MIN(l, (n - bufferindex)); \
memcpy(p, buffer + bufferindex, lcopy); \
l -= lcopy; \
p += lcopy; \
bufferindex += lcopy; \
}
#define READ_DISCARD_BUFFER(len) \
for(l = len; l > 0; ) { \
unsigned int lcopy; \
if(bufferindex >= n) { \
n = read(s, buffer, sizeof(buffer)); \
if(n<=0) break; \
bufferindex = 0; \
} \
lcopy = MIN(l, (n - bufferindex)); \
l -= lcopy; \
bufferindex += lcopy; \
}
int
connectToMiniSSDPD(const char * socketpath)
{
int s; int s;
struct sockaddr_un addr; struct sockaddr_un addr;
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
struct timeval timeout;
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
s = socket(AF_UNIX, SOCK_STREAM, 0); s = socket(AF_UNIX, SOCK_STREAM, 0);
if(s < 0) if(s < 0)
{ {
/*syslog(LOG_ERR, "socket(unix): %m");*/ /*syslog(LOG_ERR, "socket(unix): %m");*/
perror("socket(unix)"); perror("socket(unix)");
return NULL; return MINISSDPC_SOCKET_ERROR;
} }
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
/* setting a 3 seconds timeout */
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
perror("setsockopt");
}
timeout.tv_sec = 3;
timeout.tv_usec = 0;
if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
{
perror("setsockopt");
}
#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */
if(!socketpath)
socketpath = "/var/run/minissdpd.sock";
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path));
/* TODO : check if we need to handle the EINTR */ /* TODO : check if we need to handle the EINTR */
@ -69,17 +196,45 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
{ {
/*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/
close(s); close(s);
return NULL; return MINISSDPC_SOCKET_ERROR;
} }
return s;
}
int
disconnectFromMiniSSDPD(int s)
{
if (close(s) < 0)
return MINISSDPC_SOCKET_ERROR;
return MINISSDPC_SUCCESS;
}
int
requestDevicesFromMiniSSDPD(int s, const char * devtype)
{
unsigned char buffer[256];
unsigned char * p;
unsigned int stsize, l;
stsize = strlen(devtype); stsize = strlen(devtype);
buffer[0] = 1; /* request type 1 : request devices/services by type */ if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8))
{
buffer[0] = 3; /* request type 3 : everything */
}
else
{
buffer[0] = 1; /* request type 1 : request devices/services by type */
}
p = buffer + 1; p = buffer + 1;
l = stsize; CODELENGTH(l, p); l = stsize; CODELENGTH(l, p);
if(p + stsize > buffer + sizeof(buffer)) if(p + stsize > buffer + sizeof(buffer))
{ {
/* devtype is too long ! */ /* devtype is too long ! */
close(s); #ifdef DEBUG
return NULL; fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n",
stsize, (unsigned)sizeof(buffer));
#endif /* DEBUG */
return MINISSDPC_INVALID_INPUT;
} }
memcpy(p, devtype, stsize); memcpy(p, devtype, stsize);
p += stsize; p += stsize;
@ -87,47 +242,608 @@ getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath)
{ {
/*syslog(LOG_ERR, "write(): %m");*/ /*syslog(LOG_ERR, "write(): %m");*/
perror("minissdpc.c: write()"); perror("minissdpc.c: write()");
close(s); return MINISSDPC_SOCKET_ERROR;
return NULL;
} }
return MINISSDPC_SUCCESS;
}
struct UPNPDev *
receiveDevicesFromMiniSSDPD(int s, int * error)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = NULL;
unsigned char buffer[256];
ssize_t n;
unsigned char * p;
unsigned char * url;
unsigned char * st;
unsigned int bufferindex;
unsigned int i, ndev;
unsigned int urlsize, stsize, usnsize, l;
n = read(s, buffer, sizeof(buffer)); n = read(s, buffer, sizeof(buffer));
if(n<=0) if(n<=0)
{ {
perror("minissdpc.c: read()"); perror("minissdpc.c: read()");
close(s); if (error)
*error = MINISSDPC_SOCKET_ERROR;
return NULL; return NULL;
} }
p = buffer + 1; ndev = buffer[0];
for(i = 0; i < buffer[0]; i++) bufferindex = 1;
for(i = 0; i < ndev; i++)
{ {
if(p+2>=buffer+sizeof(buffer)) DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER);
break; if(n<=0) {
DECODELENGTH(urlsize, p); if (error)
if(p+urlsize+2>=buffer+sizeof(buffer)) *error = MINISSDPC_INVALID_SERVER_REPLY;
break; return devlist;
url = p; }
p += urlsize; #ifdef DEBUG
DECODELENGTH(stsize, p); printf(" urlsize=%u", urlsize);
if(p+stsize+2>=buffer+sizeof(buffer)) #endif /* DEBUG */
break; url = malloc(urlsize);
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); if(url == NULL) {
if (error)
*error = MINISSDPC_MEMORY_ERROR;
return devlist;
}
READ_COPY_BUFFER(url, urlsize);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_return;
}
DECODELENGTH_READ(stsize, READ_BYTE_BUFFER);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_return;
}
#ifdef DEBUG
printf(" stsize=%u", stsize);
#endif /* DEBUG */
st = malloc(stsize);
if (st == NULL) {
if (error)
*error = MINISSDPC_MEMORY_ERROR;
goto free_url_and_return;
}
READ_COPY_BUFFER(st, stsize);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_st_and_return;
}
DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_url_and_st_and_return;
}
#ifdef DEBUG
printf(" usnsize=%u\n", usnsize);
#endif /* DEBUG */
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
if(tmp == NULL) {
if (error)
*error = MINISSDPC_MEMORY_ERROR;
goto free_url_and_st_and_return;
}
tmp->pNext = devlist; tmp->pNext = devlist;
tmp->descURL = tmp->buffer; tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize; tmp->st = tmp->buffer + 1 + urlsize;
memcpy(tmp->buffer, url, urlsize); memcpy(tmp->buffer, url, urlsize);
tmp->buffer[urlsize] = '\0'; tmp->buffer[urlsize] = '\0';
memcpy(tmp->buffer + urlsize + 1, p, stsize); memcpy(tmp->st, st, stsize);
p += stsize;
tmp->buffer[urlsize+1+stsize] = '\0'; tmp->buffer[urlsize+1+stsize] = '\0';
free(url);
free(st);
url = NULL;
st = NULL;
tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize;
READ_COPY_BUFFER(tmp->usn, usnsize);
if(n<=0) {
if (error)
*error = MINISSDPC_INVALID_SERVER_REPLY;
goto free_tmp_and_return;
}
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */
devlist = tmp; devlist = tmp;
/* added for compatibility with recent versions of MiniSSDPd
* >= 2007/12/19 */
DECODELENGTH(usnsize, p);
p += usnsize;
if(p>buffer + sizeof(buffer))
break;
} }
close(s); if (error)
*error = MINISSDPC_SUCCESS;
return devlist;
free_url_and_st_and_return:
free(st);
free_url_and_return:
free(url);
return devlist;
free_tmp_and_return:
free(tmp);
return devlist;
}
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
/* parseMSEARCHReply()
* the last 4 arguments are filled during the parsing :
* - location/locationsize : "location:" field of the SSDP reply packet
* - st/stsize : "st:" field of the SSDP reply packet.
* The strings are NOT null terminated */
static void
parseMSEARCHReply(const char * reply, int size,
const char * * location, int * locationsize,
const char * * st, int * stsize,
const char * * usn, int * usnsize)
{
int a, b, i;
i = 0;
a = i; /* start of the line */
b = 0; /* end of the "header" (position of the colon) */
while(i<size)
{
switch(reply[i])
{
case ':':
if(b==0)
{
b = i; /* end of the "header" */
/*for(j=a; j<b; j++)
{
putchar(reply[j]);
}
*/
}
break;
case '\x0a':
case '\x0d':
if(b!=0)
{
/*for(j=b+1; j<i; j++)
{
putchar(reply[j]);
}
putchar('\n');*/
/* skip the colon and white spaces */
do { b++; } while(reply[b]==' ');
if(0==strncasecmp(reply+a, "location", 8))
{
*location = reply+b;
*locationsize = i-b;
}
else if(0==strncasecmp(reply+a, "st", 2))
{
*st = reply+b;
*stsize = i-b;
}
else if(0==strncasecmp(reply+a, "usn", 3))
{
*usn = reply+b;
*usnsize = i-b;
}
b = 0;
}
a = i+1;
break;
default:
break;
}
i++;
}
}
/* port upnp discover : SSDP protocol */
#define SSDP_PORT 1900
#define XSTR(s) STR(s)
#define STR(s) #s
#define UPNP_MCAST_ADDR "239.255.255.250"
/* for IPv6 */
#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
/* direct discovery if minissdpd responses are not sufficient */
/* ssdpDiscoverDevices() :
* return a chained list of all devices found or NULL if
* no devices was found.
* It is up to the caller to free the chained list
* delay is in millisecond (poll).
* UDA v1.1 says :
* The TTL for the IP packet SHOULD default to 2 and
* SHOULD be configurable. */
struct UPNPDev *
ssdpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
int localport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes)
{
struct UPNPDev * tmp;
struct UPNPDev * devlist = 0;
unsigned int scope_id = 0;
int opt = 1;
static const char MSearchMsgFmt[] =
"M-SEARCH * HTTP/1.1\r\n"
"HOST: %s:" XSTR(SSDP_PORT) "\r\n"
"ST: %s\r\n"
"MAN: \"ssdp:discover\"\r\n"
"MX: %u\r\n"
"\r\n";
int deviceIndex;
char bufr[1536]; /* reception and emission buffer */
int sudp;
int n;
struct sockaddr_storage sockudp_r;
unsigned int mx;
#ifdef NO_GETADDRINFO
struct sockaddr_storage sockudp_w;
#else
int rv;
struct addrinfo hints, *servinfo, *p;
#endif
#ifdef _WIN32
MIB_IPFORWARDROW ip_forward;
unsigned long _ttl = (unsigned long)ttl;
#endif
int linklocal = 1;
if(error)
*error = MINISSDPC_UNKNOWN_ERROR;
if(localport==UPNP_LOCAL_PORT_SAME)
localport = SSDP_PORT;
#ifdef _WIN32
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
#else
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
#endif
if(sudp < 0)
{
if(error)
*error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("socket");
return NULL;
}
/* reception */
memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
p->sin6_family = AF_INET6;
if(localport > 0 && localport < 65536)
p->sin6_port = htons((unsigned short)localport);
p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
p->sin_family = AF_INET;
if(localport > 0 && localport < 65536)
p->sin_port = htons((unsigned short)localport);
p->sin_addr.s_addr = INADDR_ANY;
}
#ifdef _WIN32
/* This code could help us to use the right Network interface for
* SSDP multicast traffic */
/* Get IP associated with the index given in the ip_forward struct
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
if(!ipv6
&& (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
DWORD dwRetVal = 0;
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
#ifdef DEBUG
IN_ADDR IPAddr;
#endif
int i;
#ifdef DEBUG
printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
#endif
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
if(pIPAddrTable) {
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
free(pIPAddrTable);
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
}
}
if(pIPAddrTable) {
dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
if (dwRetVal == NO_ERROR) {
#ifdef DEBUG
printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
#endif
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
#ifdef DEBUG
printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
printf("\tType and State[%d]:", i);
printf("\n");
#endif
if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
/* Set the address of this interface to be used */
struct in_addr mc_if;
memset(&mc_if, 0, sizeof(mc_if));
mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
PRINT_SOCKET_ERROR("setsockopt");
}
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
#ifndef DEBUG
break;
#endif
}
}
}
free(pIPAddrTable);
pIPAddrTable = NULL;
}
}
#endif /* _WIN32 */
#ifdef _WIN32
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
#else
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
#endif
{
if(error)
*error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)");
return NULL;
}
#ifdef _WIN32
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0)
#else /* _WIN32 */
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0)
#endif /* _WIN32 */
{
/* not a fatal error */
PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)");
}
if(multicastif)
{
if(ipv6) {
#if !defined(_WIN32)
/* according to MSDN, if_nametoindex() is supported since
* MS Windows Vista and MS Windows Server 2008.
* http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
#endif
#endif
} else {
struct in_addr mc_if;
mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
if(mc_if.s_addr != INADDR_NONE)
{
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
} else {
#ifdef HAS_IP_MREQN
/* was not an ip address, try with an interface name */
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
memset(&reqn, 0, sizeof(struct ip_mreqn));
reqn.imr_ifindex = if_nametoindex(multicastif);
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported with interface name.\n");
#endif
#endif
}
}
}
/* Before sending the packed, we first "bind" in order to be able
* to receive the response */
if (bind(sudp, (const struct sockaddr *)&sockudp_r,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
{
if(error)
*error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("bind");
closesocket(sudp);
return NULL;
}
if(error)
*error = MINISSDPC_SUCCESS;
/* Calculating maximum response time in seconds */
mx = ((unsigned int)delay) / 1000u;
if(mx == 0) {
mx = 1;
delay = 1000;
}
/* receiving SSDP response packet */
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
/* sending the SSDP M-SEARCH packet */
n = snprintf(bufr, sizeof(bufr),
MSearchMsgFmt,
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR,
deviceTypes[deviceIndex], mx);
if ((unsigned int)n >= sizeof(bufr)) {
if(error)
*error = MINISSDPC_MEMORY_ERROR;
goto error;
}
#ifdef DEBUG
/*printf("Sending %s", bufr);*/
printf("Sending M-SEARCH request to %s with ST: %s\n",
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR,
deviceTypes[deviceIndex]);
#endif
#ifdef NO_GETADDRINFO
/* the following code is not using getaddrinfo */
/* emission */
memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
p->sin6_family = AF_INET6;
p->sin6_port = htons(SSDP_PORT);
inet_pton(AF_INET6,
linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
&(p->sin6_addr));
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
p->sin_family = AF_INET;
p->sin_port = htons(SSDP_PORT);
p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
}
n = sendto(sudp, bufr, n, 0, &sockudp_w,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
if (n < 0) {
if(error)
*error = MINISSDPC_SOCKET_ERROR;
PRINT_SOCKET_ERROR("sendto");
break;
}
#else /* #ifdef NO_GETADDRINFO */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
hints.ai_socktype = SOCK_DGRAM;
/*hints.ai_flags = */
if ((rv = getaddrinfo(ipv6
? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
: UPNP_MCAST_ADDR,
XSTR(SSDP_PORT), &hints, &servinfo)) != 0) {
if(error)
*error = MINISSDPC_SOCKET_ERROR;
#ifdef _WIN32
fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
#else
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
#endif
break;
}
for(p = servinfo; p; p = p->ai_next) {
n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
if (n < 0) {
#ifdef DEBUG
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
}
#endif
PRINT_SOCKET_ERROR("sendto");
continue;
}
}
freeaddrinfo(servinfo);
if(n < 0) {
if(error)
*error = MINISSDPC_SOCKET_ERROR;
break;
}
#endif /* #ifdef NO_GETADDRINFO */
/* Waiting for SSDP REPLY packet to M-SEARCH
* if searchalltypes is set, enter the loop only
* when the last deviceType is reached */
if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do {
n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
if (n < 0) {
/* error */
if(error)
*error = MINISSDPC_SOCKET_ERROR;
goto error;
} else if (n == 0) {
/* no data or Time Out */
#ifdef DEBUG
printf("NODATA or TIMEOUT\n");
#endif /* DEBUG */
if (devlist && !searchalltypes) {
/* found some devices, stop now*/
if(error)
*error = MINISSDPC_SUCCESS;
goto error;
}
} else {
const char * descURL=NULL;
int urlsize=0;
const char * st=NULL;
int stsize=0;
const char * usn=NULL;
int usnsize=0;
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize);
if(st&&descURL) {
#ifdef DEBUG
printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n",
stsize, st, usnsize, (usn?usn:""), urlsize, descURL);
#endif /* DEBUG */
for(tmp=devlist; tmp; tmp = tmp->pNext) {
if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
tmp->descURL[urlsize] == '\0' &&
memcmp(tmp->st, st, stsize) == 0 &&
tmp->st[stsize] == '\0' &&
(usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) &&
tmp->usn[usnsize] == '\0')
break;
}
/* at the exit of the loop above, tmp is null if
* no duplicate device was found */
if(tmp)
continue;
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize);
if(!tmp) {
/* memory allocation error */
if(error)
*error = MINISSDPC_MEMORY_ERROR;
goto error;
}
tmp->pNext = devlist;
tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize;
tmp->usn = tmp->st + 1 + stsize;
memcpy(tmp->buffer, descURL, urlsize);
tmp->buffer[urlsize] = '\0';
memcpy(tmp->st, st, stsize);
tmp->buffer[urlsize+1+stsize] = '\0';
if(usn != NULL)
memcpy(tmp->usn, usn, usnsize);
tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0';
tmp->scope_id = scope_id;
devlist = tmp;
}
}
} while(n > 0);
if(ipv6) {
/* switch linklocal flag */
if(linklocal) {
linklocal = 0;
--deviceIndex;
} else {
linklocal = 1;
}
}
}
error:
closesocket(sudp);
return devlist; return devlist;
} }

View file

@ -1,15 +1,58 @@
/* $Id: minissdpc.h,v 1.1 2007/08/31 15:15:33 nanard Exp $ */ /* $Id: minissdpc.h,v 1.6 2015/09/18 12:45:16 nanard Exp $ */
/* Project: miniupnp /* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard * Author: Thomas Bernard
* Copyright (c) 2005-2007 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed * This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */ * in the LICENCE file provided within this distribution */
#ifndef MINISSDPC_H_INCLUDED #ifndef MINISSDPC_H_INCLUDED
#define MINISSDPC_H_INCLUDED #define MINISSDPC_H_INCLUDED
struct UPNPDev * #include "miniupnpc_declspec.h"
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath); #include "upnpdev.h"
/* error codes : */
#define MINISSDPC_SUCCESS (0)
#define MINISSDPC_UNKNOWN_ERROR (-1)
#define MINISSDPC_SOCKET_ERROR (-101)
#define MINISSDPC_MEMORY_ERROR (-102)
#define MINISSDPC_INVALID_INPUT (-103)
#define MINISSDPC_INVALID_SERVER_REPLY (-104)
#ifdef __cplusplus
extern "C" {
#endif
#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__))
MINIUPNP_LIBSPEC struct UPNPDev *
getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error);
MINIUPNP_LIBSPEC int
connectToMiniSSDPD(const char * socketpath);
MINIUPNP_LIBSPEC int
disconnectFromMiniSSDPD(int fd);
MINIUPNP_LIBSPEC int
requestDevicesFromMiniSSDPD(int fd, const char * devtype);
MINIUPNP_LIBSPEC struct UPNPDev *
receiveDevicesFromMiniSSDPD(int fd, int * error);
#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */
MINIUPNP_LIBSPEC struct UPNPDev *
ssdpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
int localport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes);
#ifdef __cplusplus
}
#endif
#endif #endif

View file

@ -1,26 +1,11 @@
/* $Id: miniupnpc.c,v 1.116 2014/01/31 14:09:03 nanard Exp $ */ /* $Id: miniupnpc.c,v 1.135 2015/07/23 20:40:08 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab */
/* Project : miniupnp /* Project : miniupnp
* Web : http://miniupnp.free.fr/ * Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD * Author : Thomas BERNARD
* copyright (c) 2005-2014 Thomas Bernard * copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the * This software is subjet to the conditions detailed in the
* provided LICENSE file. */ * provided LICENSE file. */
#define __EXTENSIONS__ 1
#if !defined(__APPLE__) && !defined(__sun)
#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__)
#ifndef __cplusplus
#define _XOPEN_SOURCE 600
#endif
#endif
#ifndef __BSD_VISIBLE
#define __BSD_VISIBLE 1
#endif
#endif
#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__)
#define HAS_IP_MREQN
#endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -63,28 +48,11 @@
#include <errno.h> #include <errno.h>
#define closesocket close #define closesocket close
#endif /* #else _WIN32 */ #endif /* #else _WIN32 */
#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
#include <sys/time.h>
#endif
#if defined(__amigaos__) || defined(__amigaos4__)
/* Amiga OS specific stuff */
#define TIMEVAL struct timeval
#endif
#ifdef __GNU__ #ifdef __GNU__
#define MAXHOSTNAMELEN 64 #define MAXHOSTNAMELEN 64
#endif #endif
#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN)
/* Several versions of glibc don't define this structure, define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */
struct ip_mreqn
{
struct in_addr imr_multiaddr; /* IP multicast address of group */
struct in_addr imr_address; /* local IP address of interface */
int imr_ifindex; /* Interface index */
};
#endif
#include "miniupnpc.h" #include "miniupnpc.h"
#include "minissdpc.h" #include "minissdpc.h"
#include "miniwget.h" #include "miniwget.h"
@ -92,13 +60,9 @@ struct ip_mreqn
#include "minixml.h" #include "minixml.h"
#include "upnpcommands.h" #include "upnpcommands.h"
#include "connecthostport.h" #include "connecthostport.h"
#include "receivedata.h"
#ifdef _WIN32 /* compare the begining of a string with a constant string */
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); #define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1))
#else
#define PRINT_SOCKET_ERROR(x) perror(x)
#endif
#ifndef MAXHOSTNAMELEN #ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64 #define MAXHOSTNAMELEN 64
@ -140,73 +104,93 @@ char * simpleUPnPcommand2(int s, const char * url, const char * service,
char * path; char * path;
char soapact[128]; char soapact[128];
char soapbody[2048]; char soapbody[2048];
int soapbodylen;
char * buf; char * buf;
int n; int n;
*bufsize = 0; *bufsize = 0;
snprintf(soapact, sizeof(soapact), "%s#%s", service, action); snprintf(soapact, sizeof(soapact), "%s#%s", service, action);
if(args==NULL) if(args==NULL)
{ {
/*soapbodylen = */snprintf(soapbody, sizeof(soapbody), soapbodylen = snprintf(soapbody, sizeof(soapbody),
"<?xml version=\"1.0\"?>\r\n" "<?xml version=\"1.0\"?>\r\n"
"<" SOAPPREFIX ":Envelope " "<" SOAPPREFIX ":Envelope "
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<" SOAPPREFIX ":Body>" "<" SOAPPREFIX ":Body>"
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
"</" SERVICEPREFIX ":%s>" "</" SERVICEPREFIX ":%s>"
"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>" "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
"\r\n", action, service, action); "\r\n", action, service, action);
if ((unsigned int)soapbodylen >= sizeof(soapbody))
return NULL;
} }
else else
{ {
char * p; char * p;
const char * pe, * pv; const char * pe, * pv;
int soapbodylen; const char * const pend = soapbody + sizeof(soapbody);
soapbodylen = snprintf(soapbody, sizeof(soapbody), soapbodylen = snprintf(soapbody, sizeof(soapbody),
"<?xml version=\"1.0\"?>\r\n" "<?xml version=\"1.0\"?>\r\n"
"<" SOAPPREFIX ":Envelope " "<" SOAPPREFIX ":Envelope "
"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<" SOAPPREFIX ":Body>" "<" SOAPPREFIX ":Body>"
"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">",
action, service); action, service);
if ((unsigned int)soapbodylen >= sizeof(soapbody))
return NULL;
p = soapbody + soapbodylen; p = soapbody + soapbodylen;
while(args->elt) while(args->elt)
{ {
/* check that we are never overflowing the string... */ if(p >= pend) /* check for space to write next byte */
if(soapbody + sizeof(soapbody) <= p + 100)
{
/* we keep a margin of at least 100 bytes */
return NULL; return NULL;
}
*(p++) = '<'; *(p++) = '<';
pe = args->elt; pe = args->elt;
while(*pe) while(p < pend && *pe)
*(p++) = *(pe++); *(p++) = *(pe++);
if(p >= pend) /* check for space to write next byte */
return NULL;
*(p++) = '>'; *(p++) = '>';
if((pv = args->val)) if((pv = args->val))
{ {
while(*pv) while(p < pend && *pv)
*(p++) = *(pv++); *(p++) = *(pv++);
} }
if((p+2) > pend) /* check for space to write next 2 bytes */
return NULL;
*(p++) = '<'; *(p++) = '<';
*(p++) = '/'; *(p++) = '/';
pe = args->elt; pe = args->elt;
while(*pe) while(p < pend && *pe)
*(p++) = *(pe++); *(p++) = *(pe++);
if(p >= pend) /* check for space to write next byte */
return NULL;
*(p++) = '>'; *(p++) = '>';
args++; args++;
} }
if((p+4) > pend) /* check for space to write next 4 bytes */
return NULL;
*(p++) = '<'; *(p++) = '<';
*(p++) = '/'; *(p++) = '/';
*(p++) = SERVICEPREFIX2; *(p++) = SERVICEPREFIX2;
*(p++) = ':'; *(p++) = ':';
pe = action; pe = action;
while(*pe) while(p < pend && *pe)
*(p++) = *(pe++); *(p++) = *(pe++);
strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n",
soapbody + sizeof(soapbody) - p); pend - p);
if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */
return NULL;
} }
if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; if(!parseURL(url, hostname, &port, &path, NULL)) return NULL;
if(s < 0) { if(s < 0) {
@ -263,98 +247,92 @@ char * simpleUPnPcommand(int s, const char * url, const char * service,
return buf; return buf;
} }
/* parseMSEARCHReply() /* upnpDiscoverDevices() :
* the last 4 arguments are filled during the parsing :
* - location/locationsize : "location:" field of the SSDP reply packet
* - st/stsize : "st:" field of the SSDP reply packet.
* The strings are NOT null terminated */
static void
parseMSEARCHReply(const char * reply, int size,
const char * * location, int * locationsize,
const char * * st, int * stsize)
{
int a, b, i;
i = 0;
a = i; /* start of the line */
b = 0; /* end of the "header" (position of the colon) */
while(i<size)
{
switch(reply[i])
{
case ':':
if(b==0)
{
b = i; /* end of the "header" */
/*for(j=a; j<b; j++)
{
putchar(reply[j]);
}
*/
}
break;
case '\x0a':
case '\x0d':
if(b!=0)
{
/*for(j=b+1; j<i; j++)
{
putchar(reply[j]);
}
putchar('\n');*/
/* skip the colon and white spaces */
do { b++; } while(reply[b]==' ');
if(0==strncasecmp(reply+a, "location", 8))
{
*location = reply+b;
*locationsize = i-b;
}
else if(0==strncasecmp(reply+a, "st", 2))
{
*st = reply+b;
*stsize = i-b;
}
b = 0;
}
a = i+1;
break;
default:
break;
}
i++;
}
}
/* port upnp discover : SSDP protocol */
#define PORT 1900
#define XSTR(s) STR(s)
#define STR(s) #s
#define UPNP_MCAST_ADDR "239.255.255.250"
/* for IPv6 */
#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */
#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */
/* upnpDiscover() :
* return a chained list of all devices found or NULL if * return a chained list of all devices found or NULL if
* no devices was found. * no devices was found.
* It is up to the caller to free the chained list * It is up to the caller to free the chained list
* delay is in millisecond (poll) */ * delay is in millisecond (poll).
* UDA v1.1 says :
* The TTL for the IP packet SHOULD default to 2 and
* SHOULD be configurable. */
MINIUPNP_LIBSPEC struct UPNPDev * MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif, upnpDiscoverDevices(const char * const deviceTypes[],
const char * minissdpdsock, int sameport, int delay, const char * multicastif,
int ipv6, const char * minissdpdsock, int localport,
int * error) int ipv6, unsigned char ttl,
int * error,
int searchalltypes)
{ {
struct UPNPDev * tmp; struct UPNPDev * tmp;
struct UPNPDev * devlist = 0; struct UPNPDev * devlist = 0;
unsigned int scope_id = 0; #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
int opt = 1; int deviceIndex;
static const char MSearchMsgFmt[] = #endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
"M-SEARCH * HTTP/1.1\r\n"
"HOST: %s:" XSTR(PORT) "\r\n" if(error)
"ST: %s\r\n" *error = UPNPDISCOVER_UNKNOWN_ERROR;
"MAN: \"ssdp:discover\"\r\n" #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
"MX: %u\r\n" /* first try to get infos from minissdpd ! */
"\r\n"; if(!minissdpdsock)
minissdpdsock = "/var/run/minissdpd.sock";
for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) {
struct UPNPDev * minissdpd_devlist;
int only_rootdevice = 1;
minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex],
minissdpdsock, 0);
if(minissdpd_devlist) {
#ifdef DEBUG
printf("returned by MiniSSDPD: %s\t%s\n",
minissdpd_devlist->st, minissdpd_devlist->descURL);
#endif /* DEBUG */
if(!strstr(minissdpd_devlist->st, "rootdevice"))
only_rootdevice = 0;
for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) {
#ifdef DEBUG
printf("returned by MiniSSDPD: %s\t%s\n",
tmp->pNext->st, tmp->pNext->descURL);
#endif /* DEBUG */
if(!strstr(tmp->st, "rootdevice"))
only_rootdevice = 0;
}
tmp->pNext = devlist;
devlist = minissdpd_devlist;
if(!searchalltypes && !only_rootdevice)
break;
}
}
for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) {
/* We return what we have found if it was not only a rootdevice */
if(!strstr(tmp->st, "rootdevice")) {
if(error)
*error = UPNPDISCOVER_SUCCESS;
return devlist;
}
}
#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
/* direct discovery if minissdpd responses are not sufficient */
{
struct UPNPDev * discovered_devlist;
discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport,
ipv6, ttl, error, searchalltypes);
if(devlist == NULL)
devlist = discovered_devlist;
else {
for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext);
tmp->pNext = discovered_devlist;
}
}
return devlist;
}
/* upnpDiscover() Discover IGD device */
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl,
int * error)
{
static const char * const deviceList[] = { static const char * const deviceList[] = {
#if 0 #if 0
"urn:schemas-upnp-org:device:InternetGatewayDevice:2", "urn:schemas-upnp-org:device:InternetGatewayDevice:2",
@ -364,395 +342,117 @@ upnpDiscover(int delay, const char * multicastif,
"urn:schemas-upnp-org:service:WANIPConnection:1", "urn:schemas-upnp-org:service:WANIPConnection:1",
"urn:schemas-upnp-org:service:WANPPPConnection:1", "urn:schemas-upnp-org:service:WANPPPConnection:1",
"upnp:rootdevice", "upnp:rootdevice",
/*"ssdp:all",*/
0 0
}; };
int deviceIndex = 0; return upnpDiscoverDevices(deviceList,
char bufr[1536]; /* reception and emission buffer */ delay, multicastif, minissdpdsock, localport,
int sudp; ipv6, ttl, error, 0);
int n;
struct sockaddr_storage sockudp_r;
unsigned int mx;
#ifdef NO_GETADDRINFO
struct sockaddr_storage sockudp_w;
#else
int rv;
struct addrinfo hints, *servinfo, *p;
#endif
#ifdef _WIN32
MIB_IPFORWARDROW ip_forward;
#endif
int linklocal = 1;
if(error)
*error = UPNPDISCOVER_UNKNOWN_ERROR;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
/* first try to get infos from minissdpd ! */
if(!minissdpdsock)
minissdpdsock = "/var/run/minissdpd.sock";
while(!devlist && deviceList[deviceIndex]) {
devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex],
minissdpdsock);
/* We return what we have found if it was not only a rootdevice */
if(devlist && !strstr(deviceList[deviceIndex], "rootdevice")) {
if(error)
*error = UPNPDISCOVER_SUCCESS;
return devlist;
}
deviceIndex++;
}
deviceIndex = 0;
#endif
/* fallback to direct discovery */
#ifdef _WIN32
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP);
#else
sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0);
#endif
if(sudp < 0)
{
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("socket");
return NULL;
}
/* reception */
memset(&sockudp_r, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r;
p->sin6_family = AF_INET6;
if(sameport)
p->sin6_port = htons(PORT);
p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r;
p->sin_family = AF_INET;
if(sameport)
p->sin_port = htons(PORT);
p->sin_addr.s_addr = INADDR_ANY;
}
#ifdef _WIN32
/* This code could help us to use the right Network interface for
* SSDP multicast traffic */
/* Get IP associated with the index given in the ip_forward struct
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
if(!ipv6
&& (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) {
DWORD dwRetVal = 0;
PMIB_IPADDRTABLE pIPAddrTable;
DWORD dwSize = 0;
#ifdef DEBUG
IN_ADDR IPAddr;
#endif
int i;
#ifdef DEBUG
printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop);
#endif
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE));
if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
free(pIPAddrTable);
pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize);
}
if(pIPAddrTable) {
dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
#ifdef DEBUG
printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries);
#endif
for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) {
#ifdef DEBUG
printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex);
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) );
IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr);
printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize);
printf("\tType and State[%d]:", i);
printf("\n");
#endif
if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) {
/* Set the address of this interface to be used */
struct in_addr mc_if;
memset(&mc_if, 0, sizeof(mc_if));
mc_if.s_addr = pIPAddrTable->table[i].dwAddr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) {
PRINT_SOCKET_ERROR("setsockopt");
}
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
#ifndef DEBUG
break;
#endif
}
}
free(pIPAddrTable);
pIPAddrTable = NULL;
}
}
#endif
#ifdef _WIN32
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0)
#else
if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0)
#endif
{
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("setsockopt");
return NULL;
}
if(multicastif)
{
if(ipv6) {
#if !defined(_WIN32)
/* according to MSDN, if_nametoindex() is supported since
* MS Windows Vista and MS Windows Server 2008.
* http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */
unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */
if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported in IPv6 under Windows.\n");
#endif
#endif
} else {
struct in_addr mc_if;
mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */
if(mc_if.s_addr != INADDR_NONE)
{
((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr;
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
} else {
#ifdef HAS_IP_MREQN
/* was not an ip address, try with an interface name */
struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */
memset(&reqn, 0, sizeof(struct ip_mreqn));
reqn.imr_ifindex = if_nametoindex(multicastif);
if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0)
{
PRINT_SOCKET_ERROR("setsockopt");
}
#else
#ifdef DEBUG
printf("Setting of multicast interface not supported with interface name.\n");
#endif
#endif
}
}
}
/* Before sending the packed, we first "bind" in order to be able
* to receive the response */
if (bind(sudp, (const struct sockaddr *)&sockudp_r,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0)
{
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("bind");
closesocket(sudp);
return NULL;
}
if(error)
*error = UPNPDISCOVER_SUCCESS;
/* Calculating maximum response time in seconds */
mx = ((unsigned int)delay) / 1000u;
if(mx == 0) {
mx = 1;
delay = 1000;
}
/* receiving SSDP response packet */
for(n = 0; deviceList[deviceIndex]; deviceIndex++)
{
if(n == 0)
{
/* sending the SSDP M-SEARCH packet */
n = snprintf(bufr, sizeof(bufr),
MSearchMsgFmt,
ipv6 ?
(linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]")
: UPNP_MCAST_ADDR,
deviceList[deviceIndex], mx);
#ifdef DEBUG
printf("Sending %s", bufr);
#endif
#ifdef NO_GETADDRINFO
/* the following code is not using getaddrinfo */
/* emission */
memset(&sockudp_w, 0, sizeof(struct sockaddr_storage));
if(ipv6) {
struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w;
p->sin6_family = AF_INET6;
p->sin6_port = htons(PORT);
inet_pton(AF_INET6,
linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR,
&(p->sin6_addr));
} else {
struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w;
p->sin_family = AF_INET;
p->sin_port = htons(PORT);
p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);
}
n = sendto(sudp, bufr, n, 0,
&sockudp_w,
ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
if (n < 0) {
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
PRINT_SOCKET_ERROR("sendto");
break;
}
#else /* #ifdef NO_GETADDRINFO */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */
hints.ai_socktype = SOCK_DGRAM;
/*hints.ai_flags = */
if ((rv = getaddrinfo(ipv6
? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR)
: UPNP_MCAST_ADDR,
XSTR(PORT), &hints, &servinfo)) != 0) {
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
#ifdef _WIN32
fprintf(stderr, "getaddrinfo() failed: %d\n", rv);
#else
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
#endif
break;
}
for(p = servinfo; p; p = p->ai_next) {
n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen);
if (n < 0) {
#ifdef DEBUG
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf,
sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf);
}
#endif
PRINT_SOCKET_ERROR("sendto");
continue;
}
}
freeaddrinfo(servinfo);
if(n < 0) {
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
break;
}
#endif /* #ifdef NO_GETADDRINFO */
}
/* Waiting for SSDP REPLY packet to M-SEARCH */
n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id);
if (n < 0) {
/* error */
if(error)
*error = UPNPDISCOVER_SOCKET_ERROR;
break;
} else if (n == 0) {
/* no data or Time Out */
if (devlist) {
/* no more device type to look for... */
if(error)
*error = UPNPDISCOVER_SUCCESS;
break;
}
if(ipv6) {
if(linklocal) {
linklocal = 0;
--deviceIndex;
} else {
linklocal = 1;
}
}
} else {
const char * descURL=NULL;
int urlsize=0;
const char * st=NULL;
int stsize=0;
/*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */
parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize);
if(st&&descURL)
{
#ifdef DEBUG
printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n",
stsize, st, urlsize, descURL);
#endif
for(tmp=devlist; tmp; tmp = tmp->pNext) {
if(memcmp(tmp->descURL, descURL, urlsize) == 0 &&
tmp->descURL[urlsize] == '\0' &&
memcmp(tmp->st, st, stsize) == 0 &&
tmp->st[stsize] == '\0')
break;
}
/* at the exit of the loop above, tmp is null if
* no duplicate device was found */
if(tmp)
continue;
tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize);
if(!tmp) {
/* memory allocation error */
if(error)
*error = UPNPDISCOVER_MEMORY_ERROR;
break;
}
tmp->pNext = devlist;
tmp->descURL = tmp->buffer;
tmp->st = tmp->buffer + 1 + urlsize;
memcpy(tmp->buffer, descURL, urlsize);
tmp->buffer[urlsize] = '\0';
memcpy(tmp->buffer + urlsize + 1, st, stsize);
tmp->buffer[urlsize+1+stsize] = '\0';
tmp->scope_id = scope_id;
devlist = tmp;
}
}
}
closesocket(sudp);
return devlist;
} }
/* freeUPNPDevlist() should be used to /* upnpDiscoverAll() Discover all UPnP devices */
* free the chained list returned by upnpDiscover() */ MINIUPNP_LIBSPEC struct UPNPDev *
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist) upnpDiscoverAll(int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl,
int * error)
{ {
struct UPNPDev * next; static const char * const deviceList[] = {
while(devlist) /*"upnp:rootdevice",*/
{ "ssdp:all",
next = devlist->pNext; 0
free(devlist); };
devlist = next; return upnpDiscoverDevices(deviceList,
} delay, multicastif, minissdpdsock, localport,
ipv6, ttl, error, 0);
} }
static void /* upnpDiscoverDevice() Discover a specific device */
url_cpy_or_cat(char * dst, const char * src, int n) MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl,
int * error)
{ {
if( (src[0] == 'h') const char * const deviceList[] = {
&&(src[1] == 't') device,
&&(src[2] == 't') 0
&&(src[3] == 'p') };
&&(src[4] == ':') return upnpDiscoverDevices(deviceList,
&&(src[5] == '/') delay, multicastif, minissdpdsock, localport,
&&(src[6] == '/')) ipv6, ttl, error, 0);
{ }
strncpy(dst, src, n);
static char *
build_absolute_url(const char * baseurl, const char * descURL,
const char * url, unsigned int scope_id)
{
int l, n;
char * s;
const char * base;
char * p;
#if defined(IF_NAMESIZE) && !defined(_WIN32)
char ifname[IF_NAMESIZE];
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
char scope_str[8];
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
if( (url[0] == 'h')
&&(url[1] == 't')
&&(url[2] == 't')
&&(url[3] == 'p')
&&(url[4] == ':')
&&(url[5] == '/')
&&(url[6] == '/'))
return strdup(url);
base = (baseurl[0] == '\0') ? descURL : baseurl;
n = strlen(base);
if(n > 7) {
p = strchr(base + 7, '/');
if(p)
n = p - base;
} }
else l = n + strlen(url) + 1;
{ if(url[0] != '/')
int l = strlen(dst); l++;
if(src[0] != '/') if(scope_id != 0) {
dst[l++] = '/'; #if defined(IF_NAMESIZE) && !defined(_WIN32)
if(l<=n) if(if_indextoname(scope_id, ifname)) {
strncpy(dst + l, src, n - l); l += 3 + strlen(ifname); /* 3 == strlen(%25) */
}
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
/* under windows, scope is numerical */
l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
} }
s = malloc(l);
if(s == NULL) return NULL;
memcpy(s, base, n);
if(scope_id != 0) {
s[n] = '\0';
if(0 == memcmp(s, "http://[fe80:", 13)) {
/* this is a linklocal IPv6 address */
p = strchr(s, ']');
if(p) {
/* insert %25<scope> into URL */
#if defined(IF_NAMESIZE) && !defined(_WIN32)
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, ifname, strlen(ifname));
n += 3 + strlen(ifname);
#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, scope_str, strlen(scope_str));
n += 3 + strlen(scope_str);
#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */
}
}
}
if(url[0] != '/')
s[n++] = '/';
memcpy(s + n, url, l - n);
return s;
} }
/* Prepare the Urls for usage... /* Prepare the Urls for usage...
@ -761,89 +461,24 @@ MINIUPNP_LIBSPEC void
GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data,
const char * descURL, unsigned int scope_id) const char * descURL, unsigned int scope_id)
{ {
char * p;
int n1, n2, n3, n4;
#ifdef IF_NAMESIZE
char ifname[IF_NAMESIZE];
#else
char scope_str[8];
#endif
n1 = strlen(data->urlbase);
if(n1==0)
n1 = strlen(descURL);
if(scope_id != 0) {
#ifdef IF_NAMESIZE
if(if_indextoname(scope_id, ifname)) {
n1 += 3 + strlen(ifname); /* 3 == strlen(%25) */
}
#else
/* under windows, scope is numerical */
snprintf(scope_str, sizeof(scope_str), "%u", scope_id);
#endif
}
n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */
n2 = n1; n3 = n1; n4 = n1;
n1 += strlen(data->first.scpdurl);
n2 += strlen(data->first.controlurl);
n3 += strlen(data->CIF.controlurl);
n4 += strlen(data->IPv6FC.controlurl);
/* allocate memory to store URLs */
urls->ipcondescURL = (char *)malloc(n1);
urls->controlURL = (char *)malloc(n2);
urls->controlURL_CIF = (char *)malloc(n3);
urls->controlURL_6FC = (char *)malloc(n4);
/* strdup descURL */ /* strdup descURL */
urls->rootdescURL = strdup(descURL); urls->rootdescURL = strdup(descURL);
/* get description of WANIPConnection */ /* get description of WANIPConnection */
if(data->urlbase[0] != '\0') urls->ipcondescURL = build_absolute_url(data->urlbase, descURL,
strncpy(urls->ipcondescURL, data->urlbase, n1); data->first.scpdurl, scope_id);
else urls->controlURL = build_absolute_url(data->urlbase, descURL,
strncpy(urls->ipcondescURL, descURL, n1); data->first.controlurl, scope_id);
p = strchr(urls->ipcondescURL+7, '/'); urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL,
if(p) p[0] = '\0'; data->CIF.controlurl, scope_id);
if(scope_id != 0) { urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL,
if(0 == memcmp(urls->ipcondescURL, "http://[fe80:", 13)) { data->IPv6FC.controlurl, scope_id);
/* this is a linklocal IPv6 address */
p = strchr(urls->ipcondescURL, ']');
if(p) {
/* insert %25<scope> into URL */
#ifdef IF_NAMESIZE
memmove(p + 3 + strlen(ifname), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, ifname, strlen(ifname));
#else
memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1);
memcpy(p, "%25", 3);
memcpy(p + 3, scope_str, strlen(scope_str));
#endif
}
}
}
strncpy(urls->controlURL, urls->ipcondescURL, n2);
strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3);
strncpy(urls->controlURL_6FC, urls->ipcondescURL, n4);
url_cpy_or_cat(urls->ipcondescURL, data->first.scpdurl, n1);
url_cpy_or_cat(urls->controlURL, data->first.controlurl, n2);
url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3);
url_cpy_or_cat(urls->controlURL_6FC, data->IPv6FC.controlurl, n4);
#ifdef DEBUG #ifdef DEBUG
printf("urls->ipcondescURL='%s' %u n1=%d\n", urls->ipcondescURL, printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL);
(unsigned)strlen(urls->ipcondescURL), n1); printf("urls->controlURL='%s'\n", urls->controlURL);
printf("urls->controlURL='%s' %u n2=%d\n", urls->controlURL, printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF);
(unsigned)strlen(urls->controlURL), n2); printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC);
printf("urls->controlURL_CIF='%s' %u n3=%d\n", urls->controlURL_CIF,
(unsigned)strlen(urls->controlURL_CIF), n3);
printf("urls->controlURL_6FC='%s' %u n4=%d\n", urls->controlURL_6FC,
(unsigned)strlen(urls->controlURL_6FC), n4);
#endif #endif
} }
@ -873,9 +508,9 @@ UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data)
UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype,
status, &uptime, NULL); status, &uptime, NULL);
if(0 == strcmp("Connected", status)) if(0 == strcmp("Connected", status))
{
return 1; return 1;
} else if(0 == strcmp("Up", status)) /* Also accept "Up" */
return 1;
else else
return 0; return 0;
} }
@ -911,6 +546,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */
int n_igd = 0; int n_igd = 0;
char extIpAddr[16]; char extIpAddr[16];
char myLanAddr[40];
if(!devlist) if(!devlist)
{ {
#ifdef DEBUG #ifdef DEBUG
@ -933,7 +569,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
/* we should choose an internet gateway device. /* we should choose an internet gateway device.
* with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */
desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size),
lanaddr, lanaddrlen, myLanAddr, sizeof(myLanAddr),
dev->scope_id); dev->scope_id);
#ifdef DEBUG #ifdef DEBUG
if(!desc[i].xml) if(!desc[i].xml)
@ -946,11 +582,13 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
memset(data, 0, sizeof(struct IGDdatas)); memset(data, 0, sizeof(struct IGDdatas));
memset(urls, 0, sizeof(struct UPNPUrls)); memset(urls, 0, sizeof(struct UPNPUrls));
parserootdesc(desc[i].xml, desc[i].size, data); parserootdesc(desc[i].xml, desc[i].size, data);
if(0==strcmp(data->CIF.servicetype, if(COMPARE(data->CIF.servicetype,
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:"))
{ {
desc[i].is_igd = 1; desc[i].is_igd = 1;
n_igd++; n_igd++;
if(lanaddr)
strncpy(lanaddr, myLanAddr, lanaddrlen);
} }
} }
} }

View file

@ -1,15 +1,16 @@
/* $Id: miniupnpc.h,v 1.34 2014/01/31 13:18:25 nanard Exp $ */ /* $Id: miniupnpc.h,v 1.44 2015/07/23 20:40:10 nanard Exp $ */
/* Project: miniupnp /* Project: miniupnp
* http://miniupnp.free.fr/ * http://miniupnp.free.fr/
* Author: Thomas Bernard * Author: Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed * This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */ * in the LICENCE file provided within this distribution */
#ifndef MINIUPNPC_H_INCLUDED #ifndef MINIUPNPC_H_INCLUDED
#define MINIUPNPC_H_INCLUDED #define MINIUPNPC_H_INCLUDED
#include "declspec.h" #include "miniupnpc_declspec.h"
#include "igd_desc_parse.h" #include "igd_desc_parse.h"
#include "upnpdev.h"
/* error codes : */ /* error codes : */
#define UPNPDISCOVER_SUCCESS (0) #define UPNPDISCOVER_SUCCESS (0)
@ -19,7 +20,13 @@
/* versions : */ /* versions : */
#define MINIUPNPC_VERSION "1.9" #define MINIUPNPC_VERSION "1.9"
#define MINIUPNPC_API_VERSION 10 #define MINIUPNPC_API_VERSION 15
/* Source port:
Using "1" as an alias for 1900 for backwards compatability
(presuming one would have used that for the "sameport" parameter) */
#define UPNP_LOCAL_PORT_ANY 0
#define UPNP_LOCAL_PORT_SAME 1
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -33,14 +40,6 @@ simpleUPnPcommand(int, const char *, const char *,
const char *, struct UPNParg *, const char *, struct UPNParg *,
int *); int *);
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
unsigned int scope_id;
char buffer[2];
};
/* upnpDiscover() /* upnpDiscover()
* discover UPnP devices on the network. * discover UPnP devices on the network.
* The discovered devices are returned as a chained list. * The discovered devices are returned as a chained list.
@ -52,16 +51,38 @@ struct UPNPDev {
* is NULL. * is NULL.
* If multicastif is not NULL, it will be used instead of the default * If multicastif is not NULL, it will be used instead of the default
* multicast interface for sending SSDP discover packets. * multicast interface for sending SSDP discover packets.
* If sameport is not null, SSDP packets will be sent from the source port * If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent
* 1900 (same as destination port) otherwise system assign a source port. */ * from the source port 1900 (same as destination port), if set to
* UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will
* be attempted as the source port.
* "searchalltypes" parameter is useful when searching several types,
* if 0, the discovery will stop with the first type returning results.
* TTL should default to 2. */
MINIUPNP_LIBSPEC struct UPNPDev * MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscover(int delay, const char * multicastif, upnpDiscover(int delay, const char * multicastif,
const char * minissdpdsock, int sameport, const char * minissdpdsock, int localport,
int ipv6, int ipv6, unsigned char ttl,
int * error); int * error);
/* freeUPNPDevlist()
* free list returned by upnpDiscover() */ MINIUPNP_LIBSPEC struct UPNPDev *
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); upnpDiscoverAll(int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevice(const char * device, int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl,
int * error);
MINIUPNP_LIBSPEC struct UPNPDev *
upnpDiscoverDevices(const char * const deviceTypes[],
int delay, const char * multicastif,
const char * minissdpdsock, int localport,
int ipv6, unsigned char ttl,
int * error,
int searchalltypes);
/* parserootdesc() : /* parserootdesc() :
* parse root XML description of a UPnP device and fill the IGDdatas * parse root XML description of a UPnP device and fill the IGDdatas
@ -102,6 +123,7 @@ UPNP_GetValidIGD(struct UPNPDev * devlist,
/* UPNP_GetIGDFromUrl() /* UPNP_GetIGDFromUrl()
* Used when skipping the discovery process. * Used when skipping the discovery process.
* When succeding, urls, data, and lanaddr arguments are set.
* return value : * return value :
* 0 - Not ok * 0 - Not ok
* 1 - OK */ * 1 - OK */

View file

@ -1,5 +1,5 @@
#ifndef DECLSPEC_H_INCLUDED #ifndef MINIUPNPC_DECLSPEC_H_INCLUDED
#define DECLSPEC_H_INCLUDED #define MINIUPNPC_DECLSPEC_H_INCLUDED
#if defined(_WIN32) && !defined(MINIUPNP_STATICLIB) #if defined(_WIN32) && !defined(MINIUPNP_STATICLIB)
/* for windows dll */ /* for windows dll */
@ -17,5 +17,5 @@
#endif #endif
#endif #endif
#endif #endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */

View file

@ -42,6 +42,7 @@ typedef struct {
struct UPNPUrls urls; struct UPNPUrls urls;
struct IGDdatas data; struct IGDdatas data;
unsigned int discoverdelay; /* value passed to upnpDiscover() */ unsigned int discoverdelay; /* value passed to upnpDiscover() */
unsigned int localport; /* value passed to upnpDiscover() */
char lanaddr[40]; /* our ip address on the LAN */ char lanaddr[40]; /* our ip address on the LAN */
char * multicastif; char * multicastif;
char * minissdpdsocket; char * minissdpdsocket;
@ -54,21 +55,62 @@ static PyMemberDef UPnP_members[] = {
{"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay), {"discoverdelay", T_UINT, offsetof(UPnPObject, discoverdelay),
0/*READWRITE*/, "value in ms used to wait for SSDP responses" 0/*READWRITE*/, "value in ms used to wait for SSDP responses"
}, },
{"localport", T_UINT, offsetof(UPnPObject, localport),
0/*READWRITE*/,
"If localport is set to UPNP_LOCAL_PORT_SAME(1) "
"SSDP packets will be sent from the source port "
"1900 (same as destination port), if set to "
"UPNP_LOCAL_PORT_ANY(0) system assign a source "
"port, any other value will be attempted as the "
"source port"
},
/* T_STRING is allways readonly :( */ /* T_STRING is allways readonly :( */
{"multicastif", T_STRING, offsetof(UPnPObject, multicastif), {"multicastif", T_STRING, offsetof(UPnPObject, multicastif),
0, "IP of the network interface to be used for multicast operations" 0, "IP of the network interface to be used for multicast operations"
}, },
{"minissdpdsocket", T_STRING, offsetof(UPnPObject, multicastif), {"minissdpdsocket", T_STRING, offsetof(UPnPObject, minissdpdsocket),
0, "path of the MiniSSDPd unix socket" 0, "path of the MiniSSDPd unix socket"
}, },
{NULL} {NULL}
}; };
static int UPnP_init(UPnPObject *self, PyObject *args, PyObject *kwds)
{
char* multicastif = NULL;
char* minissdpdsocket = NULL;
static char *kwlist[] = {
"multicastif", "minissdpdsocket", "discoverdelay",
"localport", NULL
};
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|zzII", kwlist,
&multicastif,
&minissdpdsocket,
&self->discoverdelay,
&self->localport))
return -1;
if(self->localport>1 &&
(self->localport>65534||self->localport<1024)) {
PyErr_SetString(PyExc_Exception, "Invalid localport value");
return -1;
}
if(multicastif)
self->multicastif = strdup(multicastif);
if(minissdpdsocket)
self->minissdpdsocket = strdup(minissdpdsocket);
return 0;
}
static void static void
UPnPObject_dealloc(UPnPObject *self) UPnPObject_dealloc(UPnPObject *self)
{ {
freeUPNPDevlist(self->devlist); freeUPNPDevlist(self->devlist);
FreeUPNPUrls(&self->urls); FreeUPNPUrls(&self->urls);
free(self->multicastif);
free(self->minissdpdsocket);
Py_TYPE(self)->tp_free((PyObject*)self); Py_TYPE(self)->tp_free((PyObject*)self);
} }
@ -85,10 +127,11 @@ UPnP_discover(UPnPObject *self)
} }
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/, self->devlist = upnpDiscover((int)self->discoverdelay/*timeout in ms*/,
0/* multicast if*/, self->multicastif,
0/*minissdpd socket*/, self->minissdpdsocket,
0/*sameport flag*/, (int)self->localport,
0/*ip v6*/, 0/*ip v6*/,
2/* TTL */,
0/*error */); 0/*error */);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
/* Py_RETURN_NONE ??? */ /* Py_RETURN_NONE ??? */
@ -126,7 +169,11 @@ Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF, i = UPNP_GetTotalBytesSent(self->urls.controlURL_CIF,
self->data.CIF.servicetype); self->data.CIF.servicetype);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", i); return Py_BuildValue("I", i);
#else
return Py_BuildValue("i", (int)i);
#endif
} }
static PyObject * static PyObject *
@ -137,7 +184,11 @@ Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF, i = UPNP_GetTotalBytesReceived(self->urls.controlURL_CIF,
self->data.CIF.servicetype); self->data.CIF.servicetype);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", i); return Py_BuildValue("I", i);
#else
return Py_BuildValue("i", (int)i);
#endif
} }
static PyObject * static PyObject *
@ -148,7 +199,11 @@ Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF, i = UPNP_GetTotalPacketsSent(self->urls.controlURL_CIF,
self->data.CIF.servicetype); self->data.CIF.servicetype);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", i); return Py_BuildValue("I", i);
#else
return Py_BuildValue("i", (int)i);
#endif
} }
static PyObject * static PyObject *
@ -159,7 +214,11 @@ Py_BEGIN_ALLOW_THREADS
i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF, i = UPNP_GetTotalPacketsReceived(self->urls.controlURL_CIF,
self->data.CIF.servicetype); self->data.CIF.servicetype);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", i); return Py_BuildValue("I", i);
#else
return Py_BuildValue("i", (int)i);
#endif
} }
static PyObject * static PyObject *
@ -176,7 +235,11 @@ Py_BEGIN_ALLOW_THREADS
status, &uptime, lastconnerror); status, &uptime, lastconnerror);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) { if(r==UPNPCOMMAND_SUCCESS) {
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror); return Py_BuildValue("(s,I,s)", status, uptime, lastconnerror);
#else
return Py_BuildValue("(s,i,s)", status, (int)uptime, lastconnerror);
#endif
} else { } else {
/* TODO: have our own exception type ! */ /* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r)); PyErr_SetString(PyExc_Exception, strupnperror(r));
@ -369,7 +432,11 @@ Py_BEGIN_ALLOW_THREADS
&n); &n);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if(r==UPNPCOMMAND_SUCCESS) { if(r==UPNPCOMMAND_SUCCESS) {
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("I", n); return Py_BuildValue("I", n);
#else
return Py_BuildValue("i", (int)n);
#endif
} else { } else {
/* TODO: have our own exception type ! */ /* TODO: have our own exception type ! */
PyErr_SetString(PyExc_Exception, strupnperror(r)); PyErr_SetString(PyExc_Exception, strupnperror(r));
@ -454,9 +521,15 @@ Py_END_ALLOW_THREADS
ePort = (unsigned short)atoi(extPort); ePort = (unsigned short)atoi(extPort);
iPort = (unsigned short)atoi(intPort); iPort = (unsigned short)atoi(intPort);
dur = (unsigned int)strtoul(duration, 0, 0); dur = (unsigned int)strtoul(duration, 0, 0);
#if (PY_MAJOR_VERSION >= 3) || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION > 3)
return Py_BuildValue("(H,s,(s,H),s,s,s,I)", return Py_BuildValue("(H,s,(s,H),s,s,s,I)",
ePort, protocol, intClient, iPort, ePort, protocol, intClient, iPort,
desc, enabled, rHost, dur); desc, enabled, rHost, dur);
#else
return Py_BuildValue("(i,s,(s,i),s,s,s,i)",
(int)ePort, protocol, intClient, (int)iPort,
desc, enabled, rHost, (int)dur);
#endif
} }
else else
{ {
@ -554,7 +627,7 @@ static PyTypeObject UPnPType = {
0, /* tp_descr_get */ 0, /* tp_descr_get */
0, /* tp_descr_set */ 0, /* tp_descr_set */
0, /* tp_dictoffset */ 0, /* tp_dictoffset */
0,/*(initproc)UPnP_init,*/ /* tp_init */ (initproc)UPnP_init, /* tp_init */
0, /* tp_alloc */ 0, /* tp_alloc */
#ifndef _WIN32 #ifndef _WIN32
PyType_GenericNew,/*UPnP_new,*/ /* tp_new */ PyType_GenericNew,/*UPnP_new,*/ /* tp_new */

View file

@ -4,4 +4,12 @@
#define OS_STRING "${CMAKE_SYSTEM_NAME}" #define OS_STRING "${CMAKE_SYSTEM_NAME}"
#define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}" #define MINIUPNPC_VERSION_STRING "${MINIUPNPC_VERSION}"
#if 0
/* according to "UPnP Device Architecture 1.0" */
#define UPNP_VERSION_STRING "UPnP/1.0"
#else
/* according to "UPnP Device Architecture 1.1" */
#define UPNP_VERSION_STRING "UPnP/1.1"
#endif
#endif #endif

View file

@ -1,8 +1,8 @@
/* $Id: miniupnpcstrings.h.in,v 1.4 2011/01/04 11:41:53 nanard Exp $ */ /* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */
/* Project: miniupnp /* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard * Author: Thomas Bernard
* Copyright (c) 2005-2011 Thomas Bernard * Copyright (c) 2005-2014 Thomas Bernard
* This software is subjects to the conditions detailed * This software is subjects to the conditions detailed
* in the LICENCE file provided within this distribution */ * in the LICENCE file provided within this distribution */
#ifndef MINIUPNPCSTRINGS_H_INCLUDED #ifndef MINIUPNPCSTRINGS_H_INCLUDED
@ -11,5 +11,13 @@
#define OS_STRING "OS/version" #define OS_STRING "OS/version"
#define MINIUPNPC_VERSION_STRING "version" #define MINIUPNPC_VERSION_STRING "version"
#if 0
/* according to "UPnP Device Architecture 1.0" */
#define UPNP_VERSION_STRING "UPnP/1.0"
#else
/* according to "UPnP Device Architecture 1.1" */
#define UPNP_VERSION_STRING "UPnP/1.1"
#endif
#endif #endif

View file

@ -1,8 +1,8 @@
/* $Id: miniwget.c,v 1.61 2014/02/05 17:27:48 nanard Exp $ */ /* $Id: miniwget.c,v 1.70 2015/07/15 12:41:13 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Website : http://miniupnp.free.fr/ * Website : http://miniupnp.free.fr/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
@ -38,6 +38,7 @@
#include <net/if.h> #include <net/if.h>
#include <netdb.h> #include <netdb.h>
#define closesocket close #define closesocket close
#include <strings.h>
#endif /* #else _WIN32 */ #endif /* #else _WIN32 */
#ifdef __GNU__ #ifdef __GNU__
#define MAXHOSTNAMELEN 64 #define MAXHOSTNAMELEN 64
@ -84,7 +85,24 @@ getHTTPResponse(int s, int * size)
unsigned int chunksize_buf_index; unsigned int chunksize_buf_index;
header_buf = malloc(header_buf_len); header_buf = malloc(header_buf_len);
if(header_buf == NULL)
{
#ifdef DEBUG
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
#endif /* DEBUG */
*size = -1;
return NULL;
}
content_buf = malloc(content_buf_len); content_buf = malloc(content_buf_len);
if(content_buf == NULL)
{
free(header_buf);
#ifdef DEBUG
fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse");
#endif /* DEBUG */
*size = -1;
return NULL;
}
chunksize_buf[0] = '\0'; chunksize_buf[0] = '\0';
chunksize_buf_index = 0; chunksize_buf_index = 0;
@ -97,7 +115,15 @@ getHTTPResponse(int s, int * size)
int colon=0; int colon=0;
int valuestart=0; int valuestart=0;
if(header_buf_used + n > header_buf_len) { if(header_buf_used + n > header_buf_len) {
header_buf = realloc(header_buf, header_buf_used + n); char * tmp = realloc(header_buf, header_buf_used + n);
if(tmp == NULL) {
/* memory allocation error */
free(header_buf);
free(content_buf);
*size = -1;
return NULL;
}
header_buf = tmp;
header_buf_len = header_buf_used + n; header_buf_len = header_buf_used + n;
} }
memcpy(header_buf + header_buf_used, buf, n); memcpy(header_buf + header_buf_used, buf, n);
@ -232,13 +258,21 @@ getHTTPResponse(int s, int * size)
bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i);
if((content_buf_used + bytestocopy) > content_buf_len) if((content_buf_used + bytestocopy) > content_buf_len)
{ {
char * tmp;
if(content_length >= (int)(content_buf_used + bytestocopy)) { if(content_length >= (int)(content_buf_used + bytestocopy)) {
content_buf_len = content_length; content_buf_len = content_length;
} else { } else {
content_buf_len = content_buf_used + bytestocopy; content_buf_len = content_buf_used + bytestocopy;
} }
content_buf = (char *)realloc((void *)content_buf, tmp = realloc(content_buf, content_buf_len);
content_buf_len); if(tmp == NULL) {
/* memory allocation error */
free(content_buf);
free(header_buf);
*size = -1;
return NULL;
}
content_buf = tmp;
} }
memcpy(content_buf + content_buf_used, buf + i, bytestocopy); memcpy(content_buf + content_buf_used, buf + i, bytestocopy);
content_buf_used += bytestocopy; content_buf_used += bytestocopy;
@ -256,13 +290,21 @@ getHTTPResponse(int s, int * size)
} }
if(content_buf_used + n > content_buf_len) if(content_buf_used + n > content_buf_len)
{ {
char * tmp;
if(content_length >= (int)(content_buf_used + n)) { if(content_length >= (int)(content_buf_used + n)) {
content_buf_len = content_length; content_buf_len = content_length;
} else { } else {
content_buf_len = content_buf_used + n; content_buf_len = content_buf_used + n;
} }
content_buf = (char *)realloc((void *)content_buf, tmp = realloc(content_buf, content_buf_len);
content_buf_len); if(tmp == NULL) {
/* memory allocation error */
free(content_buf);
free(header_buf);
*size = -1;
return NULL;
}
content_buf = tmp;
} }
memcpy(content_buf + content_buf_used, buf, n); memcpy(content_buf + content_buf_used, buf, n);
content_buf_used += n; content_buf_used += n;
@ -368,10 +410,15 @@ miniwget3(const char * host,
"GET %s HTTP/%s\r\n" "GET %s HTTP/%s\r\n"
"Host: %s:%d\r\n" "Host: %s:%d\r\n"
"Connection: Close\r\n" "Connection: Close\r\n"
"User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
"\r\n", "\r\n",
path, httpversion, host, port); path, httpversion, host, port);
if ((unsigned int)len >= sizeof(buf))
{
closesocket(s);
return NULL;
}
sent = 0; sent = 0;
/* sending the HTTP request */ /* sending the HTTP request */
while(sent < len) while(sent < len)

View file

@ -1,14 +1,14 @@
/* $Id: miniwget.h,v 1.7 2012/06/23 22:35:59 nanard Exp $ */ /* $Id: miniwget.h,v 1.7 2012/06/23 22:35:59 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
#ifndef MINIWGET_H_INCLUDED #ifndef MINIWGET_H_INCLUDED
#define MINIWGET_H_INCLUDED #define MINIWGET_H_INCLUDED
#include "declspec.h" #include "miniupnpc_declspec.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View file

@ -1,4 +1,4 @@
/* $Id: minixmlvalid.c,v 1.6 2012/05/01 16:24:07 nanard Exp $ */ /* $Id: minixmlvalid.c,v 1.7 2015/07/15 12:41:15 nanard Exp $ */
/* MiniUPnP Project /* MiniUPnP Project
* http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ * http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
* minixmlvalid.c : * minixmlvalid.c :
@ -128,6 +128,11 @@ int testxmlparser(const char * xml, int size)
struct xmlparser parser; struct xmlparser parser;
evtlist.n = 0; evtlist.n = 0;
evtlist.events = malloc(sizeof(struct event)*100); evtlist.events = malloc(sizeof(struct event)*100);
if(evtlist.events == NULL)
{
fprintf(stderr, "Memory allocation error.\n");
return -1;
}
memset(&parser, 0, sizeof(parser)); memset(&parser, 0, sizeof(parser));
parser.xmlstart = xml; parser.xmlstart = xml;
parser.xmlsize = size; parser.xmlsize = size;

View file

@ -160,6 +160,10 @@
RelativePath="..\minisoap.c" RelativePath="..\minisoap.c"
> >
</File> </File>
<File
RelativePath="..\minissdpc.c"
>
</File>
<File <File
RelativePath="..\miniupnpc.c" RelativePath="..\miniupnpc.c"
> >
@ -184,6 +188,10 @@
RelativePath="..\upnpcommands.c" RelativePath="..\upnpcommands.c"
> >
</File> </File>
<File
RelativePath="..\upnpdev.c"
>
</File>
<File <File
RelativePath="..\upnperrors.c" RelativePath="..\upnperrors.c"
> >
@ -198,10 +206,6 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd" Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
> >
<File
RelativePath="..\bsdqueue.h"
>
</File>
<File <File
RelativePath="..\connecthostport.h" RelativePath="..\connecthostport.h"
> >
@ -218,6 +222,10 @@
RelativePath="..\minisoap.h" RelativePath="..\minisoap.h"
> >
</File> </File>
<File
RelativePath="..\minissdpc.h"
>
</File>
<File <File
RelativePath="..\miniupnpc.h" RelativePath="..\miniupnpc.h"
> >
@ -250,6 +258,10 @@
RelativePath="..\upnpcommands.h" RelativePath="..\upnpcommands.h"
> >
</File> </File>
<File
RelativePath="..\upnpdev.h"
>
</File>
<File <File
RelativePath="..\upnperrors.h" RelativePath="..\upnperrors.h"
> >

View file

@ -1,11 +1,14 @@
/* $Id: portlistingparse.c,v 1.6 2012/05/29 10:26:51 nanard Exp $ */ /* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011 Thomas Bernard * (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed * This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */ * in the LICENCE file provided within the distribution */
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef DEBUG
#include <stdio.h>
#endif /* DEBUG */
#include "portlistingparse.h" #include "portlistingparse.h"
#include "minixml.h" #include "minixml.h"
@ -62,7 +65,17 @@ startelt(void * d, const char * name, int l)
{ {
struct PortMapping * pm; struct PortMapping * pm;
pm = calloc(1, sizeof(struct PortMapping)); pm = calloc(1, sizeof(struct PortMapping));
LIST_INSERT_HEAD( &(pdata->head), pm, entries); if(pm == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"startelt");
#endif /* DEBUG */
return;
}
pm->l_next = pdata->l_head; /* insert in list */
pdata->l_head = pm;
} }
} }
@ -82,7 +95,7 @@ data(void * d, const char * data, int l)
{ {
struct PortMapping * pm; struct PortMapping * pm;
struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; struct PortMappingParserData * pdata = (struct PortMappingParserData *)d;
pm = pdata->head.lh_first; pm = pdata->l_head;
if(!pm) if(!pm)
return; return;
if(l > 63) if(l > 63)
@ -134,7 +147,6 @@ ParsePortListing(const char * buffer, int bufsize,
struct xmlparser parser; struct xmlparser parser;
memset(pdata, 0, sizeof(struct PortMappingParserData)); memset(pdata, 0, sizeof(struct PortMappingParserData));
LIST_INIT(&(pdata->head));
/* init xmlparser */ /* init xmlparser */
parser.xmlstart = buffer; parser.xmlstart = buffer;
parser.xmlsize = bufsize; parser.xmlsize = bufsize;
@ -150,9 +162,10 @@ void
FreePortListing(struct PortMappingParserData * pdata) FreePortListing(struct PortMappingParserData * pdata)
{ {
struct PortMapping * pm; struct PortMapping * pm;
while((pm = pdata->head.lh_first) != NULL) while((pm = pdata->l_head) != NULL)
{ {
LIST_REMOVE(pm, entries); /* remove from list */
pdata->l_head = pm->l_next;
free(pm); free(pm);
} }
} }

View file

@ -1,22 +1,16 @@
/* $Id: portlistingparse.h,v 1.5 2012/01/21 13:30:33 nanard Exp $ */ /* $Id: portlistingparse.h,v 1.10 2014/11/01 10:37:32 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011-2012 Thomas Bernard * (c) 2011-2015 Thomas Bernard
* This software is subject to the conditions detailed * This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */ * in the LICENCE file provided within the distribution */
#ifndef PORTLISTINGPARSE_H_INCLUDED #ifndef PORTLISTINGPARSE_H_INCLUDED
#define PORTLISTINGPARSE_H_INCLUDED #define PORTLISTINGPARSE_H_INCLUDED
#include "declspec.h" #include "miniupnpc_declspec.h"
/* for the definition of UNSIGNED_INTEGER */ /* for the definition of UNSIGNED_INTEGER */
#include "miniupnpctypes.h" #include "miniupnpctypes.h"
#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__)
#include "bsdqueue.h"
#else
#include <sys/queue.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -41,7 +35,7 @@ typedef enum { PortMappingEltNone,
NewLeaseTime } portMappingElt; NewLeaseTime } portMappingElt;
struct PortMapping { struct PortMapping {
LIST_ENTRY(PortMapping) entries; struct PortMapping * l_next; /* list next element */
UNSIGNED_INTEGER leaseTime; UNSIGNED_INTEGER leaseTime;
unsigned short externalPort; unsigned short externalPort;
unsigned short internalPort; unsigned short internalPort;
@ -53,7 +47,7 @@ struct PortMapping {
}; };
struct PortMappingParserData { struct PortMappingParserData {
LIST_HEAD(portmappinglisthead, PortMapping) head; struct PortMapping * l_head; /* list head */
portMappingElt curelt; portMappingElt curelt;
}; };

View file

@ -1,4 +1,5 @@
#! /usr/bin/python #! /usr/bin/python
# vim: tabstop=2 shiftwidth=2 expandtab
# MiniUPnP project # MiniUPnP project
# Author : Thomas Bernard # Author : Thomas Bernard
# This Sample code is public domain. # This Sample code is public domain.
@ -8,14 +9,43 @@
import miniupnpc import miniupnpc
import sys import sys
# create the object try:
u = miniupnpc.UPnP() import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-m', '--multicastif')
parser.add_argument('-p', '--minissdpdsocket')
parser.add_argument('-d', '--discoverdelay', type=int, default=200)
parser.add_argument('-z', '--localport', type=int, default=0)
# create the object
u = miniupnpc.UPnP(**vars(parser.parse_args()))
except:
print 'argparse not available'
i = 1
multicastif = None
minissdpdsocket = None
discoverdelay = 200
localport = 0
while i < len(sys.argv):
print sys.argv[i]
if sys.argv[i] == '-m' or sys.argv[i] == '--multicastif':
multicastif = sys.argv[i+1]
elif sys.argv[i] == '-p' or sys.argv[i] == '--minissdpdsocket':
minissdpdsocket = sys.argv[i+1]
elif sys.argv[i] == '-d' or sys.argv[i] == '--discoverdelay':
discoverdelay = int(sys.argv[i+1])
elif sys.argv[i] == '-z' or sys.argv[i] == '--localport':
localport = int(sys.argv[i+1])
else:
raise Exception('invalid argument %s' % sys.argv[i])
i += 2
# create the object
u = miniupnpc.UPnP(multicastif, minissdpdsocket, discoverdelay, localport)
print 'inital(default) values :' print 'inital(default) values :'
print ' discoverdelay', u.discoverdelay print ' discoverdelay', u.discoverdelay
print ' lanaddr', u.lanaddr print ' lanaddr', u.lanaddr
print ' multicastif', u.multicastif print ' multicastif', u.multicastif
print ' minissdpdsocket', u.minissdpdsocket print ' minissdpdsocket', u.minissdpdsocket
u.discoverdelay = 200;
#u.minissdpdsocket = '../minissdpd/minissdpd.sock' #u.minissdpdsocket = '../minissdpd/minissdpd.sock'
# discovery process, it usualy takes several seconds (2 seconds or more) # discovery process, it usualy takes several seconds (2 seconds or more)
print 'Discovering... delay=%ums' % u.discoverdelay print 'Discovering... delay=%ums' % u.discoverdelay
@ -30,6 +60,8 @@ except Exception, e:
print 'local ip address :', u.lanaddr print 'local ip address :', u.lanaddr
print 'external ip address :', u.externalipaddress() print 'external ip address :', u.externalipaddress()
print u.statusinfo(), u.connectiontype() print u.statusinfo(), u.connectiontype()
print 'total bytes : sent', u.totalbytesent(), 'received', u.totalbytereceived()
print 'total packets : sent', u.totalpacketsent(), 'received', u.totalpacketreceived()
#print u.addportmapping(64000, 'TCP', #print u.addportmapping(64000, 'TCP',
# '192.168.1.166', 63000, 'port mapping test', '') # '192.168.1.166', 63000, 'port mapping test', '')
@ -49,4 +81,8 @@ while True:
i = i + 1 i = i + 1
print u.getspecificportmapping(port, proto) print u.getspecificportmapping(port, proto)
try:
print u.getportmappingnumberofentries()
except Exception, e:
print 'GetPortMappingNumberOfEntries() is not supported :', e

52
external/miniupnpc/pymoduletest3.py vendored Executable file
View file

@ -0,0 +1,52 @@
#! /usr/bin/python3
# MiniUPnP project
# Author : Thomas Bernard
# This Sample code is public domain.
# website : http://miniupnp.tuxfamily.org/
# import the python miniupnpc module
import miniupnpc
import sys
# create the object
u = miniupnpc.UPnP()
print('inital(default) values :')
print(' discoverdelay', u.discoverdelay)
print(' lanaddr', u.lanaddr)
print(' multicastif', u.multicastif)
print(' minissdpdsocket', u.minissdpdsocket)
u.discoverdelay = 200;
#u.minissdpdsocket = '../minissdpd/minissdpd.sock'
# discovery process, it usualy takes several seconds (2 seconds or more)
print('Discovering... delay=%ums' % u.discoverdelay)
print(u.discover(), 'device(s) detected')
# select an igd
try:
u.selectigd()
except Exception as e:
print('Exception :', e)
sys.exit(1)
# display information about the IGD and the internet connection
print('local ip address :', u.lanaddr)
print('external ip address :', u.externalipaddress())
print(u.statusinfo(), u.connectiontype())
#print u.addportmapping(64000, 'TCP',
# '192.168.1.166', 63000, 'port mapping test', '')
#print u.deleteportmapping(64000, 'TCP')
port = 0
proto = 'UDP'
# list the redirections :
i = 0
while True:
p = u.getgenericportmapping(i)
if p==None:
break
print(i, p)
(port, proto, (ihost,iport), desc, c, d, e) = p
#print port, desc
i = i + 1
print(u.getspecificportmapping(port, proto))

View file

@ -1,16 +1,17 @@
/* $Id: receivedata.c,v 1.4 2012/06/23 22:34:47 nanard Exp $ */ /* $Id: receivedata.c,v 1.7 2015/11/09 21:51:41 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Website : http://miniupnp.free.fr/ * Website : http://miniupnp.free.fr/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2011-2012 Thomas Bernard * Copyright (c) 2011-2014 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#else #else /* _WIN32 */
#include <unistd.h> #include <unistd.h>
#if defined(__amigaos__) && !defined(__amigaos4__) #if defined(__amigaos__) && !defined(__amigaos4__)
#define socklen_t int #define socklen_t int
@ -21,10 +22,10 @@
#include <netinet/in.h> #include <netinet/in.h>
#if !defined(__amigaos__) && !defined(__amigaos4__) #if !defined(__amigaos__) && !defined(__amigaos4__)
#include <poll.h> #include <poll.h>
#endif #endif /* !defined(__amigaos__) && !defined(__amigaos4__) */
#include <errno.h> #include <errno.h>
#define MINIUPNPC_IGNORE_EINTR #define MINIUPNPC_IGNORE_EINTR
#endif #endif /* _WIN32 */
#ifdef _WIN32 #ifdef _WIN32
#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); #define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError());
@ -39,23 +40,23 @@ receivedata(int socket,
char * data, int length, char * data, int length,
int timeout, unsigned int * scope_id) int timeout, unsigned int * scope_id)
{ {
#if MINIUPNPC_GET_SRC_ADDR #ifdef MINIUPNPC_GET_SRC_ADDR
struct sockaddr_storage src_addr; struct sockaddr_storage src_addr;
socklen_t src_addr_len = sizeof(src_addr); socklen_t src_addr_len = sizeof(src_addr);
#endif #endif /* MINIUPNPC_GET_SRC_ADDR */
int n; int n;
#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) #if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__)
/* using poll */ /* using poll */
struct pollfd fds[1]; /* for the poll */ struct pollfd fds[1]; /* for the poll */
#ifdef MINIUPNPC_IGNORE_EINTR #ifdef MINIUPNPC_IGNORE_EINTR
do { do {
#endif #endif /* MINIUPNPC_IGNORE_EINTR */
fds[0].fd = socket; fds[0].fd = socket;
fds[0].events = POLLIN; fds[0].events = POLLIN;
n = poll(fds, 1, timeout); n = poll(fds, 1, timeout);
#ifdef MINIUPNPC_IGNORE_EINTR #ifdef MINIUPNPC_IGNORE_EINTR
} while(n < 0 && errno == EINTR); } while(n < 0 && errno == EINTR);
#endif #endif /* MINIUPNPC_IGNORE_EINTR */
if(n < 0) { if(n < 0) {
PRINT_SOCKET_ERROR("poll"); PRINT_SOCKET_ERROR("poll");
return -1; return -1;
@ -63,7 +64,7 @@ receivedata(int socket,
/* timeout */ /* timeout */
return 0; return 0;
} }
#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ #else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
/* using select under _WIN32 and amigaos */ /* using select under _WIN32 and amigaos */
fd_set socketSet; fd_set socketSet;
TIMEVAL timeval; TIMEVAL timeval;
@ -78,27 +79,27 @@ receivedata(int socket,
} else if(n == 0) { } else if(n == 0) {
return 0; return 0;
} }
#endif #endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */
#if MINIUPNPC_GET_SRC_ADDR #ifdef MINIUPNPC_GET_SRC_ADDR
memset(&src_addr, 0, sizeof(src_addr));
n = recvfrom(socket, data, length, 0, n = recvfrom(socket, data, length, 0,
(struct sockaddr *)&src_addr, &src_addr_len); (struct sockaddr *)&src_addr, &src_addr_len);
#else #else /* MINIUPNPC_GET_SRC_ADDR */
n = recv(socket, data, length, 0); n = recv(socket, data, length, 0);
#endif #endif /* MINIUPNPC_GET_SRC_ADDR */
if(n<0) { if(n<0) {
PRINT_SOCKET_ERROR("recv"); PRINT_SOCKET_ERROR("recv");
} }
#if MINIUPNPC_GET_SRC_ADDR #ifdef MINIUPNPC_GET_SRC_ADDR
if (src_addr.ss_family == AF_INET6) { if (src_addr.ss_family == AF_INET6) {
const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr; const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr;
#ifdef DEBUG #ifdef DEBUG
printf("scope_id=%u\n", src_addr6->sin6_scope_id); printf("scope_id=%u\n", src_addr6->sin6_scope_id);
#endif #endif /* DEBUG */
if(scope_id) if(scope_id)
*scope_id = src_addr6->sin6_scope_id; *scope_id = src_addr6->sin6_scope_id;
} }
#endif #endif /* MINIUPNPC_GET_SRC_ADDR */
return n; return n;
} }

6
external/miniupnpc/setup.py vendored Normal file → Executable file
View file

@ -1,4 +1,5 @@
#! /usr/bin/python #! /usr/bin/python
# vim: tabstop=8 shiftwidth=8 expandtab
# $Id: setup.py,v 1.9 2012/05/23 08:50:10 nanard Exp $ # $Id: setup.py,v 1.9 2012/05/23 08:50:10 nanard Exp $
# the MiniUPnP Project (c) 2007-2014 Thomas Bernard # the MiniUPnP Project (c) 2007-2014 Thomas Bernard
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ # http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
@ -6,7 +7,10 @@
# python script to build the miniupnpc module under unix # python script to build the miniupnpc module under unix
# #
# replace libminiupnpc.a by libminiupnpc.so for shared library usage # replace libminiupnpc.a by libminiupnpc.so for shared library usage
from distutils.core import setup, Extension try:
from setuptools import setup, Extension
except ImportError:
from distutils.core import setup, Extension
from distutils import sysconfig from distutils import sysconfig
sysconfig.get_config_vars()["OPT"] = '' sysconfig.get_config_vars()["OPT"] = ''
sysconfig.get_config_vars()["CFLAGS"] = '' sysconfig.get_config_vars()["CFLAGS"] = ''

6
external/miniupnpc/setupmingw32.py vendored Normal file → Executable file
View file

@ -1,11 +1,15 @@
#! /usr/bin/python #! /usr/bin/python
# vim: tabstop=8 shiftwidth=8 expandtab
# $Id: setupmingw32.py,v 1.8 2012/05/23 08:50:10 nanard Exp $ # $Id: setupmingw32.py,v 1.8 2012/05/23 08:50:10 nanard Exp $
# the MiniUPnP Project (c) 2007-2014 Thomas Bernard # the MiniUPnP Project (c) 2007-2014 Thomas Bernard
# http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ # http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/
# #
# python script to build the miniupnpc module under windows (using mingw32) # python script to build the miniupnpc module under windows (using mingw32)
# #
from distutils.core import setup, Extension try:
from setuptools import setup, Extension
except ImportError:
from distutils.core import setup, Extension
from distutils import sysconfig from distutils import sysconfig
sysconfig.get_config_vars()["OPT"] = '' sysconfig.get_config_vars()["OPT"] = ''
sysconfig.get_config_vars()["CFLAGS"] = '' sysconfig.get_config_vars()["CFLAGS"] = ''

View file

@ -0,0 +1,14 @@
# values for linksys_WAG200G_desc.xml
CIF:
servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
controlurl = /upnp/control/WANCommonIFC1
eventsuburl = /upnp/event/WANCommonIFC1
scpdurl = /cmnicfg.xml
first:
servicetype = urn:schemas-upnp-org:service:WANPPPConnection:1
controlurl = /upnp/control/WANPPPConn1
eventsuburl = /upnp/event/WANPPPConn1
scpdurl = /pppcfg.xml

View file

@ -0,0 +1,110 @@
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>http://192.168.1.1:49152</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:1</deviceType>
<friendlyName>LINKSYS WAG200G Gateway</friendlyName>
<manufacturer>LINKSYS</manufacturer>
<manufacturerURL>http://www.linksys.com</manufacturerURL>
<modelDescription>LINKSYS WAG200G Gateway</modelDescription>
<modelName>Wireless-G ADSL Home Gateway</modelName>
<modelNumber>WAG200G</modelNumber>
<modelURL>http://www.linksys.com</modelURL>
<serialNumber>123456789</serialNumber>
<UDN>uuid:8ca2eb37-1dd2-11b2-86f1-001a709b5aa8</UDN>
<UPC>WAG200G</UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>
<serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId>
<controlURL>/upnp/control/L3Forwarding1</controlURL>
<eventSubURL>/upnp/event/L3Forwarding1</eventSubURL>
<SCPDURL>/l3frwd.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>
<friendlyName>WANDevice</friendlyName>
<manufacturer>LINKSYS</manufacturer>
<manufacturerURL>http://www.linksys.com/</manufacturerURL>
<modelDescription>Residential Gateway</modelDescription>
<modelName>Internet Connection Sharing</modelName>
<modelNumber>1</modelNumber>
<modelURL>http://www.linksys.com/</modelURL>
<serialNumber>0000001</serialNumber>
<UDN>uuid:8ca2eb36-1dd2-11b2-86f1-001a709b5aa8</UDN>
<UPC>WAG200G</UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>
<controlURL>/upnp/control/WANCommonIFC1</controlURL>
<eventSubURL>/upnp/event/WANCommonIFC1</eventSubURL>
<SCPDURL>/cmnicfg.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>
<friendlyName>WANConnectionDevice</friendlyName>
<manufacturer>LINKSYS</manufacturer>
<manufacturerURL>http://www.linksys.com/</manufacturerURL>
<modelDescription>Residential Gateway</modelDescription>
<modelName>Internet Connection Sharing</modelName>
<modelNumber>1</modelNumber>
<modelURL>http://www.linksys.com/</modelURL>
<serialNumber>0000001</serialNumber>
<UDN>uuid:8ca2eb37-1dd2-11b2-86f0-001a709b5aa8</UDN>
<UPC>WAG200G</UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANEthernetLinkConfig:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANEthLinkC1</serviceId>
<controlURL>/upnp/control/WANEthLinkC1</controlURL>
<eventSubURL>/upnp/event/WANEthLinkC1</eventSubURL>
<SCPDURL>/wanelcfg.xml</SCPDURL>
</service>
<service>
<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANPPPConn1</serviceId>
<controlURL>/upnp/control/WANPPPConn1</controlURL>
<eventSubURL>/upnp/event/WANPPPConn1</eventSubURL>
<SCPDURL>/pppcfg.xml</SCPDURL>
</service>
</serviceList>
</device>
</deviceList>
</device>
<device>
<deviceType>urn:schemas-upnp-org:device:LANDevice:1</deviceType>
<friendlyName>LANDevice</friendlyName>
<manufacturer>LINKSYS</manufacturer>
<manufacturerURL>http://www.linksys.com/</manufacturerURL>
<modelDescription>Residential Gateway</modelDescription>
<modelName>Residential Gateway</modelName>
<modelNumber>1</modelNumber>
<modelURL>http://www.linksys.com/</modelURL>
<serialNumber>0000001</serialNumber>
<UDN>uuid:8ca2eb36-1dd2-11b2-86f0-001a709b5aa
8</UDN>
<UPC>WAG200G</UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:LANHostConfigManagement:1</serviceType>
<serviceId>urn:upnp-org:serviceId:LANHostCfg1</serviceId>
<controlURL>/upnp/control/LANHostCfg1</controlURL>
<eventSubURL>/upnp/event/LANHostCfg1</eventSubURL>
<SCPDURL>/lanhostc.xml</SCPDURL>
</service>
</serviceList>
</device>
</deviceList>
<presentationURL>http://192.168.1.1/index.htm</presentationURL>
</device>
</root>

View file

@ -0,0 +1,20 @@
# values for new_LiveBox_desc.xml
CIF:
servicetype = urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1
controlurl = /87895a19/upnp/control/WANCommonIFC1
eventsuburl = /87895a19/upnp/control/WANCommonIFC1
scpdurl = /87895a19/gateicfgSCPD.xml
first:
servicetype = urn:schemas-upnp-org:service:WANPPPConnection:2
controlurl = /87895a19/upnp/control/WANIPConn1
eventsuburl = /87895a19/upnp/control/WANIPConn1
scpdurl = /87895a19/gateconnSCPD_PPP.xml
IPv6FC:
servicetype = urn:schemas-upnp-org:service:WANIPv6FirewallControl:1
controlurl = /87895a19/upnp/control/WANIPv6FwCtrl1
eventsuburl = /87895a19/upnp/control/WANIPv6FwCtrl1
scpdurl = /87895a19/wanipv6fwctrlSCPD.xml

View file

@ -0,0 +1,90 @@
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<pnpx:X_hardwareId xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11">VEN_0129&amp;DEV_0000&amp;SUBSYS_03&amp;REV_250417</pnpx:X_hardwareId>
<pnpx:X_compatibleId xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11">GenericUmPass</pnpx:X_compatibleId>
<pnpx:X_deviceCategory xmlns:pnpx="http://schemas.microsoft.com/windows/pnpx/2005/11">NetworkInfrastructure.Gateway</pnpx:X_deviceCategory>
<df:X_deviceCategory xmlns:df="http://schemas.microsoft.com/windows/2008/09/devicefoundation">Network.Gateway</df:X_deviceCategory>
<deviceType>urn:schemas-upnp-org:device:InternetGatewayDevice:2</deviceType>
<friendlyName>Orange Livebox</friendlyName>
<manufacturer>Sagemcom</manufacturer>
<manufacturerURL>http://www.sagemcom.com/</manufacturerURL>
<modelName>Residential Livebox,(DSL,WAN Ethernet)</modelName>
<UDN>uuid:87895a19-50f9-3736-a87f-115c230155f8</UDN>
<modelDescription>Sagemcom,fr,SG30_sip-fr-4.28.35.1</modelDescription>
<modelNumber>3</modelNumber>
<serialNumber>LK14129DP441489</serialNumber>
<presentationURL>http://192.168.1.1</presentationURL>
<UPC></UPC>
<iconList>
<icon>
<mimetype>image/png</mimetype>
<width>16</width>
<height>16</height>
<depth>8</depth>
<url>/87895a19/ligd.png</url>
</icon>
</iconList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANDevice:2</deviceType>
<friendlyName>WANDevice</friendlyName>
<manufacturer>Sagemcom</manufacturer>
<manufacturerURL>http://www.sagemcom.com/</manufacturerURL>
<modelDescription>WAN Device on Sagemcom,fr,SG30_sip-fr-4.28.35.1</modelDescription>
<modelName>Residential Livebox,(DSL,WAN Ethernet)</modelName>
<modelNumber>3</modelNumber>
<modelURL>http://www.sagemcom.com/</modelURL>
<serialNumber>LK14129DP441489</serialNumber>
<presentationURL>http://192.168.1.1</presentationURL>
<UDN>uuid:e2397374-53d8-3fc6-8306-593ba1a34625</UDN>
<UPC></UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>
<controlURL>/87895a19/upnp/control/WANCommonIFC1</controlURL>
<eventSubURL>/87895a19/upnp/control/WANCommonIFC1</eventSubURL>
<SCPDURL>/87895a19/gateicfgSCPD.xml</SCPDURL>
</service>
</serviceList>
<deviceList>
<device>
<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:2</deviceType>
<friendlyName>WANConnectionDevice</friendlyName>
<manufacturer>Sagemcom</manufacturer>
<manufacturerURL>http://www.sagemcom.com/</manufacturerURL>
<modelDescription>WanConnectionDevice on Sagemcom,fr,SG30_sip-fr-4.28.35.1</modelDescription>
<modelName>Residential Livebox,(DSL,WAN Ethernet)</modelName>
<modelNumber>3</modelNumber>
<modelURL>http://www.sagemcom.com/</modelURL>
<serialNumber>LK14129DP441489</serialNumber>
<presentationURL>http://192.168.1.1</presentationURL>
<UDN>uuid:44598a08-288e-32c9-8a4d-d3c008ede331</UDN>
<UPC></UPC>
<serviceList>
<service>
<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:2</serviceType>
<serviceId>urn:upnp-org:serviceId:WANIPConn1</serviceId>
<controlURL>/87895a19/upnp/control/WANIPConn1</controlURL>
<eventSubURL>/87895a19/upnp/control/WANIPConn1</eventSubURL>
<SCPDURL>/87895a19/gateconnSCPD_PPP.xml</SCPDURL>
</service>
<service>
<serviceType>urn:schemas-upnp-org:service:WANIPv6FirewallControl:1</serviceType>
<serviceId>urn:upnp-org:serviceId:WANIPv6FwCtrl1</serviceId>
<controlURL>/87895a19/upnp/control/WANIPv6FwCtrl1</controlURL>
<eventSubURL>/87895a19/upnp/control/WANIPv6FwCtrl1</eventSubURL>
<SCPDURL>/87895a19/wanipv6fwctrlSCPD.xml</SCPDURL>
</service>
</serviceList>
</device>
</deviceList>
</device>
</deviceList>
</device>
</root>

View file

@ -1,8 +1,8 @@
/* $Id: testigddescparse.c,v 1.4 2012/06/28 18:52:12 nanard Exp $ */ /* $Id: testigddescparse.c,v 1.8 2015/02/08 08:46:06 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* http://miniupnp.free.fr/ * http://miniupnp.free.fr/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2008-2012 Thomas Bernard * Copyright (c) 2008-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
@ -13,11 +13,108 @@
#include "minixml.h" #include "minixml.h"
#include "miniupnpc.h" #include "miniupnpc.h"
int test_igd_desc_parse(char * buffer, int len) /* count number of differences */
int compare_service(struct IGDdatas_service * s, FILE * f)
{ {
int n = 0;
char line[1024];
while(fgets(line, sizeof(line), f)) {
char * value;
char * equal;
char * name;
char * parsedvalue;
int l;
l = strlen(line);
while((l > 0) && ((line[l-1] == '\r') || (line[l-1] == '\n') || (line[l-1] == ' ')))
line[--l] = '\0';
if(l == 0)
break; /* end on blank line */
if(line[0] == '#')
continue; /* skip comments */
equal = strchr(line, '=');
if(equal == NULL) {
fprintf(stderr, "Warning, line does not contain '=' : %s\n", line);
continue;
}
*equal = '\0';
name = line;
while(*name == ' ' || *name == '\t')
name++;
l = strlen(name);
while((l > 0) && (name[l-1] == ' ' || name[l-1] == '\t'))
name[--l] = '\0';
value = equal + 1;
while(*value == ' ' || *value == '\t')
value++;
if(strcmp(name, "controlurl") == 0)
parsedvalue = s->controlurl;
else if(strcmp(name, "eventsuburl") == 0)
parsedvalue = s->eventsuburl;
else if(strcmp(name, "scpdurl") == 0)
parsedvalue = s->scpdurl;
else if(strcmp(name, "servicetype") == 0)
parsedvalue = s->servicetype;
else {
fprintf(stderr, "unknown field '%s'\n", name);
continue;
}
if(0 != strcmp(parsedvalue, value)) {
fprintf(stderr, "difference : '%s' != '%s'\n", parsedvalue, value);
n++;
}
}
return n;
}
int compare_igd(struct IGDdatas * p, FILE * f)
{
int n = 0;
char line[1024];
struct IGDdatas_service * s;
while(fgets(line, sizeof(line), f)) {
char * colon;
int l = (int)strlen(line);
while((l > 0) && (line[l-1] == '\r' || (line[l-1] == '\n')))
line[--l] = '\0';
if(l == 0 || line[0] == '#')
continue; /* skip blank lines and comments */
colon = strchr(line, ':');
if(colon == NULL) {
fprintf(stderr, "Warning, no ':' : %s\n", line);
continue;
}
s = NULL;
*colon = '\0';
if(strcmp(line, "CIF") == 0)
s = &p->CIF;
else if(strcmp(line, "first") == 0)
s = &p->first;
else if(strcmp(line, "second") == 0)
s = &p->second;
else if(strcmp(line, "IPv6FC") == 0)
s = &p->IPv6FC;
else {
s = NULL;
fprintf(stderr, "*** unknown service '%s' ***\n", line);
n++;
continue;
}
n += compare_service(s, f);
}
if(n > 0)
fprintf(stderr, "*** %d difference%s ***\n", n, (n > 1) ? "s" : "");
return n;
}
int test_igd_desc_parse(char * buffer, int len, FILE * f)
{
int n;
struct IGDdatas igd; struct IGDdatas igd;
struct xmlparser parser; struct xmlparser parser;
struct UPNPUrls urls; struct UPNPUrls urls;
memset(&igd, 0, sizeof(struct IGDdatas)); memset(&igd, 0, sizeof(struct IGDdatas));
memset(&parser, 0, sizeof(struct xmlparser)); memset(&parser, 0, sizeof(struct xmlparser));
parser.xmlstart = buffer; parser.xmlstart = buffer;
@ -27,13 +124,16 @@ int test_igd_desc_parse(char * buffer, int len)
parser.endeltfunc = IGDendelt; parser.endeltfunc = IGDendelt;
parser.datafunc = IGDdata; parser.datafunc = IGDdata;
parsexml(&parser); parsexml(&parser);
#ifdef DEBUG
printIGD(&igd); printIGD(&igd);
#endif /* DEBUG */
GetUPNPUrls(&urls, &igd, "http://fake/desc/url/file.xml", 0); GetUPNPUrls(&urls, &igd, "http://fake/desc/url/file.xml", 0);
printf("ipcondescURL='%s'\n", urls.ipcondescURL); printf("ipcondescURL='%s'\n", urls.ipcondescURL);
printf("controlURL='%s'\n", urls.controlURL); printf("controlURL='%s'\n", urls.controlURL);
printf("controlURL_CIF='%s'\n", urls.controlURL_CIF); printf("controlURL_CIF='%s'\n", urls.controlURL_CIF);
n = f ? compare_igd(&igd, f) : 0;
FreeUPNPUrls(&urls); FreeUPNPUrls(&urls);
return 0; return n;
} }
int main(int argc, char * * argv) int main(int argc, char * * argv)
@ -41,9 +141,9 @@ int main(int argc, char * * argv)
FILE * f; FILE * f;
char * buffer; char * buffer;
int len; int len;
int r = 0; int r;
if(argc<2) { if(argc<2) {
fprintf(stderr, "Usage: %s file.xml\n", argv[0]); fprintf(stderr, "Usage: %s file.xml [file.values]\n", argv[0]);
return 1; return 1;
} }
f = fopen(argv[1], "r"); f = fopen(argv[1], "r");
@ -55,10 +155,33 @@ int main(int argc, char * * argv)
len = ftell(f); len = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
buffer = malloc(len); buffer = malloc(len);
fread(buffer, 1, len, f); if(!buffer) {
fprintf(stderr, "Memory allocation error.\n");
fclose(f);
return 1;
}
r = (int)fread(buffer, 1, len, f);
if(r != len) {
fprintf(stderr, "Failed to read file %s. %d out of %d bytes.\n",
argv[1], r, len);
fclose(f);
free(buffer);
return 1;
}
fclose(f); fclose(f);
r = test_igd_desc_parse(buffer, len); f = NULL;
if(argc > 2) {
f = fopen(argv[2], "r");
if(!f) {
fprintf(stderr, "Cannot open %s for reading.\n", argv[2]);
free(buffer);
return 1;
}
}
r = test_igd_desc_parse(buffer, len, f);
free(buffer); free(buffer);
if(f)
fclose(f);
return r; return r;
} }

View file

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# $Id: testminiwget.sh,v 1.10 2013/11/13 15:08:08 nanard Exp $ # $Id: testminiwget.sh,v 1.13 2015/09/03 17:57:44 nanard Exp $
# project miniupnp : http://miniupnp.free.fr/ # project miniupnp : http://miniupnp.free.fr/
# (c) 2011-2012 Thomas Bernard # (c) 2011-2015 Thomas Bernard
# #
# test program for miniwget.c # test program for miniwget.c
# is usually invoked by "make check" # is usually invoked by "make check"
@ -15,7 +15,7 @@
# The script was tested and works with ksh, bash # The script was tested and works with ksh, bash
# it should now also run with dash # it should now also run with dash
TMPD=`mktemp -d miniwgetXXXXXXXXXX` TMPD=`mktemp -d -t miniwgetXXXXXXXXXX`
HTTPSERVEROUT="${TMPD}/httpserverout" HTTPSERVEROUT="${TMPD}/httpserverout"
EXPECTEDFILE="${TMPD}/expectedfile" EXPECTEDFILE="${TMPD}/expectedfile"
DOWNLOADEDFILE="${TMPD}/downloadedfile" DOWNLOADEDFILE="${TMPD}/downloadedfile"

View file

@ -1,8 +1,8 @@
/* $Id: testminixml.c,v 1.9 2013/05/14 19:50:49 nanard Exp $ /* $Id: testminixml.c,v 1.10 2014/11/17 17:19:13 nanard Exp $
* MiniUPnP project * MiniUPnP project
* Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * Website : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author : Thomas Bernard. * Author : Thomas Bernard.
* Copyright (c) 2005-2013 Thomas Bernard * Copyright (c) 2005-2014 Thomas Bernard
* *
* testminixml.c * testminixml.c
* test program for the "minixml" functions. * test program for the "minixml" functions.
@ -58,7 +58,9 @@ void burptest(const char * buffer, int bufsize)
parser.endeltfunc = IGDendelt; parser.endeltfunc = IGDendelt;
parser.datafunc = IGDdata; parser.datafunc = IGDdata;
parsexml(&parser); parsexml(&parser);
#ifdef DEBUG
printIGD(&data); printIGD(&data);
#endif /* DEBUG */
} }
/* ----- main ---- */ /* ----- main ---- */

View file

@ -0,0 +1,151 @@
/* $Id: testportlistingparse.c,v 1.2 2014/11/01 10:37:32 nanard Exp $ */
/* Project : miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author : Thomas Bernard
* Copyright (c) 2014 Thomas Bernard
* This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution.
* */
#include <string.h>
#include <stdio.h>
#include "portlistingparse.h"
struct port_mapping {
unsigned int leasetime;
unsigned short externalport;
unsigned short internalport;
const char * remotehost;
const char * client;
const char * proto;
const char * desc;
unsigned char enabled;
};
/* return the number of differences */
int test(const char * portListingXml, int portListingXmlLen,
const struct port_mapping * ref, int count)
{
int i;
int r = 0;
struct PortMappingParserData data;
struct PortMapping * pm;
memset(&data, 0, sizeof(data));
ParsePortListing(portListingXml, portListingXmlLen, &data);
for(i = 0, pm = data.l_head;
(pm != NULL) && (i < count);
i++, pm = pm->l_next) {
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
i, pm->protocol, pm->externalPort, pm->internalClient,
pm->internalPort,
pm->description, pm->remoteHost,
(unsigned)pm->leaseTime);
if(0 != strcmp(pm->protocol, ref[i].proto)) {
printf("protocol : '%s' != '%s'\n", pm->protocol, ref[i].proto);
r++;
}
if(pm->externalPort != ref[i].externalport) {
printf("externalPort : %hu != %hu\n",
pm->externalPort, ref[i].externalport);
r++;
}
if(0 != strcmp(pm->internalClient, ref[i].client)) {
printf("client : '%s' != '%s'\n",
pm->internalClient, ref[i].client);
r++;
}
if(pm->internalPort != ref[i].internalport) {
printf("internalPort : %hu != %hu\n",
pm->internalPort, ref[i].internalport);
r++;
}
if(0 != strcmp(pm->description, ref[i].desc)) {
printf("description : '%s' != '%s'\n",
pm->description, ref[i].desc);
r++;
}
if(0 != strcmp(pm->remoteHost, ref[i].remotehost)) {
printf("remoteHost : '%s' != '%s'\n",
pm->remoteHost, ref[i].remotehost);
r++;
}
if((unsigned)pm->leaseTime != ref[i].leasetime) {
printf("leaseTime : %u != %u\n",
(unsigned)pm->leaseTime, ref[i].leasetime);
r++;
}
if(pm->enabled != ref[i].enabled) {
printf("enabled : %d != %d\n",
(int)pm->enabled, (int)ref[i].enabled);
r++;
}
}
if((i != count) || (pm != NULL)) {
printf("count mismatch : i=%d count=%d pm=%p\n", i, count, pm);
r++;
}
FreePortListing(&data);
return r;
}
const char test_document[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<p:PortMappingList xmlns:p=\"urn:schemas-upnp-org:gw:WANIPConnection\"\n"
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n"
"xsi:schemaLocation=\"urn:schemas-upnp-org:gw:WANIPConnection "
"http://www.upnp.org/schemas/gw/WANIPConnection-v2.xsd\">\n"
" <p:PortMappingEntry>\n"
" <p:NewRemoteHost></p:NewRemoteHost>\n"
" <p:NewExternalPort>5002</p:NewExternalPort>\n"
" <p:NewProtocol>UDP</p:NewProtocol>\n"
" <p:NewInternalPort>4001</p:NewInternalPort>\n"
" <p:NewInternalClient>192.168.1.123</p:NewInternalClient>\n"
" <p:NewEnabled>1</p:NewEnabled>\n"
" <p:NewDescription>xxx</p:NewDescription>\n"
" <p:NewLeaseTime>0</p:NewLeaseTime>\n"
" </p:PortMappingEntry>\n"
" <p:PortMappingEntry>\n"
" <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost>\n"
" <p:NewExternalPort>2345</p:NewExternalPort>\n"
" <p:NewProtocol>TCP</p:NewProtocol>\n"
" <p:NewInternalPort>2349</p:NewInternalPort>\n"
" <p:NewInternalClient>192.168.1.137</p:NewInternalClient>\n"
" <p:NewEnabled>1</p:NewEnabled>\n"
" <p:NewDescription>dooom</p:NewDescription>\n"
" <p:NewLeaseTime>346</p:NewLeaseTime>\n"
" </p:PortMappingEntry>\n"
" <p:PortMappingEntry>\n"
" <p:NewRemoteHost>134.231.2.11</p:NewRemoteHost>\n"
" <p:NewExternalPort>12345</p:NewExternalPort>\n"
" <p:NewProtocol>TCP</p:NewProtocol>\n"
" <p:NewInternalPort>12345</p:NewInternalPort>\n"
" <p:NewInternalClient>192.168.1.137</p:NewInternalClient>\n"
" <p:NewEnabled>1</p:NewEnabled>\n"
" <p:NewDescription>dooom A</p:NewDescription>\n"
" <p:NewLeaseTime>347</p:NewLeaseTime>\n"
" </p:PortMappingEntry>\n"
"</p:PortMappingList>";
#define PORT_MAPPINGS_COUNT 3
const struct port_mapping port_mappings[PORT_MAPPINGS_COUNT] = {
{347, 12345, 12345, "134.231.2.11", "192.168.1.137", "TCP", "dooom A", 1},
{346, 2345, 2349, "202.233.2.1", "192.168.1.137", "TCP", "dooom", 1},
{0, 5002, 4001, "", "192.168.1.123", "UDP", "xxx", 1}
};
/* --- main --- */
int main(void)
{
int r;
r = test(test_document, sizeof(test_document) - 1,
port_mappings, PORT_MAPPINGS_COUNT);
if(r == 0) {
printf("test of portlistingparse OK\n");
return 0;
} else {
printf("test FAILED (%d differences counted)\n", r);
return 1;
}
}

View file

@ -1,7 +1,7 @@
/* $Id: upnpc.c,v 1.104 2014/09/11 14:13:30 nanard Exp $ */ /* $Id: upnpc.c,v 1.111 2015/07/23 20:40:10 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. */ * LICENCE file provided in this distribution. */
@ -16,10 +16,12 @@
/* for IPPROTO_TCP / IPPROTO_UDP */ /* for IPPROTO_TCP / IPPROTO_UDP */
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif
#include <ctype.h>
#include "miniwget.h" #include "miniwget.h"
#include "miniupnpc.h" #include "miniupnpc.h"
#include "upnpcommands.h" #include "upnpcommands.h"
#include "upnperrors.h" #include "upnperrors.h"
#include "miniupnpcstrings.h"
/* protofix() checks if protocol is "UDP" or "TCP" /* protofix() checks if protocol is "UDP" or "TCP"
* returns NULL if not */ * returns NULL if not */
@ -41,6 +43,22 @@ const char * protofix(const char * proto)
return 0; return 0;
} }
/* is_int() checks if parameter is an integer or not
* 1 for integer
* 0 for not an integer */
int is_int(char const* s)
{
if(s == NULL)
return 0;
while(*s) {
/* #define isdigit(c) ((c) >= '0' && (c) <= '9') */
if(!isdigit(*s))
return 0;
s++;
}
return 1;
}
static void DisplayInfos(struct UPNPUrls * urls, static void DisplayInfos(struct UPNPUrls * urls,
struct IGDdatas * data) struct IGDdatas * data)
{ {
@ -174,7 +192,7 @@ static void NewListRedirections(struct UPNPUrls * urls,
if(r == UPNPCOMMAND_SUCCESS) if(r == UPNPCOMMAND_SUCCESS)
{ {
printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n"); printf(" i protocol exPort->inAddr:inPort description remoteHost leaseTime\n");
for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
{ {
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
i, pm->protocol, pm->externalPort, pm->internalClient, i, pm->protocol, pm->externalPort, pm->internalClient,
@ -199,7 +217,7 @@ static void NewListRedirections(struct UPNPUrls * urls,
&pdata); &pdata);
if(r == UPNPCOMMAND_SUCCESS) if(r == UPNPCOMMAND_SUCCESS)
{ {
for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) for(pm = pdata.l_head; pm != NULL; pm = pm->l_next)
{ {
printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n",
i, pm->protocol, pm->externalPort, pm->internalClient, i, pm->protocol, pm->externalPort, pm->internalClient,
@ -525,9 +543,11 @@ int main(int argc, char ** argv)
const char * rootdescurl = 0; const char * rootdescurl = 0;
const char * multicastif = 0; const char * multicastif = 0;
const char * minissdpdpath = 0; const char * minissdpdpath = 0;
int localport = UPNP_LOCAL_PORT_ANY;
int retcode = 0; int retcode = 0;
int error = 0; int error = 0;
int ipv6 = 0; int ipv6 = 0;
unsigned char ttl = 2; /* defaulting to 2 */
const char * description = 0; const char * description = 0;
#ifdef _WIN32 #ifdef _WIN32
@ -539,7 +559,8 @@ int main(int argc, char ** argv)
return -1; return -1;
} }
#endif #endif
printf("upnpc : miniupnpc library test client. (c) 2005-2014 Thomas Bernard\n"); printf("upnpc : miniupnpc library test client, version %s.\n", MINIUPNPC_VERSION_STRING);
printf(" (c) 2005-2015 Thomas Bernard.\n");
printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n"
"for more information.\n"); "for more information.\n");
/* command line processing */ /* command line processing */
@ -556,12 +577,26 @@ int main(int argc, char ** argv)
rootdescurl = argv[++i]; rootdescurl = argv[++i];
else if(argv[i][1] == 'm') else if(argv[i][1] == 'm')
multicastif = argv[++i]; multicastif = argv[++i];
else if(argv[i][1] == 'z')
{
char junk;
if(sscanf(argv[++i], "%d%c", &localport, &junk)!=1 ||
localport<0 || localport>65535 ||
(localport >1 && localport < 1024))
{
fprintf(stderr, "Invalid localport '%s'\n", argv[i]);
localport = UPNP_LOCAL_PORT_ANY;
break;
}
}
else if(argv[i][1] == 'p') else if(argv[i][1] == 'p')
minissdpdpath = argv[++i]; minissdpdpath = argv[++i];
else if(argv[i][1] == '6') else if(argv[i][1] == '6')
ipv6 = 1; ipv6 = 1;
else if(argv[i][1] == 'e') else if(argv[i][1] == 'e')
description = argv[++i]; description = argv[++i];
else if(argv[i][1] == 't')
ttl = (unsigned char)atoi(argv[++i]);
else else
{ {
command = argv[i][1]; command = argv[i][1];
@ -577,7 +612,8 @@ int main(int argc, char ** argv)
} }
} }
if(!command || (command == 'a' && commandargc<4) if(!command
|| (command == 'a' && commandargc<4)
|| (command == 'd' && argc<2) || (command == 'd' && argc<2)
|| (command == 'r' && argc<2) || (command == 'r' && argc<2)
|| (command == 'A' && commandargc<6) || (command == 'A' && commandargc<6)
@ -591,7 +627,7 @@ int main(int argc, char ** argv)
fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings (for IGD:2 only)\n", argv[0]);
fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -n ip port external_port protocol [duration]\n\t\tAdd (any) port redirection allowing IGD to use alternative external_port (for IGD:2 only)\n", argv[0]);
fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -N external_port_start external_port_end protocol [manage]\n\t\tDelete range of port redirections (for IGD:2 only)\n", argv[0]);
fprintf(stderr, " \t%s [options] -r port1 protocol1 [port2 protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]); fprintf(stderr, " \t%s [options] -r port1 [external_port1] protocol1 [port2 [external_port2] protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]);
fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]);
fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]);
fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]); fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]);
@ -606,13 +642,15 @@ int main(int argc, char ** argv)
fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n"); fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n");
fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n"); fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n");
fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n"); fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v4 or v6) to use for sending SSDP multicast packets.\n");
fprintf(stderr, " -z localport : SSDP packets local (source) port (1024-65535).\n");
fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n"); fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n");
fprintf(stderr, " -t ttl : set multicast TTL. Default value is 2.\n");
return 1; return 1;
} }
if( rootdescurl if( rootdescurl
|| (devlist = upnpDiscover(2000, multicastif, minissdpdpath, || (devlist = upnpDiscover(2000, multicastif, minissdpdpath,
0/*sameport*/, ipv6, &error))) localport, ipv6, ttl, &error)))
{ {
struct UPNPDev * device; struct UPNPDev * device;
struct UPNPUrls urls; struct UPNPUrls urls;
@ -626,7 +664,7 @@ int main(int argc, char ** argv)
device->descURL, device->st); device->descURL, device->st);
} }
} }
else else if(!rootdescurl)
{ {
printf("upnpDiscover() error code=%d\n", error); printf("upnpDiscover() error code=%d\n", error);
} }
@ -699,13 +737,29 @@ int main(int argc, char ** argv)
GetConnectionStatus(&urls, &data); GetConnectionStatus(&urls, &data);
break; break;
case 'r': case 'r':
for(i=0; i<commandargc; i+=2) i = 0;
while(i<commandargc)
{ {
/*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/ if(!is_int(commandargv[i])) {
SetRedirectAndTest(&urls, &data, /* 1st parameter not an integer : error */
lanaddr, commandargv[i], fprintf(stderr, "command -r : %s is not an port number\n", commandargv[i]);
commandargv[i], commandargv[i+1], "0", retcode = 1;
description, 0); break;
} else if(is_int(commandargv[i+1])){
/* 2nd parameter is an integer : <port> <external_port> <protocol> */
SetRedirectAndTest(&urls, &data,
lanaddr, commandargv[i],
commandargv[i+1], commandargv[i+2], "0",
description, 0);
i+=3; /* 3 parameters parsed */
} else {
/* 2nd parameter not an integer : <port> <protocol> */
SetRedirectAndTest(&urls, &data,
lanaddr, commandargv[i],
commandargv[i], commandargv[i+1], "0",
description, 0);
i+=2; /* 2 parameters parsed */
}
} }
break; break;
case 'A': case 'A':
@ -768,6 +822,12 @@ int main(int argc, char ** argv)
fprintf(stderr, "No IGD UPnP Device found on the network !\n"); fprintf(stderr, "No IGD UPnP Device found on the network !\n");
retcode = 1; retcode = 1;
} }
#ifdef _WIN32
nResult = WSACleanup();
if(nResult != NO_ERROR) {
fprintf(stderr, "WSACleanup() failed.\n");
}
#endif /* _WIN32 */
return retcode; return retcode;
} }

View file

@ -1,7 +1,7 @@
/* $Id: upnpcommands.c,v 1.42 2014/01/31 13:18:25 nanard Exp $ */ /* $Id: upnpcommands.c,v 1.46 2015/07/15 12:19:00 nanard Exp $ */
/* Project : miniupnp /* Project : miniupnp
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2012 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided in this distribution. * LICENCE file provided in this distribution.
* */ * */
@ -159,7 +159,7 @@ UPNP_GetStatusInfo(const char * controlURL,
if(up) if(up)
sscanf(up,"%u",uptime); sscanf(up,"%u",uptime);
else else
uptime = 0; *uptime = 0;
} }
if(lastconnerror) { if(lastconnerror) {
@ -354,6 +354,8 @@ UPNP_AddPortMapping(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
if(AddPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
AddPortMappingArgs[0].elt = "NewRemoteHost"; AddPortMappingArgs[0].elt = "NewRemoteHost";
AddPortMappingArgs[0].val = remoteHost; AddPortMappingArgs[0].val = remoteHost;
AddPortMappingArgs[1].elt = "NewExternalPort"; AddPortMappingArgs[1].elt = "NewExternalPort";
@ -416,6 +418,8 @@ UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); AddPortMappingArgs = calloc(9, sizeof(struct UPNParg));
if(AddPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
AddPortMappingArgs[0].elt = "NewRemoteHost"; AddPortMappingArgs[0].elt = "NewRemoteHost";
AddPortMappingArgs[0].val = remoteHost; AddPortMappingArgs[0].val = remoteHost;
AddPortMappingArgs[1].elt = "NewExternalPort"; AddPortMappingArgs[1].elt = "NewExternalPort";
@ -478,6 +482,8 @@ UPNP_DeletePortMapping(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg));
if(DeletePortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePortMappingArgs[0].elt = "NewRemoteHost"; DeletePortMappingArgs[0].elt = "NewRemoteHost";
DeletePortMappingArgs[0].val = remoteHost; DeletePortMappingArgs[0].val = remoteHost;
DeletePortMappingArgs[1].elt = "NewExternalPort"; DeletePortMappingArgs[1].elt = "NewExternalPort";
@ -522,6 +528,8 @@ UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg)); DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg));
if(DeletePortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePortMappingArgs[0].elt = "NewStartPort"; DeletePortMappingArgs[0].elt = "NewStartPort";
DeletePortMappingArgs[0].val = extPortStart; DeletePortMappingArgs[0].val = extPortStart;
DeletePortMappingArgs[1].elt = "NewEndPort"; DeletePortMappingArgs[1].elt = "NewEndPort";
@ -575,6 +583,8 @@ UPNP_GetGenericPortMappingEntry(const char * controlURL,
intClient[0] = '\0'; intClient[0] = '\0';
intPort[0] = '\0'; intPort[0] = '\0';
GetPortMappingArgs = calloc(2, sizeof(struct UPNParg)); GetPortMappingArgs = calloc(2, sizeof(struct UPNParg));
if(GetPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPortMappingArgs[0].elt = "NewPortMappingIndex"; GetPortMappingArgs[0].elt = "NewPortMappingIndex";
GetPortMappingArgs[0].val = index; GetPortMappingArgs[0].val = index;
if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -710,6 +720,8 @@ UPNP_GetSpecificPortMappingEntry(const char * controlURL,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); GetPortMappingArgs = calloc(4, sizeof(struct UPNParg));
if(GetPortMappingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPortMappingArgs[0].elt = "NewRemoteHost"; GetPortMappingArgs[0].elt = "NewRemoteHost";
GetPortMappingArgs[0].val = remoteHost; GetPortMappingArgs[0].val = remoteHost;
GetPortMappingArgs[1].elt = "NewExternalPort"; GetPortMappingArgs[1].elt = "NewExternalPort";
@ -799,6 +811,8 @@ UPNP_GetListOfPortMappings(const char * controlURL,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg));
if(GetListOfPortMappingsArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetListOfPortMappingsArgs[0].elt = "NewStartPort"; GetListOfPortMappingsArgs[0].elt = "NewStartPort";
GetListOfPortMappingsArgs[0].val = startPort; GetListOfPortMappingsArgs[0].val = startPort;
GetListOfPortMappingsArgs[1].elt = "NewEndPort"; GetListOfPortMappingsArgs[1].elt = "NewEndPort";
@ -926,6 +940,8 @@ UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg));
if(GetOutboundPinholeTimeoutArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost"; GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost";
GetOutboundPinholeTimeoutArgs[0].val = remoteHost; GetOutboundPinholeTimeoutArgs[0].val = remoteHost;
GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort"; GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort";
@ -982,6 +998,8 @@ UPNP_AddPinhole(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); AddPinholeArgs = calloc(7, sizeof(struct UPNParg));
if(AddPinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
/* RemoteHost can be wilcarded */ /* RemoteHost can be wilcarded */
if(strncmp(remoteHost, "empty", 5)==0) if(strncmp(remoteHost, "empty", 5)==0)
{ {
@ -1055,6 +1073,8 @@ UPNP_UpdatePinhole(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg));
if(UpdatePinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
UpdatePinholeArgs[0].elt = "UniqueID"; UpdatePinholeArgs[0].elt = "UniqueID";
UpdatePinholeArgs[0].val = uniqueID; UpdatePinholeArgs[0].val = uniqueID;
UpdatePinholeArgs[1].elt = "NewLeaseTime"; UpdatePinholeArgs[1].elt = "NewLeaseTime";
@ -1096,6 +1116,8 @@ UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); DeletePinholeArgs = calloc(2, sizeof(struct UPNParg));
if(DeletePinholeArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
DeletePinholeArgs[0].elt = "UniqueID"; DeletePinholeArgs[0].elt = "UniqueID";
DeletePinholeArgs[0].val = uniqueID; DeletePinholeArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype, buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -1135,6 +1157,8 @@ UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg));
if(CheckPinholeWorkingArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
CheckPinholeWorkingArgs[0].elt = "UniqueID"; CheckPinholeWorkingArgs[0].elt = "UniqueID";
CheckPinholeWorkingArgs[0].val = uniqueID; CheckPinholeWorkingArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype, buffer = simpleUPnPcommand(-1, controlURL, servicetype,
@ -1180,6 +1204,8 @@ UPNP_GetPinholePackets(const char * controlURL, const char * servicetype,
return UPNPCOMMAND_INVALID_ARGS; return UPNPCOMMAND_INVALID_ARGS;
GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg));
if(GetPinholePacketsArgs == NULL)
return UPNPCOMMAND_MEM_ALLOC_ERROR;
GetPinholePacketsArgs[0].elt = "UniqueID"; GetPinholePacketsArgs[0].elt = "UniqueID";
GetPinholePacketsArgs[0].val = uniqueID; GetPinholePacketsArgs[0].val = uniqueID;
buffer = simpleUPnPcommand(-1, controlURL, servicetype, buffer = simpleUPnPcommand(-1, controlURL, servicetype,

View file

@ -1,7 +1,7 @@
/* $Id: upnpcommands.h,v 1.27 2014/02/17 15:38:26 nanard Exp $ */ /* $Id: upnpcommands.h,v 1.30 2015/07/15 12:21:28 nanard Exp $ */
/* Miniupnp project : http://miniupnp.free.fr/ /* Miniupnp project : http://miniupnp.free.fr/
* Author : Thomas Bernard * Author : Thomas Bernard
* Copyright (c) 2005-2014 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subject to the conditions detailed in the * This software is subject to the conditions detailed in the
* LICENCE file provided within this distribution */ * LICENCE file provided within this distribution */
#ifndef UPNPCOMMANDS_H_INCLUDED #ifndef UPNPCOMMANDS_H_INCLUDED
@ -9,7 +9,7 @@
#include "upnpreplyparse.h" #include "upnpreplyparse.h"
#include "portlistingparse.h" #include "portlistingparse.h"
#include "declspec.h" #include "miniupnpc_declspec.h"
#include "miniupnpctypes.h" #include "miniupnpctypes.h"
/* MiniUPnPc return codes : */ /* MiniUPnPc return codes : */
@ -18,6 +18,7 @@
#define UPNPCOMMAND_INVALID_ARGS (-2) #define UPNPCOMMAND_INVALID_ARGS (-2)
#define UPNPCOMMAND_HTTP_ERROR (-3) #define UPNPCOMMAND_HTTP_ERROR (-3)
#define UPNPCOMMAND_INVALID_RESPONSE (-4) #define UPNPCOMMAND_INVALID_RESPONSE (-4)
#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

23
external/miniupnpc/upnpdev.c vendored Normal file
View file

@ -0,0 +1,23 @@
/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#include <stdlib.h>
#include "upnpdev.h"
/* freeUPNPDevlist() should be used to
* free the chained list returned by upnpDiscover() */
void freeUPNPDevlist(struct UPNPDev * devlist)
{
struct UPNPDev * next;
while(devlist)
{
next = devlist->pNext;
free(devlist);
devlist = next;
}
}

36
external/miniupnpc/upnpdev.h vendored Normal file
View file

@ -0,0 +1,36 @@
/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */
/* Project : miniupnp
* Web : http://miniupnp.free.fr/
* Author : Thomas BERNARD
* copyright (c) 2005-2015 Thomas Bernard
* This software is subjet to the conditions detailed in the
* provided LICENSE file. */
#ifndef UPNPDEV_H_INCLUDED
#define UPNPDEV_H_INCLUDED
#include "miniupnpc_declspec.h"
#ifdef __cplusplus
extern "C" {
#endif
struct UPNPDev {
struct UPNPDev * pNext;
char * descURL;
char * st;
unsigned int scope_id;
char * usn;
char buffer[3];
};
/* freeUPNPDevlist()
* free list returned by upnpDiscover() */
MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist);
#ifdef __cplusplus
}
#endif
#endif /* UPNPDEV_H_INCLUDED */

View file

@ -1,5 +1,5 @@
/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */ /* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */
/* (c) 2007 Thomas Bernard /* (c) 2007-2015 Thomas Bernard
* All rights reserved. * All rights reserved.
* MiniUPnP Project. * MiniUPnP Project.
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -8,7 +8,7 @@
#ifndef UPNPERRORS_H_INCLUDED #ifndef UPNPERRORS_H_INCLUDED
#define UPNPERRORS_H_INCLUDED #define UPNPERRORS_H_INCLUDED
#include "declspec.h" #include "miniupnpc_declspec.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {

View file

@ -1,7 +1,7 @@
/* $Id: upnpreplyparse.c,v 1.15 2013/06/06 21:36:40 nanard Exp $ */ /* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2013 Thomas Bernard * (c) 2006-2015 Thomas Bernard
* This software is subject to the conditions detailed * This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */ * in the LICENCE file provided within the distribution */
@ -40,6 +40,15 @@ NameValueParserEndElt(void * d, const char * name, int l)
/* standard case. Limited to n chars strings */ /* standard case. Limited to n chars strings */
l = data->cdatalen; l = data->cdatalen;
nv = malloc(sizeof(struct NameValue)); nv = malloc(sizeof(struct NameValue));
if(nv == NULL)
{
/* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserEndElt");
#endif /* DEBUG */
return;
}
if(l>=(int)sizeof(nv->value)) if(l>=(int)sizeof(nv->value))
l = sizeof(nv->value) - 1; l = sizeof(nv->value) - 1;
strncpy(nv->name, data->curelt, 64); strncpy(nv->name, data->curelt, 64);
@ -53,7 +62,8 @@ NameValueParserEndElt(void * d, const char * name, int l)
{ {
nv->value[0] = '\0'; nv->value[0] = '\0';
} }
LIST_INSERT_HEAD( &(data->head), nv, entries); nv->l_next = data->l_head; /* insert in list */
data->l_head = nv;
} }
data->cdata = NULL; data->cdata = NULL;
data->cdatalen = 0; data->cdatalen = 0;
@ -71,6 +81,10 @@ NameValueParserGetData(void * d, const char * datas, int l)
if(!data->portListing) if(!data->portListing)
{ {
/* malloc error */ /* malloc error */
#ifdef DEBUG
fprintf(stderr, "%s: error allocating memory",
"NameValueParserGetData");
#endif /* DEBUG */
return; return;
} }
memcpy(data->portListing, datas, l); memcpy(data->portListing, datas, l);
@ -89,19 +103,19 @@ void
ParseNameValue(const char * buffer, int bufsize, ParseNameValue(const char * buffer, int bufsize,
struct NameValueParserData * data) struct NameValueParserData * data)
{ {
struct xmlparser parser; struct xmlparser parser;
LIST_INIT(&(data->head)); data->l_head = NULL;
data->portListing = NULL; data->portListing = NULL;
data->portListingLength = 0; data->portListingLength = 0;
/* init xmlparser object */ /* init xmlparser object */
parser.xmlstart = buffer; parser.xmlstart = buffer;
parser.xmlsize = bufsize; parser.xmlsize = bufsize;
parser.data = data; parser.data = data;
parser.starteltfunc = NameValueParserStartElt; parser.starteltfunc = NameValueParserStartElt;
parser.endeltfunc = NameValueParserEndElt; parser.endeltfunc = NameValueParserEndElt;
parser.datafunc = NameValueParserGetData; parser.datafunc = NameValueParserGetData;
parser.attfunc = 0; parser.attfunc = 0;
parsexml(&parser); parsexml(&parser);
} }
void void
@ -114,9 +128,9 @@ ClearNameValueList(struct NameValueParserData * pdata)
pdata->portListing = NULL; pdata->portListing = NULL;
pdata->portListingLength = 0; pdata->portListingLength = 0;
} }
while((nv = pdata->head.lh_first) != NULL) while((nv = pdata->l_head) != NULL)
{ {
LIST_REMOVE(nv, entries); pdata->l_head = nv->l_next;
free(nv); free(nv);
} }
} }
@ -127,9 +141,9 @@ GetValueFromNameValueList(struct NameValueParserData * pdata,
{ {
struct NameValue * nv; struct NameValue * nv;
char * p = NULL; char * p = NULL;
for(nv = pdata->head.lh_first; for(nv = pdata->l_head;
(nv != NULL) && (p == NULL); (nv != NULL) && (p == NULL);
nv = nv->entries.le_next) nv = nv->l_next)
{ {
if(strcmp(nv->name, Name) == 0) if(strcmp(nv->name, Name) == 0)
p = nv->value; p = nv->value;
@ -171,13 +185,13 @@ DisplayNameValueList(char * buffer, int bufsize)
struct NameValueParserData pdata; struct NameValueParserData pdata;
struct NameValue * nv; struct NameValue * nv;
ParseNameValue(buffer, bufsize, &pdata); ParseNameValue(buffer, bufsize, &pdata);
for(nv = pdata.head.lh_first; for(nv = pdata.l_head;
nv != NULL; nv != NULL;
nv = nv->entries.le_next) nv = nv->l_next)
{ {
printf("%s = %s\n", nv->name, nv->value); printf("%s = %s\n", nv->name, nv->value);
} }
ClearNameValueList(&pdata); ClearNameValueList(&pdata);
} }
#endif #endif /* DEBUG */

View file

@ -1,4 +1,4 @@
/* $Id: upnpreplyparse.h,v 1.17 2013/06/06 21:36:40 nanard Exp $ */ /* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */
/* MiniUPnP project /* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2013 Thomas Bernard * (c) 2006-2013 Thomas Bernard
@ -8,25 +8,19 @@
#ifndef UPNPREPLYPARSE_H_INCLUDED #ifndef UPNPREPLYPARSE_H_INCLUDED
#define UPNPREPLYPARSE_H_INCLUDED #define UPNPREPLYPARSE_H_INCLUDED
#if defined(NO_SYS_QUEUE_H) || defined(_WIN32) || defined(__HAIKU__)
#include "bsdqueue.h"
#else
#include <sys/queue.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
struct NameValue { struct NameValue {
LIST_ENTRY(NameValue) entries; struct NameValue * l_next;
char name[64]; char name[64];
char value[128]; char value[128];
}; };
struct NameValueParserData { struct NameValueParserData {
LIST_HEAD(listhead, NameValue) head; struct NameValue * l_head;
char curelt[64]; char curelt[64];
char * portListing; char * portListing;
int portListingLength; int portListingLength;
int topelt; int topelt;

View file

@ -1,8 +1,8 @@
/* $Id: wingenminiupnpcstrings.c,v 1.2 2011/01/11 15:31:13 nanard Exp $ */ /* $Id: wingenminiupnpcstrings.c,v 1.4 2015/02/08 08:46:06 nanard Exp $ */
/* Project: miniupnp /* Project: miniupnp
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* Author: Thomas Bernard * Author: Thomas Bernard
* Copyright (c) 2005-2009 Thomas Bernard * Copyright (c) 2005-2015 Thomas Bernard
* This software is subjects to the conditions detailed * This software is subjects to the conditions detailed
* in the LICENSE file provided within this distribution */ * in the LICENSE file provided within this distribution */
#include <stdio.h> #include <stdio.h>
@ -59,6 +59,7 @@ int main(int argc, char * * argv) {
fout = fopen(argv[2], "w"); fout = fopen(argv[2], "w");
if(!fout) { if(!fout) {
fprintf(stderr, "Cannot open %s for writing.\n", argv[2]); fprintf(stderr, "Cannot open %s for writing.\n", argv[2]);
fclose(fin);
return 1; return 1;
} }
n = 0; n = 0;

View file

@ -1,29 +1,23 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_ALLOCATORS_H_ #ifndef RAPIDJSON_ALLOCATORS_H_
#define RAPIDJSON_ALLOCATORS_H_ #define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h" #include "rapidjson.h"
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Allocator // Allocator
@ -68,8 +62,20 @@ concept Allocator {
class CrtAllocator { class CrtAllocator {
public: public:
static const bool kNeedFree = true; static const bool kNeedFree = true;
void* Malloc(size_t size) { return std::malloc(size); } void* Malloc(size_t size) {
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return std::realloc(originalPtr, newSize); } if (size) // behavior of malloc(0) is implementation defined.
return std::malloc(size);
else
return NULL; // standardize to returning NULL.
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
(void)originalSize;
if (newSize == 0) {
std::free(originalPtr);
return NULL;
}
return std::realloc(originalPtr, newSize);
}
static void Free(void *ptr) { std::free(ptr); } static void Free(void *ptr) { std::free(ptr); }
}; };
@ -104,9 +110,6 @@ public:
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{ {
if (!baseAllocator_)
ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
AddChunk(chunk_capacity_);
} }
//! Constructor with user-supplied buffer. //! Constructor with user-supplied buffer.
@ -135,16 +138,18 @@ public:
*/ */
~MemoryPoolAllocator() { ~MemoryPoolAllocator() {
Clear(); Clear();
delete ownBaseAllocator_; RAPIDJSON_DELETE(ownBaseAllocator_);
} }
//! Deallocates all memory chunks, excluding the user-supplied buffer. //! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() { void Clear() {
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) { while (chunkHead_ && chunkHead_ != userBuffer_) {
ChunkHeader* next = chunkHead_->next; ChunkHeader* next = chunkHead_->next;
baseAllocator_->Free(chunkHead_); baseAllocator_->Free(chunkHead_);
chunkHead_ = next; chunkHead_ = next;
} }
if (chunkHead_ && chunkHead_ == userBuffer_)
chunkHead_->size = 0; // Clear user buffer
} }
//! Computes the total capacity of allocated memory chunks. //! Computes the total capacity of allocated memory chunks.
@ -169,11 +174,14 @@ public:
//! Allocates a memory block. (concept Allocator) //! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) { void* Malloc(size_t size) {
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size); size = RAPIDJSON_ALIGN(size);
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size; void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
chunkHead_->size += size; chunkHead_->size += size;
return buffer; return buffer;
} }
@ -183,12 +191,15 @@ public:
if (originalPtr == 0) if (originalPtr == 0)
return Malloc(newSize); return Malloc(newSize);
if (newSize == 0)
return NULL;
// Do not shrink if new size is smaller than original // Do not shrink if new size is smaller than original
if (originalSize >= newSize) if (originalSize >= newSize)
return originalPtr; return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space // Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize); size_t increment = static_cast<size_t>(newSize - originalSize);
increment = RAPIDJSON_ALIGN(increment); increment = RAPIDJSON_ALIGN(increment);
if (chunkHead_->size + increment <= chunkHead_->capacity) { if (chunkHead_->size + increment <= chunkHead_->capacity) {
@ -200,7 +211,9 @@ public:
// Realloc process: allocate and copy memory, do not free original buffer. // Realloc process: allocate and copy memory, do not free original buffer.
void* newBuffer = Malloc(newSize); void* newBuffer = Malloc(newSize);
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
return std::memcpy(newBuffer, originalPtr, originalSize); if (originalSize)
std::memcpy(newBuffer, originalPtr, originalSize);
return newBuffer;
} }
//! Frees a memory block (concept Allocator) //! Frees a memory block (concept Allocator)
@ -216,7 +229,9 @@ private:
/*! \param capacity Capacity of the chunk in bytes. /*! \param capacity Capacity of the chunk in bytes.
*/ */
void AddChunk(size_t capacity) { void AddChunk(size_t capacity) {
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity)); if (!baseAllocator_)
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
chunk->capacity = capacity; chunk->capacity = capacity;
chunk->size = 0; chunk->size = 0;
chunk->next = chunkHead_; chunk->next = chunkHead_;
@ -241,6 +256,6 @@ private:
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
}; };
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_ #endif // RAPIDJSON_ENCODINGS_H_

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_DOCUMENT_H_ #ifndef RAPIDJSON_DOCUMENT_H_
#define RAPIDJSON_DOCUMENT_H_ #define RAPIDJSON_DOCUMENT_H_
@ -26,50 +20,41 @@
#include "reader.h" #include "reader.h"
#include "internal/meta.h" #include "internal/meta.h"
#include "internal/strfunc.h" #include "internal/strfunc.h"
#include "memorystream.h"
#include "encodedstream.h"
#include <new> // placement new #include <new> // placement new
#ifdef _MSC_VER #ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
#elif defined(__GNUC__) #endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_HAS_STDSTRING
#ifndef RAPIDJSON_HAS_STDSTRING
#ifdef RAPIDJSON_DOXYGEN_RUNNING
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
#else
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
#endif
/*! \def RAPIDJSON_HAS_STDSTRING
\ingroup RAPIDJSON_CONFIG
\brief Enable RapidJSON support for \c std::string
By defining this preprocessor symbol to \c 1, several convenience functions for using
\ref rapidjson::GenericValue with \c std::string are enabled, especially
for construction and comparison.
\hideinitializer
*/
#include <string>
#endif // RAPIDJSON_HAS_STDSTRING
#ifndef RAPIDJSON_NOMEMBERITERATORCLASS #ifndef RAPIDJSON_NOMEMBERITERATORCLASS
#include <iterator> // std::iterator, std::random_access_iterator_tag #include <iterator> // std::iterator, std::random_access_iterator_tag
#endif #endif
namespace rapidjson { #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#include <utility> // std::move
#endif
RAPIDJSON_NAMESPACE_BEGIN
// Forward declaration. // Forward declaration.
template <typename Encoding, typename Allocator> template <typename Encoding, typename Allocator>
class GenericValue; class GenericValue;
template <typename Encoding, typename Allocator, typename StackAllocator>
class GenericDocument;
//! Name-value pair in a JSON object value. //! Name-value pair in a JSON object value.
/*! /*!
This class was internal to GenericValue. It used to be a inner struct. This class was internal to GenericValue. It used to be a inner struct.
@ -258,6 +243,7 @@ struct GenericStringRef {
typedef CharType Ch; //!< character type of the string typedef CharType Ch; //!< character type of the string
//! Create string reference from \c const character array //! Create string reference from \c const character array
#ifndef __clang__ // -Wdocumentation
/*! /*!
This constructor implicitly creates a constant string reference from This constructor implicitly creates a constant string reference from
a \c const character array. It has better performance than a \c const character array. It has better performance than
@ -280,11 +266,13 @@ struct GenericStringRef {
In such cases, the referenced string should be \b copied to the In such cases, the referenced string should be \b copied to the
GenericValue instead. GenericValue instead.
*/ */
#endif
template<SizeType N> template<SizeType N>
GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
: s(str), length(N-1) {} : s(str), length(N-1) {}
//! Explicitly create string reference from \c const character pointer //! Explicitly create string reference from \c const character pointer
#ifndef __clang__ // -Wdocumentation
/*! /*!
This constructor can be used to \b explicitly create a reference to This constructor can be used to \b explicitly create a reference to
a constant string pointer. a constant string pointer.
@ -303,16 +291,19 @@ struct GenericStringRef {
In such cases, the referenced string should be \b copied to the In such cases, the referenced string should be \b copied to the
GenericValue instead. GenericValue instead.
*/ */
#endif
explicit GenericStringRef(const CharType* str) explicit GenericStringRef(const CharType* str)
: s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); } : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); }
//! Create constant string reference from pointer and length //! Create constant string reference from pointer and length
#ifndef __clang__ // -Wdocumentation
/*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
\param len length of the string, excluding the trailing NULL terminator \param len length of the string, excluding the trailing NULL terminator
\post \ref s == str && \ref length == len \post \ref s == str && \ref length == len
\note Constant complexity. \note Constant complexity.
*/ */
#endif
GenericStringRef(const CharType* str, SizeType len) GenericStringRef(const CharType* str, SizeType len)
: s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); } : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); }
@ -428,6 +419,7 @@ public:
typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
//!@name Constructors and destructor. //!@name Constructors and destructor.
//@{ //@{
@ -446,6 +438,16 @@ private:
//! Copy constructor is not permitted. //! Copy constructor is not permitted.
GenericValue(const GenericValue& rhs); GenericValue(const GenericValue& rhs);
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Moving from a GenericDocument is not permitted.
template <typename StackAllocator>
GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
//! Move assignment from a GenericDocument is not permitted.
template <typename StackAllocator>
GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
#endif
public: public:
//! Constructor with JSON value type. //! Constructor with JSON value type.
@ -453,13 +455,17 @@ public:
\param type Type of the value. \param type Type of the value.
\note Default content for number is zero. \note Default content for number is zero.
*/ */
GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() { explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() {
static const unsigned defaultFlags[7] = { static const unsigned defaultFlags[7] = {
kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag, kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
kNumberAnyFlag kNumberAnyFlag
}; };
RAPIDJSON_ASSERT(type <= kNumberType); RAPIDJSON_ASSERT(type <= kNumberType);
flags_ = defaultFlags[type]; flags_ = defaultFlags[type];
// Use ShortString to store empty string.
if (type == kStringType)
data_.ss.SetLength(0);
} }
//! Explicit copy constructor (with allocator) //! Explicit copy constructor (with allocator)
@ -637,7 +643,7 @@ public:
*/ */
template <typename SourceAllocator> template <typename SourceAllocator>
GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) { GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
this->~GenericValue(); this->~GenericValue();
new (this) GenericValue(rhs, allocator); new (this) GenericValue(rhs, allocator);
return *this; return *this;
@ -656,6 +662,20 @@ public:
return *this; return *this;
} }
//! free-standing swap function helper
/*!
Helper function to enable support for common swap implementation pattern based on \c std::swap:
\code
void swap(MyClass& a, MyClass& b) {
using std::swap;
swap(a.value, b.value);
// ...
}
\endcode
\see Swap()
*/
friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
//! Prepare Value for move semantics //! Prepare Value for move semantics
/*! \return *this */ /*! \return *this */
GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
@ -697,12 +717,15 @@ public:
return StringEqual(rhs); return StringEqual(rhs);
case kNumberType: case kNumberType:
if (IsDouble() || rhs.IsDouble()) if (IsDouble() || rhs.IsDouble()) {
return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double. double a = GetDouble(); // May convert from integer to double.
double b = rhs.GetDouble(); // Ditto
return a >= b && a <= b; // Prevent -Wfloat-equal
}
else else
return data_.n.u64 == rhs.data_.n.u64; return data_.n.u64 == rhs.data_.n.u64;
default: // kTrueType, kFalseType, kNullType default:
return true; return true;
} }
} }
@ -797,22 +820,32 @@ public:
//! Check whether the object is empty. //! Check whether the object is empty.
bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
//! Get the value associated with the name. //! Get a value from an object associated with the name.
/*! /*! \pre IsObject() == true
\tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
\note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
Since 0.2, if the name is not correct, it will assert. Since 0.2, if the name is not correct, it will assert.
If user is unsure whether a member exists, user should use HasMember() first. If user is unsure whether a member exists, user should use HasMember() first.
A better approach is to use FindMember(). A better approach is to use FindMember().
\note Linear time complexity. \note Linear time complexity.
*/ */
GenericValue& operator[](const Ch* name) { template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {
GenericValue n(StringRef(name)); GenericValue n(StringRef(name));
return (*this)[n]; return (*this)[n];
} }
const GenericValue& operator[](const Ch* name) const { return const_cast<GenericValue&>(*this)[name]; } template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }
// This version is faster because it does not need a StrLen(). //! Get a value from an object associated with the name.
// It can also handle string with null character. /*! \pre IsObject() == true
\tparam SourceAllocator Allocator of the \c name value
\note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
And it can also handle strings with embedded null characters.
\note Linear time complexity.
*/
template <typename SourceAllocator> template <typename SourceAllocator>
GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) { GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator member = FindMember(name); MemberIterator member = FindMember(name);
@ -820,13 +853,25 @@ public:
return member->value; return member->value;
else { else {
RAPIDJSON_ASSERT(false); // see above note RAPIDJSON_ASSERT(false); // see above note
static GenericValue NullValue;
return NullValue; // This will generate -Wexit-time-destructors in clang
// static GenericValue NullValue;
// return NullValue;
// Use static buffer and placement-new to prevent destruction
static char buffer[sizeof(GenericValue)];
return *new (buffer) GenericValue();
} }
} }
template <typename SourceAllocator> template <typename SourceAllocator>
const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; } const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
#if RAPIDJSON_HAS_STDSTRING
//! Get a value from an object associated with name (string object).
GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }
const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }
#endif
//! Const member iterator //! Const member iterator
/*! \pre IsObject() == true */ /*! \pre IsObject() == true */
ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); }
@ -850,6 +895,18 @@ public:
*/ */
bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
#if RAPIDJSON_HAS_STDSTRING
//! Check whether a member exists in the object with string object.
/*!
\param name Member name to be searched.
\pre IsObject() == true
\return Whether a member with that name exists.
\note It is better to use FindMember() directly if you need the obtain the value as well.
\note Linear time complexity.
*/
bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }
#endif
//! Check whether a member exists in the object with GenericValue name. //! Check whether a member exists in the object with GenericValue name.
/*! /*!
This version is faster because it does not need a StrLen(). It can also handle string with null character. This version is faster because it does not need a StrLen(). It can also handle string with null character.
@ -906,6 +963,18 @@ public:
} }
template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); } template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
#if RAPIDJSON_HAS_STDSTRING
//! Find member by string object name.
/*!
\param name Member name to be searched.
\pre IsObject() == true
\return Iterator to member, if it exists.
Otherwise returns \ref MemberEnd().
*/
MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(StringRef(name)); }
ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(StringRef(name)); }
#endif
//! Add a member (name-value pair) to the object. //! Add a member (name-value pair) to the object.
/*! \param name A string value as name of member. /*! \param name A string value as name of member.
\param value Value of any type. \param value Value of any type.
@ -938,6 +1007,60 @@ public:
return *this; return *this;
} }
//! Add a constant string value as member (name-value pair) to the object.
/*! \param name A string value as name of member.
\param value constant string reference as value of member.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\pre IsObject()
\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
GenericValue v(value);
return AddMember(name, v, allocator);
}
#if RAPIDJSON_HAS_STDSTRING
//! Add a string object as member (name-value pair) to the object.
/*! \param name A string value as name of member.
\param value constant string reference as value of member.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\pre IsObject()
\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
GenericValue v(value, allocator);
return AddMember(name, v, allocator);
}
#endif
//! Add any primitive value as member (name-value pair) to the object.
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
\param name A string value as name of member.
\param value Value of primitive type \c T as value of member
\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\pre IsObject()
\note The source type \c T explicitly disallows all pointer types,
especially (\c const) \ref Ch*. This helps avoiding implicitly
referencing character strings with insufficient lifetime, use
\ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
AddMember(StringRefType, StringRefType, Allocator&).
All other pointer types would implicitly convert to \c bool,
use an explicit cast instead, if needed.
\note Amortized Constant time complexity.
*/
template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
AddMember(GenericValue& name, T value, Allocator& allocator) {
GenericValue v(value);
return AddMember(name, v, allocator);
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
return AddMember(name, value, allocator); return AddMember(name, value, allocator);
@ -1005,8 +1128,7 @@ public:
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
AddMember(StringRefType name, T value, Allocator& allocator) { AddMember(StringRefType name, T value, Allocator& allocator) {
GenericValue n(name); GenericValue n(name);
GenericValue v(value); return AddMember(n, value, allocator);
return AddMember(n, v, allocator);
} }
//! Remove all members in the object. //! Remove all members in the object.
@ -1023,7 +1145,9 @@ public:
//! Remove a member in object by its name. //! Remove a member in object by its name.
/*! \param name Name of member to be removed. /*! \param name Name of member to be removed.
\return Whether the member existed. \return Whether the member existed.
\note Removing member is implemented by moving the last member. So the ordering of members is changed. \note This function may reorder the object members. Use \ref
EraseMember(ConstMemberIterator) if you need to preserve the
relative order of the remaining members.
\note Linear time complexity. \note Linear time complexity.
*/ */
bool RemoveMember(const Ch* name) { bool RemoveMember(const Ch* name) {
@ -1031,6 +1155,10 @@ public:
return RemoveMember(n); return RemoveMember(n);
} }
#if RAPIDJSON_HAS_STDSTRING
bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
#endif
template <typename SourceAllocator> template <typename SourceAllocator>
bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) { bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator m = FindMember(name); MemberIterator m = FindMember(name);
@ -1045,8 +1173,9 @@ public:
//! Remove a member in object by iterator. //! Remove a member in object by iterator.
/*! \param m member iterator (obtained by FindMember() or MemberBegin()). /*! \param m member iterator (obtained by FindMember() or MemberBegin()).
\return the new iterator after removal. \return the new iterator after removal.
\note Removing member is implemented by moving the last member. So the ordering of members is changed. \note This function may reorder the object members. Use \ref
\note Use \ref EraseMember(ConstMemberIterator) instead, if you need to rely on a stable member ordering. EraseMember(ConstMemberIterator) if you need to preserve the
relative order of the remaining members.
\note Constant time complexity. \note Constant time complexity.
*/ */
MemberIterator RemoveMember(MemberIterator m) { MemberIterator RemoveMember(MemberIterator m) {
@ -1073,7 +1202,8 @@ public:
\pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
\return Iterator following the removed element. \return Iterator following the removed element.
If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
\note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members. \note This function preserves the relative order of the remaining object
members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
\note Linear time complexity. \note Linear time complexity.
*/ */
MemberIterator EraseMember(ConstMemberIterator pos) { MemberIterator EraseMember(ConstMemberIterator pos) {
@ -1085,7 +1215,8 @@ public:
\param last iterator following the last member to remove \param last iterator following the last member to remove
\pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
\return Iterator following the last removed element. \return Iterator following the last removed element.
\note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members. \note This function preserves the relative order of the remaining object
members.
\note Linear time complexity. \note Linear time complexity.
*/ */
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
@ -1099,11 +1230,36 @@ public:
MemberIterator pos = MemberBegin() + (first - MemberBegin()); MemberIterator pos = MemberBegin() + (first - MemberBegin());
for (MemberIterator itr = pos; itr != last; ++itr) for (MemberIterator itr = pos; itr != last; ++itr)
itr->~Member(); itr->~Member();
std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member)); std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
data_.o.size -= (last - first); data_.o.size -= static_cast<SizeType>(last - first);
return pos; return pos;
} }
//! Erase a member in object by its name.
/*! \param name Name of member to be removed.
\return Whether the member existed.
\note Linear time complexity.
*/
bool EraseMember(const Ch* name) {
GenericValue n(StringRef(name));
return EraseMember(n);
}
#if RAPIDJSON_HAS_STDSTRING
bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
#endif
template <typename SourceAllocator>
bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
MemberIterator m = FindMember(name);
if (m != MemberEnd()) {
EraseMember(m);
return true;
}
else
return false;
}
//@} //@}
//!@name Array //!@name Array
@ -1134,14 +1290,9 @@ public:
} }
//! Get an element from array by index. //! Get an element from array by index.
/*! \param index Zero-based index of element. /*! \pre IsArray() == true
\code \param index Zero-based index of element.
Value a(kArrayType); \see operator[](T*)
a.PushBack(123);
int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
int z = a[0u].GetInt(); // This works too.
\endcode
*/ */
GenericValue& operator[](SizeType index) { GenericValue& operator[](SizeType index) {
RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(IsArray());
@ -1172,7 +1323,7 @@ int z = a[0u].GetInt(); // This works too.
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(IsArray());
if (newCapacity > data_.a.capacity) { if (newCapacity > data_.a.capacity) {
data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); data_.a.elements = static_cast<GenericValue*>(allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)));
data_.a.capacity = newCapacity; data_.a.capacity = newCapacity;
} }
return *this; return *this;
@ -1279,8 +1430,8 @@ int z = a[0u].GetInt(); // This works too.
ValueIterator pos = Begin() + (first - Begin()); ValueIterator pos = Begin() + (first - Begin());
for (ValueIterator itr = pos; itr != last; ++itr) for (ValueIterator itr = pos; itr != last; ++itr)
itr->~GenericValue(); itr->~GenericValue();
std::memmove(pos, last, (End() - last) * sizeof(GenericValue)); std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
data_.a.size -= (last - first); data_.a.size -= static_cast<SizeType>(last - first);
return pos; return pos;
} }
@ -1299,8 +1450,8 @@ int z = a[0u].GetInt(); // This works too.
if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double
if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) if ((flags_ & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
} }
GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
@ -1364,7 +1515,7 @@ int z = a[0u].GetInt(); // This works too.
\post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
\note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
*/ */
GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), s.size(), allocator); } GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
#endif #endif
//@} //@}
@ -1387,6 +1538,7 @@ int z = a[0u].GetInt(); // This works too.
if (!handler.StartObject()) if (!handler.StartObject())
return false; return false;
for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)) if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0))
return false; return false;
if (!m->value.Accept(handler)) if (!m->value.Accept(handler))
@ -1405,17 +1557,14 @@ int z = a[0u].GetInt(); // This works too.
case kStringType: case kStringType:
return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0); return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0);
case kNumberType: default:
RAPIDJSON_ASSERT(GetType() == kNumberType);
if (IsInt()) return handler.Int(data_.n.i.i); if (IsInt()) return handler.Int(data_.n.i.i);
else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsUint()) return handler.Uint(data_.n.u.u);
else if (IsInt64()) return handler.Int64(data_.n.i64); else if (IsInt64()) return handler.Int64(data_.n.i64);
else if (IsUint64()) return handler.Uint64(data_.n.u64); else if (IsUint64()) return handler.Uint64(data_.n.u64);
else return handler.Double(data_.n.d); else return handler.Double(data_.n.d);
default:
RAPIDJSON_ASSERT(false);
} }
return false;
} }
private: private:
@ -1474,9 +1623,9 @@ private:
enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
Ch str[MaxChars]; Ch str[MaxChars];
inline static bool Usable(SizeType len) { return (MaxSize >= len); } inline static bool Usable(SizeType len) { return (MaxSize >= len); }
inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); } inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize - len); }
inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); } inline SizeType GetLength() const { return static_cast<SizeType>(MaxSize - str[LenPos]); }
}; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
// By using proper binary layout, retrieval of different integer types do not need conversions. // By using proper binary layout, retrieval of different integer types do not need conversions.
@ -1528,16 +1677,24 @@ private:
// Initialize this value as array with initial data, without calling destructor. // Initialize this value as array with initial data, without calling destructor.
void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
flags_ = kArrayFlag; flags_ = kArrayFlag;
data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); if (count) {
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); data_.a.elements = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
std::memcpy(data_.a.elements, values, count * sizeof(GenericValue));
}
else
data_.a.elements = NULL;
data_.a.size = data_.a.capacity = count; data_.a.size = data_.a.capacity = count;
} }
//! Initialize this value as object with initial data, without calling destructor. //! Initialize this value as object with initial data, without calling destructor.
void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
flags_ = kObjectFlag; flags_ = kObjectFlag;
data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); if (count) {
std::memcpy(data_.o.members, members, count * sizeof(Member)); data_.o.members = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
std::memcpy(data_.o.members, members, count * sizeof(Member));
}
else
data_.o.members = NULL;
data_.o.size = data_.o.capacity = count; data_.o.size = data_.o.capacity = count;
} }
@ -1558,7 +1715,7 @@ private:
} else { } else {
flags_ = kCopyStringFlag; flags_ = kCopyStringFlag;
data_.s.length = s.length; data_.s.length = s.length;
str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch)); str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
data_.s.str = str; data_.s.str = str;
} }
std::memcpy(str, s, s.length * sizeof(Ch)); std::memcpy(str, s, s.length * sizeof(Ch));
@ -1614,7 +1771,22 @@ public:
typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter.
//! Constructor //! Constructor
/*! \param allocator Optional allocator for allocating memory. /*! Creates an empty document of specified type.
\param type Mandatory type of object to create.
\param allocator Optional allocator for allocating memory.
\param stackCapacity Optional initial capacity of stack in bytes.
\param stackAllocator Optional allocator for allocating memory for stack.
*/
explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
{
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
}
//! Constructor
/*! Creates an empty document which type is Null.
\param allocator Optional allocator for allocating memory.
\param stackCapacity Optional initial capacity of stack in bytes. \param stackCapacity Optional initial capacity of stack in bytes.
\param stackAllocator Optional allocator for allocating memory for stack. \param stackAllocator Optional allocator for allocating memory for stack.
*/ */
@ -1622,12 +1794,80 @@ public:
allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
{ {
if (!allocator_) if (!allocator_)
ownAllocator_ = allocator_ = new Allocator(); ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
} }
~GenericDocument() { #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
delete ownAllocator_; //! Move constructor in C++11
GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
: ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_),
stack_(std::move(rhs.stack_)),
parseResult_(rhs.parseResult_)
{
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.parseResult_ = ParseResult();
} }
#endif
~GenericDocument() {
Destroy();
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move assignment in C++11
GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
{
// The cast to ValueType is necessary here, because otherwise it would
// attempt to call GenericValue's templated assignment operator.
ValueType::operator=(std::forward<ValueType>(rhs));
// Calling the destructor here would prematurely call stack_'s destructor
Destroy();
allocator_ = rhs.allocator_;
ownAllocator_ = rhs.ownAllocator_;
stack_ = std::move(rhs.stack_);
parseResult_ = rhs.parseResult_;
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.parseResult_ = ParseResult();
return *this;
}
#endif
//! Exchange the contents of this document with those of another.
/*!
\param rhs Another document.
\note Constant complexity.
\see GenericValue::Swap
*/
GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
ValueType::Swap(rhs);
stack_.Swap(rhs.stack_);
internal::Swap(allocator_, rhs.allocator_);
internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(parseResult_, rhs.parseResult_);
return *this;
}
//! free-standing swap function helper
/*!
Helper function to enable support for common swap implementation pattern based on \c std::swap:
\code
void swap(MyClass& a, MyClass& b) {
using std::swap;
swap(a.doc, b.doc);
// ...
}
\endcode
\see Swap()
*/
friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
//!@name Parse from stream //!@name Parse from stream
//!@{ //!@{
@ -1641,13 +1881,13 @@ public:
*/ */
template <unsigned parseFlags, typename SourceEncoding, typename InputStream> template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
GenericDocument& ParseStream(InputStream& is) { GenericDocument& ParseStream(InputStream& is) {
ValueType::SetNull(); // Remove existing root if exist GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator()); stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
parseResult_ = reader.template Parse<parseFlags>(is, *this); parseResult_ = reader.template Parse<parseFlags>(is, *this);
if (parseResult_) { if (parseResult_) {
RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
this->RawAssign(*stack_.template Pop<ValueType>(1)); // Add this-> to prevent issue 13. ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
} }
return *this; return *this;
} }
@ -1660,7 +1900,7 @@ public:
*/ */
template <unsigned parseFlags, typename InputStream> template <unsigned parseFlags, typename InputStream>
GenericDocument& ParseStream(InputStream& is) { GenericDocument& ParseStream(InputStream& is) {
return ParseStream<parseFlags,Encoding,InputStream>(is); return ParseStream<parseFlags, Encoding, InputStream>(is);
} }
//! Parse JSON text from an input stream (with \ref kParseDefaultFlags) //! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
@ -1677,18 +1917,6 @@ public:
//!@name Parse in-place from mutable string //!@name Parse in-place from mutable string
//!@{ //!@{
//! Parse JSON text from a mutable string (with Encoding conversion)
/*! \tparam parseFlags Combination of \ref ParseFlag.
\tparam SourceEncoding Transcoding from input Encoding
\param str Mutable zero-terminated string to be parsed.
\return The document itself for fluent API.
*/
template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& ParseInsitu(Ch* str) {
GenericInsituStringStream<Encoding> s(str);
return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(s);
}
//! Parse JSON text from a mutable string //! Parse JSON text from a mutable string
/*! \tparam parseFlags Combination of \ref ParseFlag. /*! \tparam parseFlags Combination of \ref ParseFlag.
\param str Mutable zero-terminated string to be parsed. \param str Mutable zero-terminated string to be parsed.
@ -1696,7 +1924,8 @@ public:
*/ */
template <unsigned parseFlags> template <unsigned parseFlags>
GenericDocument& ParseInsitu(Ch* str) { GenericDocument& ParseInsitu(Ch* str) {
return ParseInsitu<parseFlags, Encoding>(str); GenericInsituStringStream<Encoding> s(str);
return ParseStream<parseFlags | kParseInsituFlag>(s);
} }
//! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
@ -1704,7 +1933,7 @@ public:
\return The document itself for fluent API. \return The document itself for fluent API.
*/ */
GenericDocument& ParseInsitu(Ch* str) { GenericDocument& ParseInsitu(Ch* str) {
return ParseInsitu<kParseDefaultFlags, Encoding>(str); return ParseInsitu<kParseDefaultFlags>(str);
} }
//!@} //!@}
@ -1717,7 +1946,7 @@ public:
\param str Read-only zero-terminated string to be parsed. \param str Read-only zero-terminated string to be parsed.
*/ */
template <unsigned parseFlags, typename SourceEncoding> template <unsigned parseFlags, typename SourceEncoding>
GenericDocument& Parse(const Ch* str) { GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<SourceEncoding> s(str); GenericStringStream<SourceEncoding> s(str);
return ParseStream<parseFlags, SourceEncoding>(s); return ParseStream<parseFlags, SourceEncoding>(s);
@ -1738,16 +1967,6 @@ public:
GenericDocument& Parse(const Ch* str) { GenericDocument& Parse(const Ch* str) {
return Parse<kParseDefaultFlags>(str); return Parse<kParseDefaultFlags>(str);
} }
GenericDocument& Parse(const Ch * str, size_t sz) {
const char* buf = (const char*) str;
size_t bufsz = sz * sizeof(Ch);
MemoryStream ms(buf, bufsz);
EncodedInputStream<Encoding, MemoryStream> is(ms);
ParseStream(is);
return *this;
}
//!@} //!@}
//!@name Handling parse errors //!@name Handling parse errors
@ -1762,10 +1981,26 @@ public:
//! Get the position of last parsing error in input, 0 otherwise. //! Get the position of last parsing error in input, 0 otherwise.
size_t GetErrorOffset() const { return parseResult_.Offset(); } size_t GetErrorOffset() const { return parseResult_.Offset(); }
//! Implicit conversion to get the last parse result
#ifndef __clang // -Wdocumentation
/*! \return \ref ParseResult of the last parse operation
\code
Document doc;
ParseResult ok = doc.Parse(json);
if (!ok)
printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset());
\endcode
*/
#endif
operator ParseResult() const { return parseResult_; }
//!@} //!@}
//! Get the allocator of this document. //! Get the allocator of this document.
Allocator& GetAllocator() { return *allocator_; } Allocator& GetAllocator() {
RAPIDJSON_ASSERT(allocator_);
return *allocator_;
}
//! Get the capacity of stack in bytes. //! Get the capacity of stack in bytes.
size_t GetStackCapacity() const { return stack_.GetCapacity(); } size_t GetStackCapacity() const { return stack_.GetCapacity(); }
@ -1808,7 +2043,7 @@ private:
bool EndObject(SizeType memberCount) { bool EndObject(SizeType memberCount) {
typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount); typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());
return true; return true;
} }
@ -1821,6 +2056,8 @@ private:
} }
private: private:
//! Prohibit copying
GenericDocument(const GenericDocument&);
//! Prohibit assignment //! Prohibit assignment
GenericDocument& operator=(const GenericDocument&); GenericDocument& operator=(const GenericDocument&);
@ -1833,6 +2070,10 @@ private:
stack_.ShrinkToFit(); stack_.ShrinkToFit();
} }
void Destroy() {
RAPIDJSON_DELETE(ownAllocator_);
}
static const size_t kDefaultStackCapacity = 1024; static const size_t kDefaultStackCapacity = 1024;
Allocator* allocator_; Allocator* allocator_;
Allocator* ownAllocator_; Allocator* ownAllocator_;
@ -1849,14 +2090,40 @@ template <typename SourceAllocator>
inline inline
GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator) GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
{ {
GenericDocument<Encoding,Allocator> d(&allocator); switch (rhs.GetType()) {
rhs.Accept(d); case kObjectType:
RawAssign(*d.stack_.template Pop<GenericValue>(1)); case kArrayType: { // perform deep copy via SAX Handler
GenericDocument<Encoding,Allocator> d(&allocator);
rhs.Accept(d);
RawAssign(*d.stack_.template Pop<GenericValue>(1));
}
break;
case kStringType:
if (rhs.flags_ == kConstStringFlag) {
flags_ = rhs.flags_;
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
} else {
SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
}
break;
default:
flags_ = rhs.flags_;
data_ = *reinterpret_cast<const Data*>(&rhs.data_);
break;
}
} }
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#if defined(_MSC_VER) || defined(__GNUC__) #ifdef _MSC_VER
RAPIDJSON_DIAG_POP
#endif
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_ENCODEDSTREAM_H_ #ifndef RAPIDJSON_ENCODEDSTREAM_H_
#define RAPIDJSON_ENCODEDSTREAM_H_ #define RAPIDJSON_ENCODEDSTREAM_H_
@ -28,7 +22,12 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
namespace rapidjson { #ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Input byte stream wrapper with a statically bound encoding. //! Input byte stream wrapper with a statically bound encoding.
/*! /*!
@ -66,7 +65,7 @@ private:
//! Output byte stream wrapper with statically bound encoding. //! Output byte stream wrapper with statically bound encoding.
/*! /*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam InputByteStream Type of input byte stream. For example, FileWriteStream. \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
*/ */
template <typename Encoding, typename OutputByteStream> template <typename Encoding, typename OutputByteStream>
class EncodedOutputStream { class EncodedOutputStream {
@ -83,8 +82,8 @@ public:
void Flush() { os_.Flush(); } void Flush() { os_.Flush(); }
// Not implemented // Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); } Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
Ch Take() { RAPIDJSON_ASSERT(false); } Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
@ -115,6 +114,7 @@ public:
\param type UTF encoding type if it is not detected from the stream. \param type UTF encoding type if it is not detected from the stream.
*/ */
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
DetectType(); DetectType();
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_]; takeFunc_ = f[type_];
@ -147,11 +147,11 @@ private:
// FF FE UTF-16LE // FF FE UTF-16LE
// EF BB BF UTF-8 // EF BB BF UTF-8
const unsigned char* c = (const unsigned char *)is_->Peek4(); const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
if (!c) if (!c)
return; return;
unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
hasBOM_ = false; hasBOM_ = false;
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
@ -183,21 +183,8 @@ private:
} }
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion. // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
switch (type_) { if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
case kUTF8: if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
// Do nothing
break;
case kUTF16LE:
case kUTF16BE:
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
break;
case kUTF32LE:
case kUTF32BE:
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
break;
default:
RAPIDJSON_ASSERT(false); // Invalid type
}
} }
typedef Ch (*TakeFunc)(InputByteStream& is); typedef Ch (*TakeFunc)(InputByteStream& is);
@ -211,7 +198,7 @@ private:
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection. //! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
/*! /*!
\tparam CharType Type of character for writing. \tparam CharType Type of character for writing.
\tparam InputByteStream type of output byte stream to be wrapped. \tparam OutputByteStream type of output byte stream to be wrapped.
*/ */
template <typename CharType, typename OutputByteStream> template <typename CharType, typename OutputByteStream>
class AutoUTFOutputStream { class AutoUTFOutputStream {
@ -226,22 +213,11 @@ public:
\param putBOM Whether to write BOM at the beginning of the stream. \param putBOM Whether to write BOM at the beginning of the stream.
*/ */
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
// RUntime check whether the size of character type is sufficient. It only perform checks with assertion. RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
switch (type_) {
case kUTF16LE: // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
case kUTF16BE: if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
break;
case kUTF32LE:
case kUTF32BE:
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
break;
case kUTF8:
// Do nothing
break;
default:
RAPIDJSON_ASSERT(false); // Invalid UTFType
}
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_]; putFunc_ = f[type_];
@ -256,8 +232,8 @@ public:
void Flush() { os_->Flush(); } void Flush() { os_->Flush(); }
// Not implemented // Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); } Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
Ch Take() { RAPIDJSON_ASSERT(false); } Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
@ -281,7 +257,11 @@ private:
#undef RAPIDJSON_ENCODINGS_FUNC #undef RAPIDJSON_ENCODINGS_FUNC
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_ENCODINGS_H_ #ifndef RAPIDJSON_ENCODINGS_H_
#define RAPIDJSON_ENCODINGS_H_ #define RAPIDJSON_ENCODINGS_H_
@ -30,9 +24,10 @@ RAPIDJSON_DIAG_OFF(4702) // unreachable code
#elif defined(__GNUC__) #elif defined(__GNUC__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(overflow)
#endif #endif
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Encoding // Encoding
@ -127,17 +122,17 @@ struct UTF8 {
template <typename InputStream> template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream& is, unsigned* codepoint) {
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu) #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) #define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70) #define TAIL() COPY(); TRANS(0x70)
Ch c = is.Take(); typename InputStream::Ch c = is.Take();
if (!(c & 0x80)) { if (!(c & 0x80)) {
*codepoint = (unsigned char)c; *codepoint = static_cast<unsigned char>(c);
return true; return true;
} }
unsigned char type = GetRange((unsigned char)c); unsigned char type = GetRange(static_cast<unsigned char>(c));
*codepoint = (0xFF >> type) & (unsigned char)c; *codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
bool result = true; bool result = true;
switch (type) { switch (type) {
case 2: TAIL(); return result; case 2: TAIL(); return result;
@ -157,7 +152,7 @@ struct UTF8 {
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream& is, OutputStream& os) {
#define COPY() os.Put(c = is.Take()) #define COPY() os.Put(c = is.Take())
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) #define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70) #define TAIL() COPY(); TRANS(0x70)
Ch c; Ch c;
COPY(); COPY();
@ -165,7 +160,7 @@ struct UTF8 {
return true; return true;
bool result = true; bool result = true;
switch (GetRange((unsigned char)c)) { switch (GetRange(static_cast<unsigned char>(c))) {
case 2: TAIL(); return result; case 2: TAIL(); return result;
case 3: TAIL(); TAIL(); return result; case 3: TAIL(); TAIL(); return result;
case 4: COPY(); TRANS(0x50); TAIL(); return result; case 4: COPY(); TRANS(0x50); TAIL(); return result;
@ -201,12 +196,12 @@ struct UTF8 {
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
Ch c = Take(is); typename InputByteStream::Ch c = Take(is);
if ((unsigned char)c != 0xEFu) return c; if (static_cast<unsigned char>(c) != 0xEFu) return c;
c = is.Take(); c = is.Take();
if ((unsigned char)c != 0xBBu) return c; if (static_cast<unsigned char>(c) != 0xBBu) return c;
c = is.Take(); c = is.Take();
if ((unsigned char)c != 0xBFu) return c; if (static_cast<unsigned char>(c) != 0xBFu) return c;
c = is.Take(); c = is.Take();
return c; return c;
} }
@ -214,13 +209,15 @@ struct UTF8 {
template <typename InputByteStream> template <typename InputByteStream>
static Ch Take(InputByteStream& is) { static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return is.Take(); return static_cast<Ch>(is.Take());
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
} }
template <typename OutputByteStream> template <typename OutputByteStream>
@ -267,15 +264,15 @@ struct UTF16 {
template <typename InputStream> template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream& is, unsigned* codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
Ch c = is.Take(); typename InputStream::Ch c = is.Take();
if (c < 0xD800 || c > 0xDFFF) { if (c < 0xD800 || c > 0xDFFF) {
*codepoint = c; *codepoint = static_cast<unsigned>(c);
return true; return true;
} }
else if (c <= 0xDBFF) { else if (c <= 0xDBFF) {
*codepoint = (c & 0x3FF) << 10; *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
c = is.Take(); c = is.Take();
*codepoint |= (c & 0x3FF); *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
*codepoint += 0x10000; *codepoint += 0x10000;
return c >= 0xDC00 && c <= 0xDFFF; return c >= 0xDC00 && c <= 0xDFFF;
} }
@ -286,8 +283,8 @@ struct UTF16 {
static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
Ch c; typename InputStream::Ch c;
os.Put(c = is.Take()); os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
if (c < 0xD800 || c > 0xDFFF) if (c < 0xD800 || c > 0xDFFF)
return true; return true;
else if (c <= 0xDBFF) { else if (c <= 0xDBFF) {
@ -305,28 +302,29 @@ struct UTF16LE : UTF16<CharType> {
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return (unsigned short)c == 0xFEFFu ? Take(is) : c; return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType Take(InputByteStream& is) { static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take(); unsigned c = static_cast<uint8_t>(is.Take());
c |= (unsigned char)is.Take() << 8; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
return c; return static_cast<CharType>(c);
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFFu); os.Put(0xFEu); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) { static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
os.Put((c >> 8) & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
} }
}; };
@ -337,28 +335,29 @@ struct UTF16BE : UTF16<CharType> {
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return (unsigned short)c == 0xFEFFu ? Take(is) : c; return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType Take(InputByteStream& is) { static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take() << 8; unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
c |= (unsigned char)is.Take(); c |= static_cast<uint8_t>(is.Take());
return c; return static_cast<CharType>(c);
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFEu); os.Put(0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) { static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put((c >> 8) & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
os.Put(c & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
} }
}; };
@ -411,32 +410,35 @@ struct UTF32LE : UTF32<CharType> {
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return (unsigned)c == 0x0000FEFFu ? Take(is) : c; return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType Take(InputByteStream& is) { static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take(); unsigned c = static_cast<uint8_t>(is.Take());
c |= (unsigned char)is.Take() << 8; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
c |= (unsigned char)is.Take() << 16; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
c |= (unsigned char)is.Take() << 24; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
return c; return static_cast<CharType>(c);
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u); os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) { static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
os.Put((c >> 8) & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
os.Put((c >> 16) & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
os.Put((c >> 24) & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
} }
}; };
@ -447,32 +449,35 @@ struct UTF32BE : UTF32<CharType> {
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return (unsigned)c == 0x0000FEFFu ? Take(is) : c; return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType Take(InputByteStream& is) { static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take() << 24; unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
c |= (unsigned char)is.Take() << 16; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
c |= (unsigned char)is.Take() << 8; c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
c |= (unsigned char)is.Take(); c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
return c; return static_cast<CharType>(c);
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) { static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
} }
template <typename OutputByteStream> template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) { static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put((c >> 24) & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
os.Put((c >> 16) & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
os.Put((c >> 8) & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
os.Put(c & 0xFFu); os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
} }
}; };
@ -498,29 +503,29 @@ struct ASCII {
template <typename InputStream> template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream& is, unsigned* codepoint) {
unsigned char c = static_cast<unsigned char>(is.Take()); uint8_t c = static_cast<uint8_t>(is.Take());
*codepoint = c; *codepoint = c;
return c <= 0X7F; return c <= 0X7F;
} }
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream& is, OutputStream& os) {
unsigned char c = is.Take(); uint8_t c = static_cast<uint8_t>(is.Take());
os.Put(c); os.Put(static_cast<typename OutputStream::Ch>(c));
return c <= 0x7F; return c <= 0x7F;
} }
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
Ch c = Take(is); uint8_t c = static_cast<uint8_t>(Take(is));
return c; return static_cast<Ch>(c);
} }
template <typename InputByteStream> template <typename InputByteStream>
static Ch Take(InputByteStream& is) { static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return is.Take(); return static_cast<Ch>(is.Take());
} }
template <typename OutputByteStream> template <typename OutputByteStream>
@ -621,9 +626,9 @@ struct Transcoder<Encoding, Encoding> {
} }
}; };
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) || defined(_MSV_VER) #if defined(__GNUC__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif

View file

@ -1,29 +1,29 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_ERROR_EN_H__ #ifndef RAPIDJSON_ERROR_EN_H_
#define RAPIDJSON_ERROR_EN_H__ #define RAPIDJSON_ERROR_EN_H_
#include "error.h" #include "error.h"
namespace rapidjson { #ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum)
RAPIDJSON_DIAG_OFF(covered-switch-default)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Maps error code of parsing into error message. //! Maps error code of parsing into error message.
/*! /*!
@ -61,11 +61,14 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
default: default: return RAPIDJSON_ERROR_STRING("Unknown error.");
return RAPIDJSON_ERROR_STRING("Unknown error.");
} }
} }
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ERROR_EN_H__ #ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_ERROR_EN_H_

View file

@ -1,25 +1,26 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_ERROR_ERROR_H__ #ifndef RAPIDJSON_ERROR_ERROR_H_
#define RAPIDJSON_ERROR_ERROR_H__ #define RAPIDJSON_ERROR_ERROR_H_
#include "../rapidjson.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
/*! \file error.h */ /*! \file error.h */
@ -51,7 +52,7 @@
#define RAPIDJSON_ERROR_STRING(x) x #define RAPIDJSON_ERROR_STRING(x) x
#endif #endif
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// ParseErrorCode // ParseErrorCode
@ -85,7 +86,7 @@ enum ParseErrorCode {
kParseErrorNumberMissExponent, //!< Miss exponent in number. kParseErrorNumberMissExponent, //!< Miss exponent in number.
kParseErrorTermination, //!< Parsing was terminated. kParseErrorTermination, //!< Parsing was terminated.
kParseErrorUnspecificSyntaxError, //!< Unspecific syntax error. kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
}; };
//! Result of parsing (wraps ParseErrorCode) //! Result of parsing (wraps ParseErrorCode)
@ -103,7 +104,7 @@ enum ParseErrorCode {
\see GenericReader::Parse, GenericDocument::Parse \see GenericReader::Parse, GenericDocument::Parse
*/ */
struct ParseResult { struct ParseResult {
public:
//! Default constructor, no error. //! Default constructor, no error.
ParseResult() : code_(kParseErrorNone), offset_(0) {} ParseResult() : code_(kParseErrorNone), offset_(0) {}
//! Constructor to set an error. //! Constructor to set an error.
@ -145,6 +146,10 @@ private:
*/ */
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ERROR_ERROR_H__ #ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_ERROR_ERROR_H_

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_FILEREADSTREAM_H_ #ifndef RAPIDJSON_FILEREADSTREAM_H_
#define RAPIDJSON_FILEREADSTREAM_H_ #define RAPIDJSON_FILEREADSTREAM_H_
@ -24,7 +18,14 @@
#include "rapidjson.h" #include "rapidjson.h"
#include <cstdio> #include <cstdio>
namespace rapidjson { #ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code)
RAPIDJSON_DIAG_OFF(missing-noreturn)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! File byte stream for input using fread(). //! File byte stream for input using fread().
/*! /*!
@ -40,7 +41,7 @@ public:
\param buffer user-supplied buffer. \param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes. \param bufferSize size of buffer in bytes. Must >=4 bytes.
*/ */
FileReadStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(fp_ != 0);
RAPIDJSON_ASSERT(bufferSize >= 4); RAPIDJSON_ASSERT(bufferSize >= 4);
Read(); Read();
@ -79,7 +80,7 @@ private:
} }
} }
FILE* fp_; std::FILE* fp_;
Ch *buffer_; Ch *buffer_;
size_t bufferSize_; size_t bufferSize_;
Ch *bufferLast_; Ch *bufferLast_;
@ -89,6 +90,10 @@ private:
bool eof_; bool eof_;
}; };
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_ #endif // RAPIDJSON_FILESTREAM_H_

View file

@ -1,73 +0,0 @@
// Copyright (C) 2011 Milo Yip
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_FILESTREAM_H_
#define RAPIDJSON_FILESTREAM_H_
#include "rapidjson.h"
#include <cstdio>
namespace rapidjson {
//! (Depreciated) Wrapper of C file stream for input or output.
/*!
This simple wrapper does not check the validity of the stream.
\note implements Stream concept
\note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead.
*/
class FileStream {
public:
typedef char Ch; //!< Character type. Only support char.
FileStream(FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); }
char Peek() const { return current_; }
char Take() { char c = current_; Read(); return c; }
size_t Tell() const { return count_; }
void Put(char c) { fputc(c, fp_); }
void Flush() { fflush(fp_); }
// Not implemented
char* PutBegin() { return 0; }
size_t PutEnd(char*) { return 0; }
private:
// Prohibit copy constructor & assignment operator.
FileStream(const FileStream&);
FileStream& operator=(const FileStream&);
void Read() {
RAPIDJSON_ASSERT(fp_ != 0);
int c = fgetc(fp_);
if (c != EOF) {
current_ = (char)c;
count_++;
}
else if (current_ != '\0')
current_ = '\0';
}
FILE* fp_;
char current_;
size_t count_;
};
} // namespace rapidjson
#endif // RAPIDJSON_FILESTREAM_H_

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_FILEWRITESTREAM_H_ #ifndef RAPIDJSON_FILEWRITESTREAM_H_
#define RAPIDJSON_FILEWRITESTREAM_H_ #define RAPIDJSON_FILEWRITESTREAM_H_
@ -24,7 +18,12 @@
#include "rapidjson.h" #include "rapidjson.h"
#include <cstdio> #include <cstdio>
namespace rapidjson { #ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(unreachable-code)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of C file stream for input using fread(). //! Wrapper of C file stream for input using fread().
/*! /*!
@ -34,7 +33,7 @@ class FileWriteStream {
public: public:
typedef char Ch; //!< Character type. Only support char. typedef char Ch; //!< Character type. Only support char.
FileWriteStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(fp_ != 0);
} }
@ -63,7 +62,11 @@ public:
void Flush() { void Flush() {
if (current_ != buffer_) { if (current_ != buffer_) {
fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_); size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
if (result < static_cast<size_t>(current_ - buffer_)) {
// failure deliberately ignored at this time
// added to avoid warn_unused_result build errors
}
current_ = buffer_; current_ = buffer_;
} }
} }
@ -80,7 +83,7 @@ private:
FileWriteStream(const FileWriteStream&); FileWriteStream(const FileWriteStream&);
FileWriteStream& operator=(const FileWriteStream&); FileWriteStream& operator=(const FileWriteStream&);
FILE* fp_; std::FILE* fp_;
char *buffer_; char *buffer_;
char *bufferEnd_; char *bufferEnd_;
char *current_; char *current_;
@ -92,6 +95,10 @@ inline void PutN(FileWriteStream& stream, char c, size_t n) {
stream.PutN(c, n); stream.PutN(c, n);
} }
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_ #endif // RAPIDJSON_FILESTREAM_H_

290
external/rapidjson/internal/biginteger.h vendored Executable file
View file

@ -0,0 +1,290 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_BIGINTEGER_H_
#define RAPIDJSON_BIGINTEGER_H_
#include "../rapidjson.h"
#if defined(_MSC_VER) && defined(_M_AMD64)
#include <intrin.h> // for _umul128
#pragma intrinsic(_umul128)
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
class BigInteger {
public:
typedef uint64_t Type;
BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
}
explicit BigInteger(uint64_t u) : count_(1) {
digits_[0] = u;
}
BigInteger(const char* decimals, size_t length) : count_(1) {
RAPIDJSON_ASSERT(length > 0);
digits_[0] = 0;
size_t i = 0;
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
while (length >= kMaxDigitPerIteration) {
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
length -= kMaxDigitPerIteration;
i += kMaxDigitPerIteration;
}
if (length > 0)
AppendDecimal64(decimals + i, decimals + i + length);
}
BigInteger& operator=(const BigInteger &rhs)
{
if (this != &rhs) {
count_ = rhs.count_;
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
}
return *this;
}
BigInteger& operator=(uint64_t u) {
digits_[0] = u;
count_ = 1;
return *this;
}
BigInteger& operator+=(uint64_t u) {
Type backup = digits_[0];
digits_[0] += u;
for (size_t i = 0; i < count_ - 1; i++) {
if (digits_[i] >= backup)
return *this; // no carry
backup = digits_[i + 1];
digits_[i + 1] += 1;
}
// Last carry
if (digits_[count_ - 1] < backup)
PushBack(1);
return *this;
}
BigInteger& operator*=(uint64_t u) {
if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint64_t k = 0;
for (size_t i = 0; i < count_; i++) {
uint64_t hi;
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
k = hi;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator*=(uint32_t u) {
if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint64_t k = 0;
for (size_t i = 0; i < count_; i++) {
const uint64_t c = digits_[i] >> 32;
const uint64_t d = digits_[i] & 0xFFFFFFFF;
const uint64_t uc = u * c;
const uint64_t ud = u * d;
const uint64_t p0 = ud + k;
const uint64_t p1 = uc + (p0 >> 32);
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
k = p1 >> 32;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator<<=(size_t shift) {
if (IsZero() || shift == 0) return *this;
size_t offset = shift / kTypeBit;
size_t interShift = shift % kTypeBit;
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
if (interShift == 0) {
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
count_ += offset;
}
else {
digits_[count_] = 0;
for (size_t i = count_; i > 0; i--)
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
digits_[offset] = digits_[0] << interShift;
count_ += offset;
if (digits_[count_])
count_++;
}
std::memset(digits_, 0, offset * sizeof(Type));
return *this;
}
bool operator==(const BigInteger& rhs) const {
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
}
bool operator==(const Type rhs) const {
return count_ == 1 && digits_[0] == rhs;
}
BigInteger& MultiplyPow5(unsigned exp) {
static const uint32_t kPow5[12] = {
5,
5 * 5,
5 * 5 * 5,
5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
};
if (exp == 0) return *this;
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
if (exp > 0) *this *= kPow5[exp - 1];
return *this;
}
// Compute absolute difference of this and rhs.
// Assume this != rhs
bool Difference(const BigInteger& rhs, BigInteger* out) const {
int cmp = Compare(rhs);
RAPIDJSON_ASSERT(cmp != 0);
const BigInteger *a, *b; // Makes a > b
bool ret;
if (cmp < 0) { a = &rhs; b = this; ret = true; }
else { a = this; b = &rhs; ret = false; }
Type borrow = 0;
for (size_t i = 0; i < a->count_; i++) {
Type d = a->digits_[i] - borrow;
if (i < b->count_)
d -= b->digits_[i];
borrow = (d > a->digits_[i]) ? 1 : 0;
out->digits_[i] = d;
if (d != 0)
out->count_ = i + 1;
}
return ret;
}
int Compare(const BigInteger& rhs) const {
if (count_ != rhs.count_)
return count_ < rhs.count_ ? -1 : 1;
for (size_t i = count_; i-- > 0;)
if (digits_[i] != rhs.digits_[i])
return digits_[i] < rhs.digits_[i] ? -1 : 1;
return 0;
}
size_t GetCount() const { return count_; }
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
private:
void AppendDecimal64(const char* begin, const char* end) {
uint64_t u = ParseUint64(begin, end);
if (IsZero())
*this = u;
else {
unsigned exp = static_cast<unsigned>(end - begin);
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
}
}
void PushBack(Type digit) {
RAPIDJSON_ASSERT(count_ < kCapacity);
digits_[count_++] = digit;
}
static uint64_t ParseUint64(const char* begin, const char* end) {
uint64_t r = 0;
for (const char* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10u + static_cast<unsigned>(*p - '0');
}
return r;
}
// Assume a * b + k < 2^128
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
#if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t low = _umul128(a, b, outHigh) + k;
if (low < k)
(*outHigh)++;
return low;
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
p += k;
*outHigh = static_cast<uint64_t>(p >> 64);
return static_cast<uint64_t>(p);
#else
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
x1 += (x0 >> 32); // can't give carry
x1 += x2;
if (x1 < x2)
x3 += (static_cast<uint64_t>(1) << 32);
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
uint64_t hi = x3 + (x1 >> 32);
lo += k;
if (lo < k)
hi++;
*outHigh = hi;
return lo;
#endif
}
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
static const size_t kCapacity = kBitCount / sizeof(Type);
static const size_t kTypeBit = sizeof(Type) * 8;
Type digits_[kCapacity];
size_t count_;
};
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_BIGINTEGER_H_

258
external/rapidjson/internal/diyfp.h vendored Normal file
View file

@ -0,0 +1,258 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
#ifndef RAPIDJSON_DIYFP_H_
#define RAPIDJSON_DIYFP_H_
#include "../rapidjson.h"
#if defined(_MSC_VER) && defined(_M_AMD64)
#include <intrin.h>
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_umul128)
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
struct DiyFp {
DiyFp() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
explicit DiyFp(double d) {
union {
double d;
uint64_t u64;
} u = { d };
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0) {
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
}
else {
f = significand;
e = kDpMinExponent + 1;
}
}
DiyFp operator-(const DiyFp& rhs) const {
return DiyFp(f - rhs.f, e);
}
DiyFp operator*(const DiyFp& rhs) const {
#if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t h;
uint64_t l = _umul128(f, rhs.f, &h);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
uint64_t h = static_cast<uint64_t>(p >> 64);
uint64_t l = static_cast<uint64_t>(p);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#else
const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32;
const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
tmp += 1U << 31; /// mult_round
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
#endif
}
DiyFp Normalize() const {
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#elif defined(__GNUC__) && __GNUC__ >= 4
int s = __builtin_clzll(f);
return DiyFp(f << s, e - s);
#else
DiyFp res = *this;
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
res.f <<= 1;
res.e--;
}
return res;
#endif
}
DiyFp NormalizeBoundary() const {
DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1))) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
return res;
}
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
double ToDouble() const {
union {
double d;
uint64_t u64;
}u;
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
static_cast<uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d;
}
static const int kDiySignificandSize = 64;
static const int kDpSignificandSize = 52;
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
static const int kDpMinExponent = -kDpExponentBias;
static const int kDpDenormalExponent = -kDpExponentBias + 1;
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
uint64_t f;
int e;
};
inline DiyFp GetCachedPowerByIndex(size_t index) {
// 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = {
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
};
static const int16_t kCachedPowers_E[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
907, 933, 960, 986, 1013, 1039, 1066
};
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
inline DiyFp GetCachedPower(int e, int* K) {
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk);
if (dk - k > 0.0)
k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1);
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
return GetCachedPowerByIndex(index);
}
inline DiyFp GetCachedPower10(int exp, int *outExp) {
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
*outExp = -348 + static_cast<int>(index) * 8;
return GetCachedPowerByIndex(index);
}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#ifdef __clang__
RAPIDJSON_DIAG_POP
RAPIDJSON_DIAG_OFF(padded)
#endif
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_DIYFP_H_

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication: // This is a C++ header-only implementation of Grisu2 algorithm from the publication:
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
@ -25,16 +19,11 @@
#ifndef RAPIDJSON_DTOA_ #ifndef RAPIDJSON_DTOA_
#define RAPIDJSON_DTOA_ #define RAPIDJSON_DTOA_
#if defined(_MSC_VER)
#include <intrin.h>
#if defined(_M_AMD64)
#pragma intrinsic(_BitScanReverse64)
#endif
#endif
#include "itoa.h" // GetDigitsLut() #include "itoa.h" // GetDigitsLut()
#include "diyfp.h"
#include "ieee754.h"
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
#ifdef __GNUC__ #ifdef __GNUC__
@ -42,193 +31,6 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
struct DiyFp {
DiyFp() {}
DiyFp(uint64_t f, int e) : f(f), e(e) {}
DiyFp(double d) {
union {
double d;
uint64_t u64;
} u = { d };
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0) {
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
}
else {
f = significand;
e = kDpMinExponent + 1;
}
}
DiyFp operator-(const DiyFp& rhs) const {
return DiyFp(f - rhs.f, e);
}
DiyFp operator*(const DiyFp& rhs) const {
#if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t h;
uint64_t l = _umul128(f, rhs.f, &h);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
unsigned __int128 p = static_cast<unsigned __int128>(f) * static_cast<unsigned __int128>(rhs.f);
uint64_t h = static_cast<uint64_t>(p >> 64);
uint64_t l = static_cast<uint64_t>(p);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#else
const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32;
const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
tmp += 1U << 31; /// mult_round
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
#endif
}
DiyFp Normalize() const {
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#elif defined(__GNUC__)
int s = __builtin_clzll(f);
return DiyFp(f << s, e - s);
#else
DiyFp res = *this;
while (!(res.f & kDpHiddenBit)) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
return res;
#endif
}
DiyFp NormalizeBoundary() const {
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp (f << (63 - index), e - (63 - index));
#else
DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1))) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
return res;
#endif
}
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
static const int kDiySignificandSize = 64;
static const int kDpSignificandSize = 52;
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
static const int kDpMinExponent = -kDpExponentBias;
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
uint64_t f;
int e;
};
inline DiyFp GetCachedPower(int e, int* K) {
// 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = {
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
};
static const int16_t kCachedPowers_E[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
907, 933, 960, 986, 1013, 1039, 1066
};
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk);
if (k != dk)
k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1);
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
while (rest < wp_w && delta - rest >= ten_kappa && while (rest < wp_w && delta - rest >= ten_kappa &&
(rest + ten_kappa < wp_w || /// closer (rest + ten_kappa < wp_w || /// closer
@ -248,8 +50,10 @@ inline unsigned CountDecimalDigit32(uint32_t n) {
if (n < 1000000) return 6; if (n < 1000000) return 6;
if (n < 10000000) return 7; if (n < 10000000) return 7;
if (n < 100000000) return 8; if (n < 100000000) return 8;
if (n < 1000000000) return 9; // Will not reach 10 digits in DigitGen()
return 10; //if (n < 1000000000) return 9;
//return 10;
return 9;
} }
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
@ -258,13 +62,12 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
const DiyFp wp_w = Mp - W; const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1); uint64_t p2 = Mp.f & (one.f - 1);
int kappa = CountDecimalDigit32(p1); unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0; *len = 0;
while (kappa > 0) { while (kappa > 0) {
uint32_t d; uint32_t d = 0;
switch (kappa) { switch (kappa) {
case 10: d = p1 / 1000000000; p1 %= 1000000000; break;
case 9: d = p1 / 100000000; p1 %= 100000000; break; case 9: d = p1 / 100000000; p1 %= 100000000; break;
case 8: d = p1 / 10000000; p1 %= 10000000; break; case 8: d = p1 / 10000000; p1 %= 10000000; break;
case 7: d = p1 / 1000000; p1 %= 1000000; break; case 7: d = p1 / 1000000; p1 %= 1000000; break;
@ -274,14 +77,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
case 3: d = p1 / 100; p1 %= 100; break; case 3: d = p1 / 100; p1 %= 100; break;
case 2: d = p1 / 10; p1 %= 10; break; case 2: d = p1 / 10; p1 %= 10; break;
case 1: d = p1; p1 = 0; break; case 1: d = p1; p1 = 0; break;
default: default:;
#if defined(_MSC_VER)
__assume(0);
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
__builtin_unreachable();
#else
d = 0;
#endif
} }
if (d || *len) if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d)); buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
@ -305,7 +101,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
kappa--; kappa--;
if (p2 < delta) { if (p2 < delta) {
*K += kappa; *K += kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast<int>(kappa)]);
return; return;
} }
} }
@ -362,14 +158,14 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
else if (0 < kk && kk <= 21) { else if (0 < kk && kk <= 21) {
// 1234e-2 -> 12.34 // 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], length - kk); std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
buffer[kk] = '.'; buffer[kk] = '.';
return &buffer[length + 1]; return &buffer[length + 1];
} }
else if (-6 < kk && kk <= 0) { else if (-6 < kk && kk <= 0) {
// 1234e-6 -> 0.001234 // 1234e-6 -> 0.001234
const int offset = 2 - kk; const int offset = 2 - kk;
std::memmove(&buffer[offset], &buffer[0], length); std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
buffer[0] = '0'; buffer[0] = '0';
buffer[1] = '.'; buffer[1] = '.';
for (int i = 2; i < offset; i++) for (int i = 2; i < offset; i++)
@ -383,7 +179,7 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
else { else {
// 1234e30 -> 1.234e33 // 1234e30 -> 1.234e33
std::memmove(&buffer[2], &buffer[1], length - 1); std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
buffer[1] = '.'; buffer[1] = '.';
buffer[length + 1] = 'e'; buffer[length + 1] = 'e';
return WriteExponent(kk - 1, &buffer[0 + length + 2]); return WriteExponent(kk - 1, &buffer[0 + length + 2]);
@ -391,7 +187,10 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
inline char* dtoa(double value, char* buffer) { inline char* dtoa(double value, char* buffer) {
if (value == 0) { Double d(value);
if (d.IsZero()) {
if (d.Sign())
*buffer++ = '-'; // -0.0, Issue #289
buffer[0] = '0'; buffer[0] = '0';
buffer[1] = '.'; buffer[1] = '.';
buffer[2] = '0'; buffer[2] = '0';
@ -413,6 +212,6 @@ RAPIDJSON_DIAG_POP
#endif #endif
} // namespace internal } // namespace internal
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_DTOA_ #endif // RAPIDJSON_DTOA_

77
external/rapidjson/internal/ieee754.h vendored Normal file
View file

@ -0,0 +1,77 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_IEEE754_
#define RAPIDJSON_IEEE754_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
class Double {
public:
Double() {}
Double(double d) : d_(d) {}
Double(uint64_t u) : u_(u) {}
double Value() const { return d_; }
uint64_t Uint64Value() const { return u_; }
double NextPositiveDouble() const {
RAPIDJSON_ASSERT(!Sign());
return Double(u_ + 1).Value();
}
bool Sign() const { return (u_ & kSignMask) != 0; }
uint64_t Significand() const { return u_ & kSignificandMask; }
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
static unsigned EffectiveSignificandSize(int order) {
if (order >= -1021)
return 53;
else if (order <= -1074)
return 0;
else
return static_cast<unsigned>(order) + 1074;
}
private:
static const int kSignificandSize = 52;
static const int kExponentBias = 0x3FF;
static const int kDenormalExponent = 1 - kExponentBias;
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
union {
double d_;
uint64_t u_;
};
};
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_IEEE754_

View file

@ -1,27 +1,23 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_ITOA_ #ifndef RAPIDJSON_ITOA_
#define RAPIDJSON_ITOA_ #define RAPIDJSON_ITOA_
namespace rapidjson { #include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
inline const char* GetDigitsLut() { inline const char* GetDigitsLut() {
@ -115,12 +111,13 @@ inline char* u32toa(uint32_t value, char* buffer) {
} }
inline char* i32toa(int32_t value, char* buffer) { inline char* i32toa(int32_t value, char* buffer) {
uint32_t u = static_cast<uint32_t>(value);
if (value < 0) { if (value < 0) {
*buffer++ = '-'; *buffer++ = '-';
value = -value; u = ~u + 1;
} }
return u32toa(static_cast<uint32_t>(value), buffer); return u32toa(u, buffer);
} }
inline char* u64toa(uint64_t value, char* buffer) { inline char* u64toa(uint64_t value, char* buffer) {
@ -292,15 +289,16 @@ inline char* u64toa(uint64_t value, char* buffer) {
} }
inline char* i64toa(int64_t value, char* buffer) { inline char* i64toa(int64_t value, char* buffer) {
uint64_t u = static_cast<uint64_t>(value);
if (value < 0) { if (value < 0) {
*buffer++ = '-'; *buffer++ = '-';
value = -value; u = ~u + 1;
} }
return u64toa(static_cast<uint64_t>(value), buffer); return u64toa(u, buffer);
} }
} // namespace internal } // namespace internal
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ITOA_ #endif // RAPIDJSON_ITOA_

View file

@ -1,29 +1,21 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_INTERNAL_META_H_ #ifndef RAPIDJSON_INTERNAL_META_H_
#define RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_
#ifndef RAPIDJSON_RAPIDJSON_H_ #include "../rapidjson.h"
#error <rapidjson.h> not yet included. Do not include this file directly.
#endif
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
@ -39,7 +31,7 @@ RAPIDJSON_DIAG_OFF(6334)
#endif #endif
//@cond RAPIDJSON_INTERNAL //@cond RAPIDJSON_INTERNAL
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
@ -157,29 +149,29 @@ template <typename T> struct RemoveSfinaeTag;
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; }; template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
#define RAPIDJSON_REMOVEFPTR_(type) \ #define RAPIDJSON_REMOVEFPTR_(type) \
typename ::rapidjson::internal::RemoveSfinaeTag \ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
< ::rapidjson::internal::SfinaeTag&(*) type>::Type < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
#define RAPIDJSON_ENABLEIF(cond) \ #define RAPIDJSON_ENABLEIF(cond) \
typename ::rapidjson::internal::EnableIf \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_DISABLEIF(cond) \ #define RAPIDJSON_DISABLEIF(cond) \
typename ::rapidjson::internal::DisableIf \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
typename ::rapidjson::internal::EnableIf \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \ <RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type RAPIDJSON_REMOVEFPTR_(returntype)>::Type
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
typename ::rapidjson::internal::DisableIf \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \ <RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type RAPIDJSON_REMOVEFPTR_(returntype)>::Type
} // namespace internal } // namespace internal
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
//@endcond //@endcond
#if defined(__GNUC__) || defined(_MSC_VER) #if defined(__GNUC__) || defined(_MSC_VER)

View file

@ -1,27 +1,23 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_POW10_ #ifndef RAPIDJSON_POW10_
#define RAPIDJSON_POW10_ #define RAPIDJSON_POW10_
namespace rapidjson { #include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
//! Computes integer powers of 10 in double (10.0^n). //! Computes integer powers of 10 in double (10.0^n).
@ -54,6 +50,6 @@ inline double Pow10(int n) {
} }
} // namespace internal } // namespace internal
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_POW10_ #endif // RAPIDJSON_POW10_

View file

@ -1,27 +1,24 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_INTERNAL_STACK_H_ #ifndef RAPIDJSON_INTERNAL_STACK_H_
#define RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_
namespace rapidjson { #include "../rapidjson.h"
#include "swap.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -35,15 +32,63 @@ class Stack {
public: public:
// Optimization note: Do not allocate memory for stack_ in constructor. // Optimization note: Do not allocate memory for stack_ in constructor.
// Do it lazily when first Push() -> Expand() -> Resize(). // Do it lazily when first Push() -> Expand() -> Resize().
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
RAPIDJSON_ASSERT(stackCapacity > 0); RAPIDJSON_ASSERT(stackCapacity > 0);
if (!allocator_)
ownAllocator = allocator_ = new Allocator();
} }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack(Stack&& rhs)
: allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_),
stack_(rhs.stack_),
stackTop_(rhs.stackTop_),
stackEnd_(rhs.stackEnd_),
initialCapacity_(rhs.initialCapacity_)
{
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.stack_ = 0;
rhs.stackTop_ = 0;
rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0;
}
#endif
~Stack() { ~Stack() {
Allocator::Free(stack_); Destroy();
delete ownAllocator; // Only delete if it is owned by the stack }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack& operator=(Stack&& rhs) {
if (&rhs != this)
{
Destroy();
allocator_ = rhs.allocator_;
ownAllocator_ = rhs.ownAllocator_;
stack_ = rhs.stack_;
stackTop_ = rhs.stackTop_;
stackEnd_ = rhs.stackEnd_;
initialCapacity_ = rhs.initialCapacity_;
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.stack_ = 0;
rhs.stackTop_ = 0;
rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0;
}
return *this;
}
#endif
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
internal::Swap(allocator_, rhs.allocator_);
internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(stack_, rhs.stack_);
internal::Swap(stackTop_, rhs.stackTop_);
internal::Swap(stackEnd_, rhs.stackEnd_);
internal::Swap(initialCapacity_, rhs.initialCapacity_);
} }
void Clear() { stackTop_ = stack_; } void Clear() { stackTop_ = stack_; }
@ -87,9 +132,16 @@ public:
} }
template<typename T> template<typename T>
T* Bottom() { return (T*)stack_; } T* Bottom() { return reinterpret_cast<T*>(stack_); }
Allocator& GetAllocator() { return *allocator_; } bool HasAllocator() const {
return allocator_ != 0;
}
Allocator& GetAllocator() {
RAPIDJSON_ASSERT(allocator_);
return *allocator_;
}
bool Empty() const { return stackTop_ == stack_; } bool Empty() const { return stackTop_ == stack_; }
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); } size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); } size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
@ -99,9 +151,11 @@ private:
void Expand(size_t count) { void Expand(size_t count) {
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
size_t newCapacity; size_t newCapacity;
if (stack_ == 0) if (stack_ == 0) {
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
newCapacity = initialCapacity_; newCapacity = initialCapacity_;
else { } else {
newCapacity = GetCapacity(); newCapacity = GetCapacity();
newCapacity += (newCapacity + 1) / 2; newCapacity += (newCapacity + 1) / 2;
} }
@ -114,17 +168,22 @@ private:
void Resize(size_t newCapacity) { void Resize(size_t newCapacity) {
const size_t size = GetSize(); // Backup the current size const size_t size = GetSize(); // Backup the current size
stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity); stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
stackTop_ = stack_ + size; stackTop_ = stack_ + size;
stackEnd_ = stack_ + newCapacity; stackEnd_ = stack_ + newCapacity;
} }
void Destroy() {
Allocator::Free(stack_);
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
}
// Prohibit copy constructor & assignment operator. // Prohibit copy constructor & assignment operator.
Stack(const Stack&); Stack(const Stack&);
Stack& operator=(const Stack&); Stack& operator=(const Stack&);
Allocator* allocator_; Allocator* allocator_;
Allocator* ownAllocator; Allocator* ownAllocator_;
char *stack_; char *stack_;
char *stackTop_; char *stackTop_;
char *stackEnd_; char *stackEnd_;
@ -132,6 +191,6 @@ private:
}; };
} // namespace internal } // namespace internal
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STACK_H_ #endif // RAPIDJSON_STACK_H_

View file

@ -1,27 +1,23 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
#define RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_
namespace rapidjson { #include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
//! Custom strlen() which works on different character types. //! Custom strlen() which works on different character types.
@ -38,6 +34,6 @@ inline SizeType StrLen(const Ch* s) {
} }
} // namespace internal } // namespace internal
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ #endif // RAPIDJSON_INTERNAL_STRFUNC_H_

270
external/rapidjson/internal/strtod.h vendored Normal file
View file

@ -0,0 +1,270 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRTOD_
#define RAPIDJSON_STRTOD_
#include "../rapidjson.h"
#include "ieee754.h"
#include "biginteger.h"
#include "diyfp.h"
#include "pow10.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
inline double FastPath(double significand, int exp) {
if (exp < -308)
return 0.0;
else if (exp >= 0)
return significand * internal::Pow10(exp);
else
return significand / internal::Pow10(-exp);
}
inline double StrtodNormalPrecision(double d, int p) {
if (p < -308) {
// Prevent expSum < -308, making Pow10(p) = 0
d = FastPath(d, -308);
d = FastPath(d, p + 308);
}
else
d = FastPath(d, p);
return d;
}
template <typename T>
inline T Min3(T a, T b, T c) {
T m = a;
if (m > b) m = b;
if (m > c) m = c;
return m;
}
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
const Double db(b);
const uint64_t bInt = db.IntegerSignificand();
const int bExp = db.IntegerExponent();
const int hExp = bExp - 1;
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
// Adjust for decimal exponent
if (dExp >= 0) {
dS_Exp2 += dExp;
dS_Exp5 += dExp;
}
else {
bS_Exp2 -= dExp;
bS_Exp5 -= dExp;
hS_Exp2 -= dExp;
hS_Exp5 -= dExp;
}
// Adjust for binary exponent
if (bExp >= 0)
bS_Exp2 += bExp;
else {
dS_Exp2 -= bExp;
hS_Exp2 -= bExp;
}
// Adjust for half ulp exponent
if (hExp >= 0)
hS_Exp2 += hExp;
else {
dS_Exp2 -= hExp;
bS_Exp2 -= hExp;
}
// Remove common power of two factor from all three scaled values
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
dS_Exp2 -= common_Exp2;
bS_Exp2 -= common_Exp2;
hS_Exp2 -= common_Exp2;
BigInteger dS = d;
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
BigInteger bS(bInt);
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
BigInteger hS(1);
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
BigInteger delta(0);
dS.Difference(bS, &delta);
return delta.Compare(hS);
}
inline bool StrtodFast(double d, int p, double* result) {
// Use fast path for string-to-double conversion if possible
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
if (p > 22 && p < 22 + 16) {
// Fast Path Cases In Disguise
d *= internal::Pow10(p - 22);
p = 22;
}
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
*result = FastPath(d, p);
return true;
}
else
return false;
}
// Compute an approximation and see if it is within 1/2 ULP
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
uint64_t significand = 0;
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
for (; i < length; i++) {
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
break;
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
}
if (i < length && decimals[i] >= '5') // Rounding
significand++;
size_t remaining = length - i;
const unsigned kUlpShift = 3;
const unsigned kUlp = 1 << kUlpShift;
int error = (remaining == 0) ? 0 : kUlp / 2;
DiyFp v(significand, 0);
v = v.Normalize();
error <<= -v.e;
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
int actualExp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if (actualExp != dExp) {
static const DiyFp kPow10[] = {
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
};
int adjustment = dExp - actualExp - 1;
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
v = v * kPow10[adjustment];
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
error += kUlp / 2;
}
v = v * cachedPower;
error += kUlp + (error == 0 ? 0 : 1);
const int oldExp = v.e;
v = v.Normalize();
error <<= oldExp - v.e;
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
unsigned precisionSize = 64 - effectiveSignificandSize;
if (precisionSize + kUlpShift >= 64) {
unsigned scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp;
v.e += scaleExp;
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
precisionSize -= scaleExp;
}
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
rounded.f++;
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
rounded.f >>= 1;
rounded.e++;
}
}
*result = rounded.ToDouble();
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
}
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
const BigInteger dInt(decimals, length);
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
Double a(approx);
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
if (cmp < 0)
return a.Value(); // within half ULP
else if (cmp == 0) {
// Round towards even
if (a.Significand() & 1)
return a.NextPositiveDouble();
else
return a.Value();
}
else // adjustment
return a.NextPositiveDouble();
}
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
RAPIDJSON_ASSERT(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1);
double result;
if (StrtodFast(d, p, &result))
return result;
// Trim leading zeros
while (*decimals == '0' && length > 1) {
length--;
decimals++;
decimalPosition--;
}
// Trim trailing zeros
while (decimals[length - 1] == '0' && length > 1) {
length--;
decimalPosition--;
exp++;
}
// Trim right-most digits
const int kMaxDecimalDigit = 780;
if (static_cast<int>(length) > kMaxDecimalDigit) {
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
exp += delta;
decimalPosition -= static_cast<unsigned>(delta);
length = kMaxDecimalDigit;
}
// If too small, underflow to zero
if (int(length) + exp < -324)
return 0.0;
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
return result;
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STRTOD_

37
external/rapidjson/internal/swap.h vendored Normal file
View file

@ -0,0 +1,37 @@
// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
#define RAPIDJSON_INTERNAL_SWAP_H_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
//! Custom swap() to avoid dependency on C++ <algorithm> header
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
\note This has the same semantics as std::swap().
*/
template <typename T>
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
T tmp = a;
a = b;
b = tmp;
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_INTERNAL_SWAP_H_

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_MEMORYBUFFER_H_ #ifndef RAPIDJSON_MEMORYBUFFER_H_
#define RAPIDJSON_MEMORYBUFFER_H_ #define RAPIDJSON_MEMORYBUFFER_H_
@ -24,7 +18,7 @@
#include "rapidjson.h" #include "rapidjson.h"
#include "internal/stack.h" #include "internal/stack.h"
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
//! Represents an in-memory output byte stream. //! Represents an in-memory output byte stream.
/*! /*!
@ -71,6 +65,6 @@ inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c)); std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
} }
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_MEMORYBUFFER_H_ #endif // RAPIDJSON_MEMORYBUFFER_H_

View file

@ -1,29 +1,29 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_MEMORYSTREAM_H_ #ifndef RAPIDJSON_MEMORYSTREAM_H_
#define RAPIDJSON_MEMORYSTREAM_H_ #define RAPIDJSON_MEMORYSTREAM_H_
#include "rapidjson.h" #include "rapidjson.h"
namespace rapidjson { #ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(unreachable-code)
RAPIDJSON_DIAG_OFF(missing-noreturn)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Represents an in-memory input byte stream. //! Represents an in-memory input byte stream.
/*! /*!
@ -42,7 +42,7 @@ struct MemoryStream {
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
Ch Peek() const { return *src_; } Ch Peek() const { return (src_ == end_) ? '\0' : *src_; }
Ch Take() { return (src_ == end_) ? '\0' : *src_++; } Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - begin_); } size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
@ -62,6 +62,10 @@ struct MemoryStream {
size_t size_; //!< Size of the stream. size_t size_; //!< Size of the stream.
}; };
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_MEMORYBUFFER_H_ #endif // RAPIDJSON_MEMORYBUFFER_H_

View file

@ -30,6 +30,10 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// The above software in this distribution may have been modified by
// THL A29 Limited ("Tencent Modifications").
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
#ifndef _MSC_VER // [ #ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!" #error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ] #endif // _MSC_VER ]
@ -43,6 +47,11 @@
#include "stdint.h" #include "stdint.h"
// miloyip: VC supports inttypes.h since VC2013
#if _MSC_VER >= 1800
#include <inttypes.h>
#else
// 7.8 Format conversion of integer types // 7.8 Format conversion of integer types
typedef struct { typedef struct {
@ -302,5 +311,6 @@ imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
#define wcstoimax _wcstoi64 #define wcstoimax _wcstoi64
#define wcstoumax _wcstoui64 #define wcstoumax _wcstoui64
#endif // _MSC_VER >= 1800
#endif // _MSC_INTTYPES_H_ ] #endif // _MSC_INTTYPES_H_ ]

View file

@ -30,6 +30,10 @@
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// The above software in this distribution may have been modified by
// THL A29 Limited ("Tencent Modifications").
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
#ifndef _MSC_VER // [ #ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!" #error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ] #endif // _MSC_VER ]
@ -85,14 +89,14 @@
#include <limits.h> #include <limits.h>
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when // For Visual Studio 6 in C++ mode and for many Visual Studio versions when
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}' // compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
// or compiler give many errors like this: // or compiler would give many errors like this:
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed // error C2733: second C linkage of overloaded function 'wmemchr' not allowed
#ifdef __cplusplus #if defined(__cplusplus) && !defined(_M_ARM)
extern "C" { extern "C" {
#endif #endif
# include <wchar.h> # include <wchar.h>
#ifdef __cplusplus #if defined(__cplusplus) && !defined(_M_ARM)
} }
#endif #endif

1326
external/rapidjson/pointer.h vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_PRETTYWRITER_H_ #ifndef RAPIDJSON_PRETTYWRITER_H_
#define RAPIDJSON_PRETTYWRITER_H_ #define RAPIDJSON_PRETTYWRITER_H_
@ -28,7 +22,7 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
//! Writer with indentation and spacing. //! Writer with indentation and spacing.
/*! /*!
@ -82,6 +76,12 @@ public:
return Base::WriteString(str, length); return Base::WriteString(str, length);
} }
#if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) {
return String(str.data(), SizeType(str.size()));
}
#endif
bool StartObject() { bool StartObject() {
PrettyPrefix(kObjectType); PrettyPrefix(kObjectType);
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false); new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
@ -100,8 +100,9 @@ public:
Base::os_->Put('\n'); Base::os_->Put('\n');
WriteIndent(); WriteIndent();
} }
if (!Base::WriteEndObject()) bool ret = Base::WriteEndObject();
return false; (void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush(); Base::os_->Flush();
return true; return true;
@ -123,8 +124,9 @@ public:
Base::os_->Put('\n'); Base::os_->Put('\n');
WriteIndent(); WriteIndent();
} }
if (!Base::WriteEndArray()) bool ret = Base::WriteEndArray();
return false; (void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush(); Base::os_->Flush();
return true; return true;
@ -184,7 +186,7 @@ protected:
void WriteIndent() { void WriteIndent() {
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
PutN(*Base::os_, indentChar_, count); PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
} }
Ch indentChar_; Ch indentChar_;
@ -196,7 +198,7 @@ private:
PrettyWriter& operator=(const PrettyWriter&); PrettyWriter& operator=(const PrettyWriter&);
}; };
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP

View file

@ -1,32 +1,23 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_RAPIDJSON_H_ #ifndef RAPIDJSON_RAPIDJSON_H_
#define RAPIDJSON_RAPIDJSON_H_ #define RAPIDJSON_RAPIDJSON_H_
// Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
// Version 0.1
/*!\file rapidjson.h /*!\file rapidjson.h
\brief common definitions and configuration \brief common definitions and configuration
\see RAPIDJSON_CONFIG \see RAPIDJSON_CONFIG
*/ */
@ -48,6 +39,111 @@
#include <cstdlib> // malloc(), realloc(), free(), size_t #include <cstdlib> // malloc(), realloc(), free(), size_t
#include <cstring> // memset(), memcpy(), memmove(), memcmp() #include <cstring> // memset(), memcpy(), memmove(), memcmp()
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_VERSION_STRING
//
// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
//
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
// token stringification
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
#define RAPIDJSON_DO_STRINGIFY(x) #x
//!@endcond
/*! \def RAPIDJSON_MAJOR_VERSION
\ingroup RAPIDJSON_CONFIG
\brief Major version of RapidJSON in integer.
*/
/*! \def RAPIDJSON_MINOR_VERSION
\ingroup RAPIDJSON_CONFIG
\brief Minor version of RapidJSON in integer.
*/
/*! \def RAPIDJSON_PATCH_VERSION
\ingroup RAPIDJSON_CONFIG
\brief Patch version of RapidJSON in integer.
*/
/*! \def RAPIDJSON_VERSION_STRING
\ingroup RAPIDJSON_CONFIG
\brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
*/
#define RAPIDJSON_MAJOR_VERSION 1
#define RAPIDJSON_MINOR_VERSION 0
#define RAPIDJSON_PATCH_VERSION 2
#define RAPIDJSON_VERSION_STRING \
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NAMESPACE_(BEGIN|END)
/*! \def RAPIDJSON_NAMESPACE
\ingroup RAPIDJSON_CONFIG
\brief provide custom rapidjson namespace
In order to avoid symbol clashes and/or "One Definition Rule" errors
between multiple inclusions of (different versions of) RapidJSON in
a single binary, users can customize the name of the main RapidJSON
namespace.
In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
RAPIDJSON_NAMESPACE_END need to be defined as well:
\code
// in some .cpp file
#define RAPIDJSON_NAMESPACE my::rapidjson
#define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
#define RAPIDJSON_NAMESPACE_END } }
#include "rapidjson/..."
\endcode
\see rapidjson
*/
/*! \def RAPIDJSON_NAMESPACE_BEGIN
\ingroup RAPIDJSON_CONFIG
\brief provide custom rapidjson namespace (opening expression)
\see RAPIDJSON_NAMESPACE
*/
/*! \def RAPIDJSON_NAMESPACE_END
\ingroup RAPIDJSON_CONFIG
\brief provide custom rapidjson namespace (closing expression)
\see RAPIDJSON_NAMESPACE
*/
#ifndef RAPIDJSON_NAMESPACE
#define RAPIDJSON_NAMESPACE rapidjson
#endif
#ifndef RAPIDJSON_NAMESPACE_BEGIN
#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
#endif
#ifndef RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_NAMESPACE_END }
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_HAS_STDSTRING
#ifndef RAPIDJSON_HAS_STDSTRING
#ifdef RAPIDJSON_DOXYGEN_RUNNING
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
#else
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
#endif
/*! \def RAPIDJSON_HAS_STDSTRING
\ingroup RAPIDJSON_CONFIG
\brief Enable RapidJSON support for \c std::string
By defining this preprocessor symbol to \c 1, several convenience functions for using
\ref rapidjson::GenericValue with \c std::string are enabled, especially
for construction and comparison.
\hideinitializer
*/
#endif // !defined(RAPIDJSON_HAS_STDSTRING)
#if RAPIDJSON_HAS_STDSTRING
#include <string>
#endif // RAPIDJSON_HAS_STDSTRING
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NO_INT64DEFINE // RAPIDJSON_NO_INT64DEFINE
@ -82,9 +178,9 @@
#ifndef RAPIDJSON_FORCEINLINE #ifndef RAPIDJSON_FORCEINLINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#ifdef _MSC_VER #if defined(_MSC_VER) && !defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __forceinline #define RAPIDJSON_FORCEINLINE __forceinline
#elif defined(__GNUC__) && __GNUC__ >= 4 #elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
#else #else
#define RAPIDJSON_FORCEINLINE #define RAPIDJSON_FORCEINLINE
@ -140,6 +236,8 @@
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(_MSC_VER) && defined(_M_ARM)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(RAPIDJSON_DOXYGEN_RUNNING) # elif defined(RAPIDJSON_DOXYGEN_RUNNING)
# define RAPIDJSON_ENDIAN # define RAPIDJSON_ENDIAN
# else # else
@ -152,7 +250,7 @@
//! Whether using 64-bit architecture //! Whether using 64-bit architecture
#ifndef RAPIDJSON_64BIT #ifndef RAPIDJSON_64BIT
#if defined(__LP64__) || defined(_WIN64) #if defined(__LP64__) || defined(_WIN64) || defined(__EMSCRIPTEN__)
#define RAPIDJSON_64BIT 1 #define RAPIDJSON_64BIT 1
#else #else
#define RAPIDJSON_64BIT 0 #define RAPIDJSON_64BIT 0
@ -167,10 +265,14 @@
\param x pointer to align \param x pointer to align
Some machines require strict data alignment. Currently the default uses 4 bytes Some machines require strict data alignment. Currently the default uses 4 bytes
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro., alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.
*/ */
#ifndef RAPIDJSON_ALIGN #ifndef RAPIDJSON_ALIGN
#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u) #if RAPIDJSON_64BIT == 1
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
#else
#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
#endif
#endif #endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -238,20 +340,20 @@
#ifdef RAPIDJSON_DOXYGEN_RUNNING #ifdef RAPIDJSON_DOXYGEN_RUNNING
#define RAPIDJSON_NO_SIZETYPEDEFINE #define RAPIDJSON_NO_SIZETYPEDEFINE
#endif #endif
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
//! Size type (for string lengths, array sizes, etc.) //! Size type (for string lengths, array sizes, etc.)
/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, /*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
instead of using \c size_t. Users may override the SizeType by defining instead of using \c size_t. Users may override the SizeType by defining
\ref RAPIDJSON_NO_SIZETYPEDEFINE. \ref RAPIDJSON_NO_SIZETYPEDEFINE.
*/ */
typedef unsigned SizeType; typedef unsigned SizeType;
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif #endif
// always import std::size_t to rapidjson namespace // always import std::size_t to rapidjson namespace
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
using std::size_t; using std::size_t;
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ASSERT // RAPIDJSON_ASSERT
@ -274,13 +376,14 @@ using std::size_t;
// Adopt from boost // Adopt from boost
#ifndef RAPIDJSON_STATIC_ASSERT #ifndef RAPIDJSON_STATIC_ASSERT
#ifndef __clang__
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
namespace rapidjson { #endif
RAPIDJSON_NAMESPACE_BEGIN
template <bool x> struct STATIC_ASSERTION_FAILURE; template <bool x> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; }; template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
template<int x> struct StaticAssertTest {}; template<int x> struct StaticAssertTest {};
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) #define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) #define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
@ -291,15 +394,18 @@ template<int x> struct StaticAssertTest {};
#else #else
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif #endif
#ifndef __clang__
//!@endcond //!@endcond
#endif
/*! \def RAPIDJSON_STATIC_ASSERT /*! \def RAPIDJSON_STATIC_ASSERT
\brief (Internal) macro to check for conditions at compile-time \brief (Internal) macro to check for conditions at compile-time
\param x compile-time condition \param x compile-time condition
\hideinitializer \hideinitializer
*/ */
#define RAPIDJSON_STATIC_ASSERT(x) typedef ::rapidjson::StaticAssertTest<\ #define RAPIDJSON_STATIC_ASSERT(x) \
sizeof(::rapidjson::STATIC_ASSERTION_FAILURE<bool(x) >)>\ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif #endif
@ -316,10 +422,6 @@ template<int x> struct StaticAssertTest {};
#define RAPIDJSON_VERSION_CODE(x,y,z) \ #define RAPIDJSON_VERSION_CODE(x,y,z) \
(((x)*100000) + ((y)*100) + (z)) (((x)*100000) + ((y)*100) + (z))
// token stringification
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
#define RAPIDJSON_DO_STRINGIFY(x) #x
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
@ -367,7 +469,8 @@ template<int x> struct StaticAssertTest {};
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
#if defined(__clang__) #if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1600) (defined(_MSC_VER) && _MSC_VER >= 1600)
@ -400,14 +503,29 @@ template<int x> struct StaticAssertTest {};
//!@endcond //!@endcond
///////////////////////////////////////////////////////////////////////////////
// new/delete
#ifndef RAPIDJSON_NEW
///! customization point for global \c new
#define RAPIDJSON_NEW(x) new x
#endif
#ifndef RAPIDJSON_DELETE
///! customization point for global \c delete
#define RAPIDJSON_DELETE(x) delete x
#endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Allocators and Encodings // Allocators and Encodings
#include "allocators.h" #include "allocators.h"
#include "encodings.h" #include "encodings.h"
//! main RapidJSON namespace /*! \namespace rapidjson
namespace rapidjson { \brief main RapidJSON namespace
\see RAPIDJSON_NAMESPACE
*/
RAPIDJSON_NAMESPACE_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Stream // Stream
@ -562,6 +680,6 @@ enum Type {
kNumberType = 6 //!< number kNumberType = 6 //!< number
}; };
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_RAPIDJSON_H_ #endif // RAPIDJSON_RAPIDJSON_H_

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_READER_H_ #ifndef RAPIDJSON_READER_H_
#define RAPIDJSON_READER_H_ #define RAPIDJSON_READER_H_
@ -26,8 +20,8 @@
#include "rapidjson.h" #include "rapidjson.h"
#include "encodings.h" #include "encodings.h"
#include "internal/meta.h" #include "internal/meta.h"
#include "internal/pow10.h"
#include "internal/stack.h" #include "internal/stack.h"
#include "internal/strtod.h"
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
@ -45,6 +39,17 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
RAPIDJSON_DIAG_OFF(4702) // unreachable code RAPIDJSON_DIAG_OFF(4702) // unreachable code
#endif #endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define RAPIDJSON_NOTHING /* deliberately empty */ #define RAPIDJSON_NOTHING /* deliberately empty */
#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN #ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
@ -116,20 +121,33 @@ RAPIDJSON_DIAG_OFF(4702) // unreachable code
#include "error/error.h" // ParseErrorCode, ParseResult #include "error/error.h" // ParseErrorCode, ParseResult
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// ParseFlag // ParseFlag
/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
\ingroup RAPIDJSON_CONFIG
\brief User-defined kParseDefaultFlags definition.
User can define this as any \c ParseFlag combinations.
*/
#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags
#endif
//! Combination of parseFlags //! Combination of parseFlags
/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream /*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
*/ */
enum ParseFlag { enum ParseFlag {
kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer. kParseNoFlags = 0, //!< No flags are set.
kParseInsituFlag = 1, //!< In-situ(destructive) parsing. kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
kParseStopWhenDoneFlag = 8 //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments.
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -244,27 +262,27 @@ void SkipWhitespace(InputStream& is) {
#ifdef RAPIDJSON_SSE42 #ifdef RAPIDJSON_SSE42
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) { inline const char *SkipWhitespace_SIMD(const char* p) {
// Fast return for single non-whitespace // Fast return for single non-whitespace
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// 16-byte align to the next boundary // 16-byte align to the next boundary
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15); const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned) while (p != nextAligned)
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// The rest of string using SIMD // The rest of string using SIMD
static const char whitespace[16] = " \n\r\t"; static const char whitespace[16] = " \n\r\t";
const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
for (;; p += 16) { for (;; p += 16) {
const __m128i s = _mm_load_si128((const __m128i *)p); const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
if (r != 0) { // some of characters is non-whitespace if (r != 0) { // some of characters is non-whitespace
#ifdef _MSC_VER // Find the index of first non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace
unsigned long offset; unsigned long offset;
@ -281,39 +299,39 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) { inline const char *SkipWhitespace_SIMD(const char* p) {
// Fast return for single non-whitespace // Fast return for single non-whitespace
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// 16-byte align to the next boundary // 16-byte align to the next boundary
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & ~15); const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned) while (p != nextAligned)
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p; ++p;
else else
return p; return p;
// The rest of string // The rest of string
static const char whitespaces[4][17] = { static const char whitespaces[4][17] = {
" ", " ",
"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
for (;; p += 16) { for (;; p += 16) {
const __m128i s = _mm_load_si128((const __m128i *)p); const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
__m128i x = _mm_cmpeq_epi8(s, w0); __m128i x = _mm_cmpeq_epi8(s, w0);
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
unsigned short r = (unsigned short)~_mm_movemask_epi8(x); unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
if (r != 0) { // some of characters may be non-whitespace if (r != 0) { // some of characters may be non-whitespace
#ifdef _MSC_VER // Find the index of first non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace
unsigned long offset; unsigned long offset;
@ -365,7 +383,7 @@ public:
typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
//! Constructor. //! Constructor.
/*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
\param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
*/ */
GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
@ -387,7 +405,8 @@ public:
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (is.Peek() == '\0') { if (is.Peek() == '\0') {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
@ -398,7 +417,8 @@ public:
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (!(parseFlags & kParseStopWhenDoneFlag)) { if (!(parseFlags & kParseStopWhenDoneFlag)) {
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
if (is.Peek() != '\0') { if (is.Peek() != '\0') {
RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
@ -451,6 +471,40 @@ private:
ClearStackOnExit& operator=(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&);
}; };
template<unsigned parseFlags, typename InputStream>
void SkipWhitespaceAndComments(InputStream& is) {
SkipWhitespace(is);
if (parseFlags & kParseCommentsFlag) {
while (is.Peek() == '/') {
is.Take();
if (is.Peek() == '*') {
is.Take();
while (true) {
if (is.Peek() == '\0')
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
if (is.Take() == '*') {
if (is.Peek() == '\0')
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
if (is.Take() == '/')
break;
}
}
} else if (is.Peek() == '/') {
is.Take();
while (is.Peek() != '\0' && is.Take() != '\n') { }
} else {
RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
}
SkipWhitespace(is);
}
}
}
// Parse object: { string : value, ... } // Parse object: { string : value, ... }
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseObject(InputStream& is, Handler& handler) { void ParseObject(InputStream& is, Handler& handler) {
@ -460,7 +514,8 @@ private:
if (!handler.StartObject()) if (!handler.StartObject())
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Peek() == '}') { if (is.Peek() == '}') {
is.Take(); is.Take();
@ -476,28 +531,35 @@ private:
ParseString<parseFlags>(is, handler, true); ParseString<parseFlags>(is, handler, true);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Take() != ':') if (is.Take() != ':')
RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
ParseValue<parseFlags>(is, handler); ParseValue<parseFlags>(is, handler);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
++memberCount; ++memberCount;
switch (is.Take()) { switch (is.Take()) {
case ',': SkipWhitespace(is); break; case ',':
SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
break;
case '}': case '}':
if (!handler.EndObject(memberCount)) if (!handler.EndObject(memberCount))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
else return;
return; default:
default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell());
break;
} }
} }
} }
@ -511,7 +573,8 @@ private:
if (!handler.StartArray()) if (!handler.StartArray())
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (is.Peek() == ']') { if (is.Peek() == ']') {
is.Take(); is.Take();
@ -525,16 +588,21 @@ private:
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
++elementCount; ++elementCount;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
switch (is.Take()) { switch (is.Take()) {
case ',': SkipWhitespace(is); break; case ',':
SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
break;
case ']': case ']':
if (!handler.EndArray(elementCount)) if (!handler.EndArray(elementCount))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
else return;
return; default:
default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
break;
} }
} }
} }
@ -600,21 +668,27 @@ private:
return codepoint; return codepoint;
} }
template <typename CharType>
class StackStream { class StackStream {
public: public:
typedef typename TargetEncoding::Ch Ch; typedef CharType Ch;
StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {} StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}
RAPIDJSON_FORCEINLINE void Put(Ch c) { RAPIDJSON_FORCEINLINE void Put(Ch c) {
*stack_.template Push<Ch>() = c; *stack_.template Push<Ch>() = c;
++length_; ++length_;
} }
internal::Stack<StackAllocator>& stack_; size_t Length() const { return length_; }
SizeType length_; Ch* Pop() {
return stack_.template Pop<Ch>(length_);
}
private: private:
StackStream(const StackStream&); StackStream(const StackStream&);
StackStream& operator=(const StackStream&); StackStream& operator=(const StackStream&);
internal::Stack<StackAllocator>& stack_;
SizeType length_;
}; };
// Parse string and generate String event. Different code paths for kParseInsituFlag. // Parse string and generate String event. Different code paths for kParseInsituFlag.
@ -630,15 +704,16 @@ private:
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
size_t length = s.PutEnd(head) - 1; size_t length = s.PutEnd(head) - 1;
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head; const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
} }
else { else {
StackStream stackStream(stack_); StackStream<typename TargetEncoding::Ch> stackStream(stack_);
ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream); ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
const typename TargetEncoding::Ch* const str = stack_.template Pop<typename TargetEncoding::Ch>(stackStream.length_); SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
success = (isKey ? handler.Key(str, stackStream.length_ - 1, true) : handler.String(str, stackStream.length_ - 1, true)); const typename TargetEncoding::Ch* const str = stackStream.Pop();
success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
} }
if (!success) if (!success)
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
@ -668,16 +743,17 @@ private:
if (c == '\\') { // Escape if (c == '\\') { // Escape
is.Take(); is.Take();
Ch e = is.Take(); Ch e = is.Take();
if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) { if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[static_cast<unsigned char>(e)])
os.Put(escape[(unsigned char)e]); os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
}
else if (e == 'u') { // Unicode else if (e == 'u') { // Unicode
unsigned codepoint = ParseHex4(is); unsigned codepoint = ParseHex4(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
// Handle UTF-16 surrogate pair // Handle UTF-16 surrogate pair
if (is.Take() != '\\' || is.Take() != 'u') if (is.Take() != '\\' || is.Take() != 'u')
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
unsigned codepoint2 = ParseHex4(is); unsigned codepoint2 = ParseHex4(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2);
codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
@ -694,7 +770,7 @@ private:
} }
else if (c == '\0') else if (c == '\0')
RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1);
else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF else if (static_cast<unsigned>(c) < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1);
else { else {
if (parseFlags & kParseValidateEncodingFlag ? if (parseFlags & kParseValidateEncodingFlag ?
@ -705,22 +781,55 @@ private:
} }
} }
inline double StrtodFastPath(double significand, int exp) { template<typename InputStream, bool backup>
// Fast path only works on limited range of values. class NumberStream;
// But for simplicity and performance, currently only implement this.
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ template<typename InputStream>
if (exp < -308) class NumberStream<InputStream, false> {
return 0.0; public:
else if (exp >= 0) NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
return significand * internal::Pow10(exp); ~NumberStream() {}
else
return significand / internal::Pow10(-exp); RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
} RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
size_t Tell() { return is.Tell(); }
size_t Length() { return 0; }
const char* Pop() { return 0; }
protected:
NumberStream& operator=(const NumberStream&);
InputStream& is;
};
template<typename InputStream>
class NumberStream<InputStream, true> : public NumberStream<InputStream, false> {
typedef NumberStream<InputStream, false> Base;
public:
NumberStream(GenericReader& reader, InputStream& is) : NumberStream<InputStream, false>(reader, is), stackStream(reader.stack_) {}
~NumberStream() {}
RAPIDJSON_FORCEINLINE Ch TakePush() {
stackStream.Put(static_cast<char>(Base::is.Peek()));
return Base::is.Take();
}
size_t Length() { return stackStream.Length(); }
const char* Pop() {
stackStream.Put('\0');
return stackStream.Pop();
}
private:
StackStream<char> stackStream;
};
template<unsigned parseFlags, typename InputStream, typename Handler> template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNumber(InputStream& is, Handler& handler) { void ParseNumber(InputStream& is, Handler& handler) {
internal::StreamLocalCopy<InputStream> copy(is); internal::StreamLocalCopy<InputStream> copy(is);
InputStream& s(copy.s); NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);
// Parse minus // Parse minus
bool minus = false; bool minus = false;
@ -733,12 +842,13 @@ private:
unsigned i = 0; unsigned i = 0;
uint64_t i64 = 0; uint64_t i64 = 0;
bool use64bit = false; bool use64bit = false;
int significandDigit = 0;
if (s.Peek() == '0') { if (s.Peek() == '0') {
i = 0; i = 0;
s.Take(); s.TakePush();
} }
else if (s.Peek() >= '1' && s.Peek() <= '9') { else if (s.Peek() >= '1' && s.Peek() <= '9') {
i = static_cast<unsigned>(s.Take() - '0'); i = static_cast<unsigned>(s.TakePush() - '0');
if (minus) if (minus)
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
@ -749,7 +859,8 @@ private:
break; break;
} }
} }
i = i * 10 + static_cast<unsigned>(s.Take() - '0'); i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
significandDigit++;
} }
else else
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
@ -760,35 +871,38 @@ private:
break; break;
} }
} }
i = i * 10 + static_cast<unsigned>(s.Take() - '0'); i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
significandDigit++;
} }
} }
else else
RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
// Parse 64bit int // Parse 64bit int
double d = 0.0;
bool useDouble = false; bool useDouble = false;
double d = 0.0;
if (use64bit) { if (use64bit) {
if (minus) if (minus)
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808 if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808
if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') { if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') {
d = (double)i64; d = i64;
useDouble = true; useDouble = true;
break; break;
} }
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
significandDigit++;
} }
else else
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615 if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615
if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') { if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') {
d = (double)i64; d = i64;
useDouble = true; useDouble = true;
break; break;
} }
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
significandDigit++;
} }
} }
@ -797,53 +911,64 @@ private:
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0 if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
d = d * 10 + (s.Take() - '0'); d = d * 10 + (s.TakePush() - '0');
} }
} }
// Parse frac = decimal-point 1*DIGIT // Parse frac = decimal-point 1*DIGIT
int expFrac = 0; int expFrac = 0;
size_t decimalPosition;
if (s.Peek() == '.') { if (s.Peek() == '.') {
s.Take(); s.Take();
decimalPosition = s.Length();
if (!(s.Peek() >= '0' && s.Peek() <= '9'))
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
#if RAPIDJSON_64BIT
// Use i64 to store significand in 64-bit architecture
if (!useDouble) { if (!useDouble) {
#if RAPIDJSON_64BIT
// Use i64 to store significand in 64-bit architecture
if (!use64bit) if (!use64bit)
i64 = i; i64 = i;
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
break; break;
else { else {
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0'); i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
--expFrac; --expFrac;
if (i64 != 0)
significandDigit++;
} }
} }
d = (double)i64; d = static_cast<double>(i64);
}
#else #else
// Use double to store significand in 32-bit architecture // Use double to store significand in 32-bit architecture
if (!useDouble) d = static_cast<double>(use64bit ? i64 : i);
d = use64bit ? (double)i64 : (double)i;
#endif #endif
useDouble = true; useDouble = true;
}
while (s.Peek() >= '0' && s.Peek() <= '9') { while (s.Peek() >= '0' && s.Peek() <= '9') {
d = d * 10 + (s.Take() - '0'); if (significandDigit < 17) {
--expFrac; d = d * 10.0 + (s.TakePush() - '0');
--expFrac;
if (d > 0.0)
significandDigit++;
}
else
s.TakePush();
} }
if (expFrac == 0)
RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
} }
else
decimalPosition = s.Length(); // decimal position at the end of integer.
// Parse exp = e [ minus / plus ] 1*DIGIT // Parse exp = e [ minus / plus ] 1*DIGIT
int exp = 0; int exp = 0;
if (s.Peek() == 'e' || s.Peek() == 'E') { if (s.Peek() == 'e' || s.Peek() == 'E') {
if (!useDouble) { if (!useDouble) {
d = use64bit ? (double)i64 : (double)i; d = use64bit ? i64 : i;
useDouble = true; useDouble = true;
} }
s.Take(); s.Take();
@ -857,11 +982,23 @@ private:
} }
if (s.Peek() >= '0' && s.Peek() <= '9') { if (s.Peek() >= '0' && s.Peek() <= '9') {
exp = s.Take() - '0'; exp = static_cast<int>(s.Take() - '0');
while (s.Peek() >= '0' && s.Peek() <= '9') { if (expMinus) {
exp = exp * 10 + (s.Take() - '0'); while (s.Peek() >= '0' && s.Peek() <= '9') {
if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first. exp = exp * 10 + static_cast<int>(s.Take() - '0');
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); if (exp >= 214748364) { // Issue #313: prevent overflow exponent
while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent
s.Take();
}
}
}
else { // positive exp
int maxExp = 308 - expFrac;
while (s.Peek() >= '0' && s.Peek() <= '9') {
exp = exp * 10 + static_cast<int>(s.Take() - '0');
if (exp > maxExp)
RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell());
}
} }
} }
else else
@ -873,28 +1010,28 @@ private:
// Finish parsing, call event according to the type of number. // Finish parsing, call event according to the type of number.
bool cont = true; bool cont = true;
size_t length = s.Length();
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
if (useDouble) { if (useDouble) {
int expSum = exp + expFrac; int p = exp + expFrac;
if (expSum < -308) { if (parseFlags & kParseFullPrecisionFlag)
// Prevent expSum < -308, making Pow10(expSum) = 0 d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
d = StrtodFastPath(d, exp);
d = StrtodFastPath(d, expFrac);
}
else else
d = StrtodFastPath(d, expSum); d = internal::StrtodNormalPrecision(d, p);
cont = handler.Double(minus ? -d : d); cont = handler.Double(minus ? -d : d);
} }
else { else {
if (use64bit) { if (use64bit) {
if (minus) if (minus)
cont = handler.Int64(-(int64_t)i64); cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
else else
cont = handler.Uint64(i64); cont = handler.Uint64(i64);
} }
else { else {
if (minus) if (minus)
cont = handler.Int(-(int)i); cont = handler.Int(static_cast<int32_t>(~i + 1));
else else
cont = handler.Uint(i); cont = handler.Uint(i);
} }
@ -913,7 +1050,10 @@ private:
case '"': ParseString<parseFlags>(is, handler); break; case '"': ParseString<parseFlags>(is, handler); break;
case '{': ParseObject<parseFlags>(is, handler); break; case '{': ParseObject<parseFlags>(is, handler); break;
case '[': ParseArray <parseFlags>(is, handler); break; case '[': ParseArray <parseFlags>(is, handler); break;
default : ParseNumber<parseFlags>(is, handler); default :
ParseNumber<parseFlags>(is, handler);
break;
} }
} }
@ -940,11 +1080,11 @@ private:
IterativeParsingArrayFinishState, IterativeParsingArrayFinishState,
// Single value state // Single value state
IterativeParsingValueState, IterativeParsingValueState
cIterativeParsingStateCount
}; };
enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
// Tokens // Tokens
enum Token { enum Token {
LeftBracketToken = 0, LeftBracketToken = 0,
@ -986,8 +1126,8 @@ private:
#undef N16 #undef N16
//!@endcond //!@endcond
if (sizeof(Ch) == 1 || unsigned(c) < 256) if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
return (Token)tokenMap[(unsigned char)c]; return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
else else
return NumberToken; return NumberToken;
} }
@ -1153,21 +1293,16 @@ private:
} }
}; // End of G }; // End of G
return (IterativeParsingState)G[state][token]; return static_cast<IterativeParsingState>(G[state][token]);
} }
// Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
// May return a new state on state pop. // May return a new state on state pop.
template <unsigned parseFlags, typename InputStream, typename Handler> template <unsigned parseFlags, typename InputStream, typename Handler>
RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {
(void)token;
switch (dst) { switch (dst) {
case IterativeParsingStartState:
RAPIDJSON_ASSERT(false);
return IterativeParsingErrorState;
case IterativeParsingFinishState:
return dst;
case IterativeParsingErrorState: case IterativeParsingErrorState:
return dst; return dst;
@ -1206,12 +1341,9 @@ private:
return dst; return dst;
case IterativeParsingKeyValueDelimiterState: case IterativeParsingKeyValueDelimiterState:
if (token == ColonToken) { RAPIDJSON_ASSERT(token == ColonToken);
is.Take(); is.Take();
return dst; return dst;
}
else
return IterativeParsingErrorState;
case IterativeParsingMemberValueState: case IterativeParsingMemberValueState:
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
@ -1286,17 +1418,25 @@ private:
} }
} }
case IterativeParsingValueState: default:
// This branch is for IterativeParsingValueState actually.
// Use `default:` rather than
// `case IterativeParsingValueState:` is for code coverage.
// The IterativeParsingStartState is not enumerated in this switch-case.
// It is impossible for that case. And it can be caught by following assertion.
// The IterativeParsingFinishState is not enumerated in this switch-case either.
// It is a "derivative" state which cannot triggered from Predict() directly.
// Therefore it cannot happen here. And it can be caught by following assertion.
RAPIDJSON_ASSERT(dst == IterativeParsingValueState);
// Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
ParseValue<parseFlags>(is, handler); ParseValue<parseFlags>(is, handler);
if (HasParseError()) { if (HasParseError()) {
return IterativeParsingErrorState; return IterativeParsingErrorState;
} }
return IterativeParsingFinishState; return IterativeParsingFinishState;
default:
RAPIDJSON_ASSERT(false);
return IterativeParsingErrorState;
} }
} }
@ -1308,14 +1448,14 @@ private:
} }
switch (src) { switch (src) {
case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
case IterativeParsingObjectInitialState: case IterativeParsingObjectInitialState:
case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); return;
} }
} }
@ -1325,7 +1465,8 @@ private:
ClearStackOnExit scope(*this); ClearStackOnExit scope(*this);
IterativeParsingState state = IterativeParsingStartState; IterativeParsingState state = IterativeParsingStartState;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
while (is.Peek() != '\0') { while (is.Peek() != '\0') {
Token t = Tokenize(is.Peek()); Token t = Tokenize(is.Peek());
IterativeParsingState n = Predict(state, t); IterativeParsingState n = Predict(state, t);
@ -1342,7 +1483,8 @@ private:
if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
break; break;
SkipWhitespace(is); SkipWhitespaceAndComments<parseFlags>(is);
RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
} }
// Handle the end of file. // Handle the end of file.
@ -1360,7 +1502,16 @@ private:
//! Reader with UTF8 encoding and default allocator. //! Reader with UTF8 encoding and default allocator.
typedef GenericReader<UTF8<>, UTF8<> > Reader; typedef GenericReader<UTF8<>, UTF8<> > Reader;
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP

View file

@ -1,30 +1,29 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_STRINGBUFFER_H_ #ifndef RAPIDJSON_STRINGBUFFER_H_
#define RAPIDJSON_STRINGBUFFER_H_ #define RAPIDJSON_STRINGBUFFER_H_
#include "rapidjson.h" #include "rapidjson.h"
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#include <utility> // std::move
#endif
#include "internal/stack.h" #include "internal/stack.h"
namespace rapidjson { RAPIDJSON_NAMESPACE_BEGIN
//! Represents an in-memory output stream. //! Represents an in-memory output stream.
/*! /*!
@ -33,11 +32,21 @@ namespace rapidjson {
\note implements Stream concept \note implements Stream concept
*/ */
template <typename Encoding, typename Allocator = CrtAllocator> template <typename Encoding, typename Allocator = CrtAllocator>
struct GenericStringBuffer { class GenericStringBuffer {
public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
if (&rhs != this)
stack_ = std::move(rhs.stack_);
return *this;
}
#endif
void Put(Ch c) { *stack_.template Push<Ch>() = c; } void Put(Ch c) { *stack_.template Push<Ch>() = c; }
void Flush() {} void Flush() {}
@ -63,6 +72,11 @@ struct GenericStringBuffer {
static const size_t kDefaultCapacity = 256; static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_; mutable internal::Stack<Allocator> stack_;
private:
// Prohibit copy constructor & assignment operator.
GenericStringBuffer(const GenericStringBuffer&);
GenericStringBuffer& operator=(const GenericStringBuffer&);
}; };
//! String buffer with UTF8 encoding //! String buffer with UTF8 encoding
@ -74,6 +88,6 @@ inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c)); std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
} }
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STRINGBUFFER_H_ #endif // RAPIDJSON_STRINGBUFFER_H_

View file

@ -1,22 +1,16 @@
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_WRITER_H_ #ifndef RAPIDJSON_WRITER_H_
#define RAPIDJSON_WRITER_H_ #define RAPIDJSON_WRITER_H_
@ -34,7 +28,12 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
#endif #endif
namespace rapidjson { #ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! JSON writer //! JSON writer
/*! Writer implements the concept Handler. /*! Writer implements the concept Handler.
@ -59,12 +58,14 @@ public:
//! Constructor //! Constructor
/*! \param os Output stream. /*! \param os Output stream.
\param allocator User supplied allocator. If it is null, it will create a private one. \param stackAllocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of stack. \param levelDepth Initial capacity of stack.
*/ */
explicit
Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {} os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
explicit
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {} os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
@ -125,6 +126,12 @@ public:
return WriteString(str, length); return WriteString(str, length);
} }
#if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) {
return String(str.data(), SizeType(str.size()));
}
#endif
bool StartObject() { bool StartObject() {
Prefix(kObjectType); Prefix(kObjectType);
new (level_stack_.template Push<Level>()) Level(false); new (level_stack_.template Push<Level>()) Level(false);
@ -199,7 +206,7 @@ protected:
char buffer[11]; char buffer[11];
const char* end = internal::i32toa(i, buffer); const char* end = internal::i32toa(i, buffer);
for (const char* p = buffer; p != end; ++p) for (const char* p = buffer; p != end; ++p)
os_->Put(*p); os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
return true; return true;
} }
@ -207,7 +214,7 @@ protected:
char buffer[10]; char buffer[10];
const char* end = internal::u32toa(u, buffer); const char* end = internal::u32toa(u, buffer);
for (const char* p = buffer; p != end; ++p) for (const char* p = buffer; p != end; ++p)
os_->Put(*p); os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
return true; return true;
} }
@ -215,7 +222,7 @@ protected:
char buffer[21]; char buffer[21];
const char* end = internal::i64toa(i64, buffer); const char* end = internal::i64toa(i64, buffer);
for (const char* p = buffer; p != end; ++p) for (const char* p = buffer; p != end; ++p)
os_->Put(*p); os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
return true; return true;
} }
@ -223,7 +230,7 @@ protected:
char buffer[20]; char buffer[20];
char* end = internal::u64toa(u64, buffer); char* end = internal::u64toa(u64, buffer);
for (char* p = buffer; p != end; ++p) for (char* p = buffer; p != end; ++p)
os_->Put(*p); os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
return true; return true;
} }
@ -231,12 +238,12 @@ protected:
char buffer[25]; char buffer[25];
char* end = internal::dtoa(d, buffer); char* end = internal::dtoa(d, buffer);
for (char* p = buffer; p != end; ++p) for (char* p = buffer; p != end; ++p)
os_->Put(*p); os_->Put(static_cast<typename TargetEncoding::Ch>(*p));
return true; return true;
} }
bool WriteString(const Ch* str, SizeType length) { bool WriteString(const Ch* str, SizeType length) {
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
static const char escape[256] = { static const char escape[256] = {
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
//0 1 2 3 4 5 6 7 8 9 A B C D E F //0 1 2 3 4 5 6 7 8 9 A B C D E F
@ -253,7 +260,7 @@ protected:
GenericStringStream<SourceEncoding> is(str); GenericStringStream<SourceEncoding> is(str);
while (is.Tell() < length) { while (is.Tell() < length) {
const Ch c = is.Peek(); const Ch c = is.Peek();
if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) { if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
// Unicode escaping // Unicode escaping
unsigned codepoint; unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint)) if (!SourceEncoding::Decode(is, &codepoint))
@ -266,7 +273,8 @@ protected:
os_->Put(hexDigits[(codepoint >> 4) & 15]); os_->Put(hexDigits[(codepoint >> 4) & 15]);
os_->Put(hexDigits[(codepoint ) & 15]); os_->Put(hexDigits[(codepoint ) & 15]);
} }
else if (codepoint >= 0x010000 && codepoint <= 0x10FFFF) { else {
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
// Surrogate pair // Surrogate pair
unsigned s = codepoint - 0x010000; unsigned s = codepoint - 0x010000;
unsigned lead = (s >> 10) + 0xD800; unsigned lead = (s >> 10) + 0xD800;
@ -282,22 +290,21 @@ protected:
os_->Put(hexDigits[(trail >> 4) & 15]); os_->Put(hexDigits[(trail >> 4) & 15]);
os_->Put(hexDigits[(trail ) & 15]); os_->Put(hexDigits[(trail ) & 15]);
} }
else
return false; // invalid code point
} }
else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && escape[static_cast<unsigned char>(c)]) {
is.Take(); is.Take();
os_->Put('\\'); os_->Put('\\');
os_->Put(escape[(unsigned char)c]); os_->Put(static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
if (escape[(unsigned char)c] == 'u') { if (escape[static_cast<unsigned char>(c)] == 'u') {
os_->Put('0'); os_->Put('0');
os_->Put('0'); os_->Put('0');
os_->Put(hexDigits[(unsigned char)c >> 4]); os_->Put(hexDigits[static_cast<unsigned char>(c) >> 4]);
os_->Put(hexDigits[(unsigned char)c & 0xF]); os_->Put(hexDigits[static_cast<unsigned char>(c) & 0xF]);
} }
} }
else else
Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_); if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))
return false;
} }
os_->Put('\"'); os_->Put('\"');
return true; return true;
@ -344,7 +351,7 @@ template<>
inline bool Writer<StringBuffer>::WriteInt(int i) { inline bool Writer<StringBuffer>::WriteInt(int i) {
char *buffer = os_->Push(11); char *buffer = os_->Push(11);
const char* end = internal::i32toa(i, buffer); const char* end = internal::i32toa(i, buffer);
os_->Pop(11 - (end - buffer)); os_->Pop(static_cast<size_t>(11 - (end - buffer)));
return true; return true;
} }
@ -352,7 +359,7 @@ template<>
inline bool Writer<StringBuffer>::WriteUint(unsigned u) { inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
char *buffer = os_->Push(10); char *buffer = os_->Push(10);
const char* end = internal::u32toa(u, buffer); const char* end = internal::u32toa(u, buffer);
os_->Pop(10 - (end - buffer)); os_->Pop(static_cast<size_t>(10 - (end - buffer)));
return true; return true;
} }
@ -360,7 +367,7 @@ template<>
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) { inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
char *buffer = os_->Push(21); char *buffer = os_->Push(21);
const char* end = internal::i64toa(i64, buffer); const char* end = internal::i64toa(i64, buffer);
os_->Pop(21 - (end - buffer)); os_->Pop(static_cast<size_t>(21 - (end - buffer)));
return true; return true;
} }
@ -368,7 +375,7 @@ template<>
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) { inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
char *buffer = os_->Push(20); char *buffer = os_->Push(20);
const char* end = internal::u64toa(u, buffer); const char* end = internal::u64toa(u, buffer);
os_->Pop(20 - (end - buffer)); os_->Pop(static_cast<size_t>(20 - (end - buffer)));
return true; return true;
} }
@ -376,14 +383,18 @@ template<>
inline bool Writer<StringBuffer>::WriteDouble(double d) { inline bool Writer<StringBuffer>::WriteDouble(double d) {
char *buffer = os_->Push(25); char *buffer = os_->Push(25);
char* end = internal::dtoa(d, buffer); char* end = internal::dtoa(d, buffer);
os_->Pop(25 - (end - buffer)); os_->Pop(static_cast<size_t>(25 - (end - buffer)));
return true; return true;
} }
} // namespace rapidjson RAPIDJSON_NAMESPACE_END
#ifdef _MSC_VER #ifdef _MSC_VER
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_RAPIDJSON_H_ #endif // RAPIDJSON_RAPIDJSON_H_

View file

@ -894,7 +894,7 @@ void wallet2::load_keys(const std::string& keys_file_name, const std::string& pa
// The contents should be JSON if the wallet follows the new format. // The contents should be JSON if the wallet follows the new format.
rapidjson::Document json; rapidjson::Document json;
if (json.Parse(account_data.c_str(), keys_file_data.account_data.size()).HasParseError()) if (json.Parse(account_data.c_str()).HasParseError())
{ {
is_old_file_format = true; is_old_file_format = true;
m_watch_only = false; m_watch_only = false;
@ -972,7 +972,7 @@ bool wallet2::verify_password(const std::string& password) const
// The contents should be JSON if the wallet follows the new format. // The contents should be JSON if the wallet follows the new format.
rapidjson::Document json; rapidjson::Document json;
if (json.Parse(account_data.c_str(), keys_file_data.account_data.size()).HasParseError()) if (json.Parse(account_data.c_str()).HasParseError())
{ {
// old format before JSON wallet key file format // old format before JSON wallet key file format
} }