Compare commits
32
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa98b6b94c | ||
|
|
1d2eb7a8d2 | ||
|
|
fa65627150 | ||
|
|
0e293b57b8 | ||
|
|
954cd02724 | ||
|
|
cd42d5a38b | ||
|
|
32cc34b0d5 | ||
|
|
cbc533dd63 | ||
|
|
997f87303e | ||
|
|
bb4bca56fb | ||
|
|
1c07710e8e | ||
|
|
b1f370cd56 | ||
|
|
3e500e64bf | ||
|
|
2d5c52acd5 | ||
|
|
658ddb53f2 | ||
|
|
3172c8ff23 | ||
|
|
2c00eb0c44 | ||
|
|
cb4a92bd4b | ||
|
|
5f31ee7019 | ||
|
|
49d91518ae | ||
|
|
e6dea62c32 | ||
|
|
f29077d926 | ||
|
|
24ebfae73b | ||
|
|
5bddbc5008 | ||
|
|
f06ce5a58e | ||
|
|
81bd4b0237 | ||
|
|
8f9ad51172 | ||
|
|
8ded925717 | ||
|
|
c1453e09a4 | ||
|
|
859c8282ea | ||
|
|
c17ceea043 | ||
|
|
791eec9d8c |
@@ -1,3 +0,0 @@
|
||||
/bin
|
||||
/lib
|
||||
/build
|
||||
@@ -722,6 +722,15 @@ version if BRLCAD_BUNDLED_LIBS is also AUTO.
|
||||
Aliases: ENABLE_SPR
|
||||
|
||||
|
||||
--- BRLCAD_BSON ---
|
||||
|
||||
Option for enabling and disabling compilation of the Libbson library
|
||||
provided with BRL-CAD's source code. Default is BUNDLED, using
|
||||
the included other/src version.
|
||||
|
||||
Aliases: ENABLE_BSON
|
||||
|
||||
|
||||
--- BRLCAD_SC ---
|
||||
|
||||
Option for enabling and disabling compilation of the NIST Step Class
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
branch/binary-attributes
|
||||
========================
|
||||
|
||||
To turn on the use of binary attributes define:
|
||||
|
||||
USE_BINARY_ATTRIBUTES
|
||||
|
||||
E.g., prior to running CMake:
|
||||
|
||||
export CFLAGS=-DUSE_BINARY_ATTRIBUTES
|
||||
export CXXFLAGS=-DUSE_BINARY_ATTRIBUTES
|
||||
|
||||
external code added:
|
||||
-------------------
|
||||
|
||||
BSON
|
||||
specification: http://bsonspec.org/spec.html
|
||||
libbson source: https://github.com/mongodb/libbson
|
||||
current release tarball: https://github.com/mongodb/libbson/releases/
|
||||
libbson-1.3.0-beta0.tar.gz
|
||||
converter: libbson has tools included to convert BSON to/from JSON
|
||||
|
||||
Scheme
|
||||
------
|
||||
|
||||
The BRL-CAD V5 database seems to allow an arbitrary binary chunk
|
||||
following the ASCII attributes. The idea is to define the total
|
||||
attribute chunk length to include any desired binary objects. The
|
||||
read or write (RW) of the ASCII attributes stops with the char* RW of
|
||||
a double NULL which should be a sufficient stop RW mark. Then, any
|
||||
difference in length read versus attribute chunk length is the length
|
||||
of a chunk of binary attributes (BAs) which we will define as a BSON
|
||||
collection of BSON documents (??? check BSON terminology). At that
|
||||
point we use libbson to RW the BAs.
|
||||
|
||||
As a minumum, a BA must have an ASCII key and a binary value.
|
||||
Following the BSON specification, the user can add other objects in
|
||||
the BA if desired.
|
||||
|
||||
The user interface relies on AVS handling which will have to also
|
||||
handle the BAs (that appears to be doable). Our best practice should
|
||||
encourage (maybe require?) a BA to have a short ASCII comment.
|
||||
|
||||
We will need appropriate functions to convert BAs to/from AVS
|
||||
objects. In the course of developing the BA capability we will add a
|
||||
file IO scheme for users to manipulate the BAs.
|
||||
|
||||
User interface (mged)
|
||||
---------------------
|
||||
|
||||
Current attr usage
|
||||
******************
|
||||
|
||||
mged> attr
|
||||
Usage: attr {[-c sep_char] set|get|show|rm|append|sort|list} object [key [value] ... ]
|
||||
|
||||
Proposed attr usage
|
||||
*******************
|
||||
|
||||
mged> attr
|
||||
Usage: attr {[-c sep_char][-b] set|get|show|rm|append|sort|list} object [key [value] ... ]
|
||||
|
||||
Where the '-b', indicating a binary attribute (BA), works with 'get'
|
||||
and 'set' only (and ignored for the other commands).
|
||||
|
||||
Note that 'set' and 'get' for binary attributes require an external
|
||||
file name (which must must be a valid JSON file for 'set') and must
|
||||
NOT exist for 'get'. The 'append' command will NOT work for a BA.
|
||||
|
||||
The 'show', 'sort', and 'list' commands will show for BAs their key
|
||||
followed by followed by '(binary)' followed by their comment string,
|
||||
if it exists (we should make that mandatory I believe). The 'rm'
|
||||
command will remove the BA referenced by the key.
|
||||
|
||||
The BAs will have both a key and a comment, and it is an error to try
|
||||
to add a BA with a key the same as an existing key.
|
||||
|
||||
Tentative JSON format of a BA
|
||||
-----------------------------
|
||||
|
||||
(See http://www.json.org/ for the JSON specification.)
|
||||
|
||||
Functions needed
|
||||
----------------
|
||||
|
||||
JSON BA to/from in-memory AVS
|
||||
see current functions:
|
||||
|
||||
AVS BA to/from on-disk attribute body
|
||||
see current functions:
|
||||
|
||||
...
|
||||
|
||||
Macro definitions needed
|
||||
------------------------
|
||||
|
||||
Data structures needed
|
||||
----------------------
|
||||
|
||||
Other notes
|
||||
-----------
|
||||
Files affected:
|
||||
|
||||
./include/bu/parse.h
|
||||
./include/bu/avs.h
|
||||
./src/librt/db5_io.c
|
||||
./src/librt/attributes.c
|
||||
|
||||
Features to be implemented and other considerations:
|
||||
|
||||
+ add a binary attribute using similar syntax as a string attribute
|
||||
+ a binary attribute should have an optional description field
|
||||
+ implement auto update of an object's ctime (creation time) and
|
||||
mtime (last modification)
|
||||
+ mtime and ctime should be 64-bit integers (based on Unix time and
|
||||
epoch) (int64_t; see src/libbu/y2038/time64_config.h)
|
||||
+ binary attributes should be able to be entered from or output to a
|
||||
file
|
||||
|
||||
A db admin tool:
|
||||
|
||||
./src/util/db-admin-tool.cpp
|
||||
|
||||
On-disk format of a binary attribute [following the (char*)NULL
|
||||
(char*)NULL end of the normal attributes]:
|
||||
|
||||
While I believe we can use the existing AVS attribute section for BAs,
|
||||
I believe in the future we ought to create a separate object structure
|
||||
section for binary attributes, especially if we use a more compact
|
||||
binary representation such as CBOR.
|
||||
|
||||
The following describes the current V5 db:
|
||||
|
||||
BRL_CAD_g_format_V5.xml
|
||||
|
||||
The following describes the proposed V6 db with the binary attributes:
|
||||
|
||||
BRL_CAD_g_format_V6.xml
|
||||
|
||||
|
||||
Possible tests:
|
||||
|
||||
1. Simple TGM
|
||||
+ create a single-object TGM
|
||||
+ copy the TGM to a new file (TGM2)
|
||||
+ add multiple binary attributes to TGM2
|
||||
+ add a file to TGM2
|
||||
+ use the admin-db tool to check TGM2
|
||||
+ export the file; check that it is the same as was imported
|
||||
+ delete the added binary attributes from TGM2
|
||||
+ run cmp on TGM and TGM2 to see they are the same
|
||||
|
||||
2. Complex TGM
|
||||
+ select a complex TGM in the db directory as a test subject
|
||||
+ copy the TGM to a new file (TGM2)
|
||||
+ add multiple binary attributes to TGM2
|
||||
+ add a file to TGM2
|
||||
+ use the admin-db tool to check TGM2
|
||||
+ export the file; check that it is the same as was imported
|
||||
+ delete the added binary attributes from TGM2
|
||||
+ run cmp on TGM and TGM2 to see they are the same
|
||||
|
||||
See the TODO file, sections "ATTRIBUTES" and "THESE BREAK PROTOCOL OR
|
||||
ARE BACKWARDS-INCOMPATIBLE" for more official information.
|
||||
@@ -190,6 +190,10 @@ do
|
||||
shift;;
|
||||
--disable-spr) options="$options -DBRLCAD_SPR=SYSTEM";
|
||||
shift;;
|
||||
--enable-bson) options="$options -DBRLCAD_BSON=BUNDLED";
|
||||
shift;;
|
||||
--disable-bson) options="$options -DBRLCAD_BSON=SYSTEM";
|
||||
shift;;
|
||||
--enable-scl) options="$options -DBRLCAD_SC=BUNDLED";
|
||||
shift;;
|
||||
--disable-scl) options="$options -DBRLCAD_SC=SYSTEM";
|
||||
|
||||
@@ -92,8 +92,8 @@
|
||||
are combined using boolean operations to form regions of homogeneous material.
|
||||
</para>
|
||||
<para>
|
||||
The database is organized as a <emphasis>directed acyclic graph</emphasis> (DAG), which
|
||||
comprises
|
||||
The database is organized as a <emphasis>directed acyclic graph</emphasis> (DAG), which is
|
||||
comprised of:
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
@@ -107,7 +107,7 @@
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>arcs</emphasis> - contain boolean operators and 4x4 homogeneous transformation matrices.</para>
|
||||
<para><emphasis>arcs</emphasis> - containing boolean operators and 4x4 homogeneous transformation matrices.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
@@ -1600,14 +1600,6 @@
|
||||
place of anameN+1 signals the end of the ASCII attribute data.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
PROPOSED: A second type of attribute has an ASCII key but a binary value.
|
||||
Such attributes follow the ASCII-valued ones after the double NULLs:
|
||||
<literallayout class="normal">anameN+1 NULL uintN <uintN binary bytes> [...0 or more binary attribute pairs]</literallayout>
|
||||
where, for each binary attribute pair, the uintN is of size AWid and is
|
||||
the length of the binary value for its ASCII key.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Every object in the database may have zero or more attributes
|
||||
attached to it; the meaning of these attributes will vary
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,6 +29,10 @@
|
||||
#include "bu/magic.h"
|
||||
#include "bu/vls.h"
|
||||
|
||||
#if defined(USE_BINARY_ATTRIBUTES)
|
||||
#include "bson.h"
|
||||
#endif
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
@@ -3,6 +3,8 @@ set(BU_INCLUDE_DIRS
|
||||
${BRLCAD_BINARY_DIR}/include
|
||||
${BRLCAD_SOURCE_DIR}/include
|
||||
${TCL_INCLUDE_DIRS}
|
||||
${BRLCAD_BINARY_DIR}/src/other/libbson/src/bson
|
||||
${BRLCAD_SOURCE_DIR}/src/other/libbson/src/bson
|
||||
)
|
||||
|
||||
# locally used but not needed by users of the library
|
||||
|
||||
Regular → Executable
Regular → Executable
@@ -65,16 +65,16 @@ db5_import_attributes(struct bu_attribute_value_set *avs, const struct bu_extern
|
||||
size_t abinlen;
|
||||
cp += 2; /* We are now at the first byte of the first binary attribute... */
|
||||
while (cp != ep) {
|
||||
++bcount
|
||||
++bcount;
|
||||
cp += strlen(cp)+1; /* name */
|
||||
/* The next value is an unsigned integer of variable width
|
||||
* (a_width: DB5HDR_WIDTHCODE_x) so how do we get its
|
||||
* width? We now have a new member of struct bu_external:
|
||||
* 'unsigned char intwid'. Note that the integer
|
||||
* 'unsigned char widcode'. Note that the integer
|
||||
* is in network order and must be properly decoded for
|
||||
* the local architecture.
|
||||
*/
|
||||
cp += db5_decode_length(&abinlen, cp, ap->intwid);
|
||||
cp += db5_decode_length(&abinlen, (const unsigned char*)cp, ap->widcode);
|
||||
/* account for the abinlen bytes */
|
||||
cp += abinlen;
|
||||
}
|
||||
@@ -122,10 +122,9 @@ db5_import_attributes(struct bu_attribute_value_set *avs, const struct bu_extern
|
||||
while (cp != ep) {
|
||||
const char *name = cp; /* name */
|
||||
cp += strlen(cp)+1; /* name */
|
||||
cp += db5_decode_length(&abinlen, cp, ap->intwid);
|
||||
cp += db5_decode_length(&abinlen, (const unsigned char*)cp, ap->widcode);
|
||||
/* now decode for the abinlen bytes */
|
||||
decode_binary_attribute(const size_t len, const char *cp)
|
||||
decod
|
||||
decode_binary_attribute(abinlen, (const unsigned char*)cp);
|
||||
cp += abinlen;
|
||||
}
|
||||
/* now cp should be at the end */
|
||||
@@ -491,7 +490,7 @@ db5_fwrite_ident(FILE *fp, const char *title, double local2mm)
|
||||
|
||||
#if defined(USE_BINARY_ATTRIBUTES)
|
||||
void
|
||||
decode_binary_attribute(const size_t len, const char *cp)
|
||||
decode_binary_attribute(const size_t len, const unsigned char *cp)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -34,6 +34,10 @@ add_test(NAME rt_test_nmg_mk COMMAND test_nmg_mk)
|
||||
BRLCAD_ADDEXEC(test_nmg_copy test_nmg_copy.c "librt" NO_INSTALL)
|
||||
add_test(NAME rt_test_nmg_copy COMMAND test_nmg_copy)
|
||||
|
||||
# binary attribute testing
|
||||
BRLCAD_ADDEXEC(test_binary_attribute test_binary_attribute.c "librt" NO_INSTALL)
|
||||
add_test(NAME rt_test_binary_attribute COMMAND test_binary_attribute)
|
||||
|
||||
set(distcheck_files
|
||||
arb_intersect.g
|
||||
brep_boolean_tests.g
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/* T E S T _ B I N A R Y _ A T T R I B U T E . C
|
||||
* BRL-CAD
|
||||
*
|
||||
* Copyright (c) 2013-2014 United States Government as represented by
|
||||
* the U.S. Army Research Laboratory.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this file; see the file named COPYING for more
|
||||
* information.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#include "bn.h"
|
||||
#include "vmath.h"
|
||||
#include "raytrace.h"
|
||||
|
||||
|
||||
int
|
||||
main(int UNUSED(argc), char **UNUSED(argv))
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* tab-width: 8
|
||||
* mode: C
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "stroustrup"
|
||||
* End:
|
||||
* ex: shiftwidth=4 tabstop=8
|
||||
*/
|
||||
@@ -51,6 +51,7 @@ foreach(ITEM ${dlists})
|
||||
CMAKEFILES(${dlist})
|
||||
endforeach(ITEM ${dlists})
|
||||
|
||||
#=== LIBREGEX ============================================
|
||||
# libregex library - often needed by tools, so do this one first.
|
||||
set(regex_ALIASES ENABLE_REGEX)
|
||||
set(regex_DESCRIPTION "
|
||||
@@ -94,6 +95,7 @@ if(BUILD_SHARED_LIBS AND HAVE_LIBC_REGEX AND "${BRLCAD_REGEX}" MATCHES "BUNDLED"
|
||||
set_property(DIRECTORY libregex APPEND PROPERTY COMPILE_DEFINITIONS regexec=libregex_regexec)
|
||||
set_property(DIRECTORY libregex APPEND PROPERTY COMPILE_DEFINITIONS regfree=libregex_regfree)
|
||||
endif(BUILD_SHARED_LIBS AND HAVE_LIBC_REGEX AND "${BRLCAD_REGEX}" MATCHES "BUNDLED")
|
||||
#=== END LIBREGEX ============================================
|
||||
|
||||
# Same deal for zlib Library - common requirement, deal with it up front
|
||||
set(zlib_ALIASES ENABLE_ZLIB ENABLE_LIBZ)
|
||||
@@ -741,6 +743,22 @@ if(BRLCAD_SPR_BUILD)
|
||||
SetTargetFolder(libSPR-static "Third Party Libraries")
|
||||
endif(BRLCAD_SPR_BUILD)
|
||||
|
||||
#=== LIBBSON ==================================================
|
||||
# Libbson needed for binary attributes, always use this local version
|
||||
set(libbson_ALIASES ENABLE_BSON)
|
||||
set(libbson_DESCRIPTION "
|
||||
Option for enabling and disabling compilation of the Libbson library
|
||||
provided with BRL-CAD's source code. Default is BUNDLED, using
|
||||
the included other/src version.
|
||||
")
|
||||
THIRD_PARTY(libbson BSON Libbson libbson_DESCRIPTION ALIASES
|
||||
${libbson_ALIASES} FLAGS NOSYS)
|
||||
if(BRLCAD_BSON_BUILD)
|
||||
SetTargetFolder(libBSON "Third Party Libraries")
|
||||
SetTargetFolder(libBSON-static "Third Party Libraries")
|
||||
endif(BRLCAD_BSON_BUILD)
|
||||
#=== END LIBBSON ==================================================
|
||||
|
||||
# STEPcode
|
||||
# Need Lemon/Perplex to build STEP - conditionalize
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
*~
|
||||
*.a
|
||||
aclocal.m4
|
||||
AUTHORS
|
||||
autom4te.cache
|
||||
bcon-col-view
|
||||
bcon-speed
|
||||
bson-streaming-reader
|
||||
bson-metrics
|
||||
bson-to-json
|
||||
bson-validate
|
||||
ChangeLog
|
||||
*.cmake
|
||||
CMakeFiles
|
||||
CMakeCache.txt
|
||||
compile
|
||||
config.*
|
||||
configure
|
||||
depcomp
|
||||
.deps
|
||||
.dirstamp
|
||||
*.exe
|
||||
INSTALL
|
||||
install-sh
|
||||
json-to-bson
|
||||
*.la
|
||||
.libs
|
||||
libtool
|
||||
libbson-1.0.so*
|
||||
*.lo
|
||||
ltmain.sh
|
||||
Makefile
|
||||
Makefile.in
|
||||
missing
|
||||
*.o
|
||||
*.pc
|
||||
README
|
||||
stamp-h1
|
||||
*.swp
|
||||
test-libbson
|
||||
test.log
|
||||
.DS_Store
|
||||
xcuserdata
|
||||
@@ -0,0 +1,259 @@
|
||||
#######################################
|
||||
# libbson config for MCI #
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Options #
|
||||
#######################################
|
||||
|
||||
stepback: true
|
||||
|
||||
#######################################
|
||||
# Functions #
|
||||
#######################################
|
||||
|
||||
functions:
|
||||
fetch_source:
|
||||
command: git.get_project
|
||||
params:
|
||||
directory: libbson
|
||||
|
||||
libbson_variables:
|
||||
## Tests run on most buildvariants
|
||||
|
||||
std_test_def: &std_tests
|
||||
- name: compile
|
||||
- name: make check
|
||||
|
||||
## Architectures
|
||||
|
||||
default_expansions_def: &default_expansions
|
||||
env_vars: CFLAGS=""
|
||||
i386_expansions_def: &i386_expansions
|
||||
env_vars: CFLAGS="-m32 -march=i386"
|
||||
i686_expansions_def: &i686_expansions
|
||||
env_vars: CFLAGS="-m32 -march=i686"
|
||||
x86_64_expansions_def: &x86_64_expansions
|
||||
env_vars: CFLAGS="-m64 -march=x86-64"
|
||||
|
||||
## "Platforms" or whatever
|
||||
|
||||
linux_expansions_def: &linux_expansions
|
||||
j_flag: -j$(grep -c ^processor /proc/cpuinfo)
|
||||
|
||||
osx_expansions_def: &osx_expansions
|
||||
j_flag: -j$(sysctl -n hw.logicalcpu)
|
||||
|
||||
solaris_expansions_def: &solaris_expansions
|
||||
j_flag: -j$(kstat cpu_info|grep core_id|sort -u|wc -l)
|
||||
|
||||
mingw_expansions_def: &mingw_expansions
|
||||
j_flag: -j$(grep -c ^processor /proc/cpuinfo)
|
||||
|
||||
#######################################
|
||||
# Pre Task #
|
||||
#######################################
|
||||
|
||||
pre:
|
||||
- command: expansions.fetch
|
||||
params:
|
||||
keys:
|
||||
- local_key: aws_key
|
||||
remote_key: project_aws_key
|
||||
- local_key: aws_secret
|
||||
remote_key: project_aws_secret
|
||||
|
||||
- command: shell.exec
|
||||
params:
|
||||
script: |
|
||||
set -o verbose
|
||||
rm -rf libbson
|
||||
|
||||
#######################################
|
||||
# Tasks #
|
||||
#######################################
|
||||
|
||||
tasks:
|
||||
- name: compile
|
||||
commands:
|
||||
- command: git.get_project
|
||||
params:
|
||||
directory: libbson
|
||||
- command: git.apply_patch
|
||||
params:
|
||||
directory: libbson
|
||||
- command: shell.exec
|
||||
params:
|
||||
working_dir: libbson
|
||||
script: |
|
||||
set -o verbose
|
||||
set -o errexit
|
||||
export PATH=${path}:$PATH
|
||||
${env_vars} ./autogen.sh
|
||||
make ${j_flag}
|
||||
- command: shell.exec
|
||||
params:
|
||||
working_dir: libbson
|
||||
script: |
|
||||
set -o verbose
|
||||
tar -czvf ../libbson.tar.gz .
|
||||
- command: s3.put
|
||||
params:
|
||||
aws_key: ${aws_key}
|
||||
aws_secret: ${aws_secret}
|
||||
remote_file: libbson/${build_variant}/${revision}/artifacts/${build_id}.tar.gz
|
||||
bucket: mciuploads
|
||||
local_file: libbson.tar.gz
|
||||
permissions: public-read
|
||||
content_type: ${content_type|application/x-gzip}
|
||||
|
||||
- name: make check
|
||||
depends_on:
|
||||
- name: compile
|
||||
commands:
|
||||
- command: shell.exec
|
||||
params:
|
||||
script: |
|
||||
mkdir libbson
|
||||
- command: shell.exec
|
||||
params:
|
||||
working_dir: libbson
|
||||
script: |
|
||||
set -o verbose
|
||||
set -o errexit
|
||||
# MCI's S3 mechanism doesn't support symlinks
|
||||
curl http://s3.amazonaws.com/mciuploads/libbson/${build_variant}/${revision}/artifacts/${build_id}.tar.gz -o ${build_id}.tar.gz --silent
|
||||
tar -xzf ${build_id}.tar.gz
|
||||
export PATH=${path}:$PATH
|
||||
make check
|
||||
|
||||
#######################################
|
||||
# Buildvariants #
|
||||
#######################################
|
||||
|
||||
buildvariants:
|
||||
|
||||
################ 32-bit ###############
|
||||
|
||||
- name: rhel55-32
|
||||
display_name: RHEL 5.5 32-bit
|
||||
expansions:
|
||||
<<: *default_expansions
|
||||
<<: *linux_expansions
|
||||
run_on:
|
||||
- rhel55-32
|
||||
tasks: *std_tests
|
||||
|
||||
- name: windows-32
|
||||
display_name: Windows 32-bit
|
||||
expansions:
|
||||
<<: *default_expansions
|
||||
<<: *linux_expansions
|
||||
run_on:
|
||||
- windows-32
|
||||
tasks: *std_tests
|
||||
|
||||
########## i386 cross-compile #########
|
||||
|
||||
- name: ubuntu-1204-i386
|
||||
display_name: Ubuntu 12.04 i386
|
||||
expansions:
|
||||
<<: *i386_expansions
|
||||
<<: *linux_expansions
|
||||
run_on:
|
||||
- ubuntu1204-test
|
||||
tasks: *std_tests
|
||||
|
||||
- name: ubuntu-1404-i386
|
||||
display_name: Ubuntu 14.04 i386
|
||||
expansions:
|
||||
<<: *i386_expansions
|
||||
<<: *linux_expansions
|
||||
run_on:
|
||||
- ubuntu1404-test
|
||||
tasks: *std_tests
|
||||
|
||||
- name: os-x-108-i386
|
||||
display_name: OS X 10.8 i386
|
||||
expansions:
|
||||
<<: *osx_expansions
|
||||
env_vars: CC="clang -m32 -march=i386"
|
||||
run_on:
|
||||
- osx-108
|
||||
tasks: *std_tests
|
||||
|
||||
########## i686 cross-compile #########
|
||||
|
||||
- name: ubuntu-1204-i686
|
||||
display_name: Ubuntu 12.04 i686
|
||||
expansions:
|
||||
<<: *i686_expansions
|
||||
<<: *linux_expansions
|
||||
run_on:
|
||||
- ubuntu1204-test
|
||||
tasks: *std_tests
|
||||
|
||||
- name: ubuntu-1404-i686
|
||||
display_name: Ubuntu 14.04 i686
|
||||
expansions:
|
||||
<<: *i686_expansions
|
||||
<<: *linux_expansions
|
||||
run_on:
|
||||
- ubuntu1404-test
|
||||
tasks: *std_tests
|
||||
|
||||
- name: os-x-108-i686
|
||||
display_name: OS X 10.8 i686
|
||||
expansions:
|
||||
<<: *osx_expansions
|
||||
env_vars: CC="clang -m32 -march=i686"
|
||||
run_on:
|
||||
- osx-108
|
||||
tasks: *std_tests
|
||||
|
||||
############## x86_64 #################
|
||||
|
||||
- name: ubuntu-1204-64
|
||||
display_name: Ubuntu 12.04 64-bit
|
||||
expansions:
|
||||
<<: *x86_64_expansions
|
||||
<<: *linux_expansions
|
||||
run_on:
|
||||
- ubuntu1204-test
|
||||
tasks: *std_tests
|
||||
|
||||
- name: ubuntu-1404-64
|
||||
display_name: Ubuntu 14.04 64-bit
|
||||
expansions:
|
||||
<<: *x86_64_expansions
|
||||
<<: *linux_expansions
|
||||
run_on:
|
||||
- ubuntu1404-test
|
||||
tasks: *std_tests
|
||||
|
||||
- name: os-x-108-64
|
||||
display_name: OS X 10.8 64-bit
|
||||
expansions:
|
||||
<<: *osx_expansions
|
||||
run_on:
|
||||
- osx-108
|
||||
tasks: *std_tests
|
||||
|
||||
- name: solaris-64-bit
|
||||
display_name: Solaris 64-bit
|
||||
expansions:
|
||||
<<: *x86_64_expansions
|
||||
<<: *solaris_expansions
|
||||
path: "/opt/mongodbtoolchain/bin/"
|
||||
run_on:
|
||||
- solaris
|
||||
tasks: *std_tests
|
||||
|
||||
- name: windows-64-mingw64
|
||||
display_name: Windows 64-bit MinGW-64
|
||||
expansions:
|
||||
<<: *default_expansions
|
||||
path: "/cygdrive/c/mingw-w64/x86_64-4.9.1-posix-seh-rt_v3-rev1/mingw64/bin:/cygdrive/c/sasl/"
|
||||
run_on:
|
||||
- windows-64-vs2013-test
|
||||
tasks: *std_tests
|
||||
@@ -0,0 +1,239 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project (libbson)
|
||||
|
||||
include(CheckFunctionExists)
|
||||
include(CheckIncludeFile)
|
||||
include(CheckStructHasMember)
|
||||
include(CheckSymbolExists)
|
||||
include(TestBigEndian)
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
# Set BSON_MAJOR_VERSION, BSON_MINOR_VERSION, etc.
|
||||
include(LoadVersion)
|
||||
LoadVersion(${PROJECT_SOURCE_DIR}/VERSION_CURRENT BSON)
|
||||
LoadVersion(${PROJECT_SOURCE_DIR}/VERSION_RELEASED BSON_RELEASED)
|
||||
|
||||
message("Current version (from VERSION_CURRENT file): ${BSON_VERSION}")
|
||||
if (NOT ${BSON_VERSION} STREQUAL ${BSON_RELEASED_VERSION})
|
||||
message("Previous release (from VERSION_RELEASED file): ${BSON_RELEASED_VERSION}")
|
||||
endif()
|
||||
|
||||
set (SOURCE_DIR "${PROJECT_SOURCE_DIR}/")
|
||||
|
||||
set (BSON_API_VERSION 1.0)
|
||||
|
||||
set (CPACK_RESOURCE_FILE_LICENSE "${SOURCE_DIR}/COPYING")
|
||||
set (CPACK_PACKAGE_VERSION_MAJOR ${BSON_MAJOR_VERSION})
|
||||
set (CPACK_PACKAGE_VERSION_MINOR ${BSON_MINOR_VERSION})
|
||||
|
||||
include (CPack)
|
||||
|
||||
TEST_BIG_ENDIAN(BSON_BIG_ENDIAN)
|
||||
|
||||
# These need proper checks like automake.
|
||||
set (BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES 0)
|
||||
|
||||
#librt needed on linux for clock_gettime
|
||||
find_library(RT_LIBRARY rt)
|
||||
if (RT_LIBRARY)
|
||||
#set required libraries for CHECK_FUNCTION_EXISTS
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${RT_LIBRARY})
|
||||
endif()
|
||||
|
||||
# See https://public.kitware.com/Bug/view.php?id=15659
|
||||
CHECK_SYMBOL_EXISTS(snprintf stdio.h BSON_HAVE_SNPRINTF)
|
||||
if (NOT BSON_HAVE_SNPRINTF)
|
||||
set(BSON_HAVE_SNPRINTF 0)
|
||||
else ()
|
||||
set(BSON_HAVE_SNPRINTF 1)
|
||||
endif ()
|
||||
|
||||
CHECK_FUNCTION_EXISTS(_set_output_format BSON_NEEDS_SET_OUTPUT_FORMAT)
|
||||
if (NOT BSON_NEEDS_SET_OUTPUT_FORMAT)
|
||||
set(BSON_NEEDS_SET_OUTPUT_FORMAT 0)
|
||||
endif ()
|
||||
|
||||
CHECK_STRUCT_HAS_MEMBER("struct timespec" tv_sec time.h BSON_HAVE_TIMESPEC)
|
||||
if (NOT BSON_HAVE_TIMESPEC)
|
||||
message(STATUS " no timespec struct")
|
||||
set(BSON_HAVE_TIMESPEC 0)
|
||||
else ()
|
||||
message(STATUS " struct timespec found")
|
||||
set(BSON_HAVE_TIMESPEC 1)
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
set (BSON_OS 2)
|
||||
set (BSON_HAVE_CLOCK_GETTIME 0)
|
||||
set (BSON_HAVE_STDBOOL_H 0)
|
||||
set (BSON_HAVE_STRNLEN 0)
|
||||
set (BSON_EXTRA_ALIGN 1)
|
||||
else ()
|
||||
find_package (Threads)
|
||||
|
||||
set (BSON_OS 1)
|
||||
CHECK_FUNCTION_EXISTS(clock_gettime BSON_HAVE_CLOCK_GETTIME)
|
||||
if (NOT BSON_HAVE_CLOCK_GETTIME)
|
||||
set(BSON_HAVE_CLOCK_GETTIME 0)
|
||||
endif ()
|
||||
CHECK_FUNCTION_EXISTS(strnlen BSON_HAVE_STRNLEN)
|
||||
if (NOT BSON_HAVE_STRNLEN)
|
||||
set(BSON_HAVE_STRNLEN 0)
|
||||
endif ()
|
||||
CHECK_INCLUDE_FILE(stdbool.h BSON_HAVE_STDBOOL_H)
|
||||
if (NOT BSON_HAVE_STDBOOL_H)
|
||||
set(BSON_HAVE_STDBOOL_H 0)
|
||||
endif ()
|
||||
set (BSON_EXTRA_ALIGN 1)
|
||||
endif ()
|
||||
|
||||
set (BSON_HAVE_ATOMIC_32_ADD_AND_FETCH 1)
|
||||
set (BSON_HAVE_ATOMIC_64_ADD_AND_FETCH 1)
|
||||
|
||||
if (BSON_BIG_ENDIAN)
|
||||
set (BSON_BYTE_ORDER 4321)
|
||||
else ()
|
||||
set (BSON_BYTE_ORDER 1234)
|
||||
endif ()
|
||||
|
||||
configure_file (
|
||||
"${SOURCE_DIR}/src/bson/bson-config.h.in"
|
||||
"${PROJECT_BINARY_DIR}/src/bson/bson-config.h"
|
||||
)
|
||||
|
||||
configure_file (
|
||||
"${SOURCE_DIR}/src/bson/bson-version.h.in"
|
||||
"${PROJECT_BINARY_DIR}/src/bson/bson-version.h"
|
||||
)
|
||||
|
||||
configure_file (
|
||||
"${PROJECT_SOURCE_DIR}/cmake/bson/bson-stdint.h"
|
||||
"${PROJECT_BINARY_DIR}/src/bson/bson-stdint.h"
|
||||
)
|
||||
|
||||
include_directories("${PROJECT_BINARY_DIR}/src/bson")
|
||||
include_directories("${SOURCE_DIR}/src/bson")
|
||||
include_directories("${SOURCE_DIR}/src")
|
||||
|
||||
if (APPLE)
|
||||
cmake_policy(SET CMP0042 OLD)
|
||||
endif()
|
||||
|
||||
set (SOURCES
|
||||
${SOURCE_DIR}/src/bson/bcon.c
|
||||
${SOURCE_DIR}/src/bson/bson.c
|
||||
${SOURCE_DIR}/src/bson/bson-atomic.c
|
||||
${SOURCE_DIR}/src/bson/bson-clock.c
|
||||
${SOURCE_DIR}/src/bson/bson-context.c
|
||||
${SOURCE_DIR}/src/bson/bson-error.c
|
||||
${SOURCE_DIR}/src/bson/bson-iso8601.c
|
||||
${SOURCE_DIR}/src/bson/bson-iter.c
|
||||
${SOURCE_DIR}/src/bson/bson-json.c
|
||||
${SOURCE_DIR}/src/bson/bson-keys.c
|
||||
${SOURCE_DIR}/src/bson/bson-md5.c
|
||||
${SOURCE_DIR}/src/bson/bson-memory.c
|
||||
${SOURCE_DIR}/src/bson/bson-oid.c
|
||||
${SOURCE_DIR}/src/bson/bson-reader.c
|
||||
${SOURCE_DIR}/src/bson/bson-string.c
|
||||
${SOURCE_DIR}/src/bson/bson-timegm.c
|
||||
${SOURCE_DIR}/src/bson/bson-utf8.c
|
||||
${SOURCE_DIR}/src/bson/bson-value.c
|
||||
${SOURCE_DIR}/src/bson/bson-version-functions.c
|
||||
${SOURCE_DIR}/src/bson/bson-writer.c
|
||||
${SOURCE_DIR}/src/yajl/yajl_alloc.c
|
||||
${SOURCE_DIR}/src/yajl/yajl_buf.c
|
||||
${SOURCE_DIR}/src/yajl/yajl.c
|
||||
${SOURCE_DIR}/src/yajl/yajl_encode.c
|
||||
${SOURCE_DIR}/src/yajl/yajl_gen.c
|
||||
${SOURCE_DIR}/src/yajl/yajl_lex.c
|
||||
${SOURCE_DIR}/src/yajl/yajl_parser.c
|
||||
${SOURCE_DIR}/src/yajl/yajl_tree.c
|
||||
${SOURCE_DIR}/src/yajl/yajl_version.c
|
||||
)
|
||||
|
||||
set (HEADERS
|
||||
${PROJECT_BINARY_DIR}/src/bson/bson-config.h
|
||||
${PROJECT_BINARY_DIR}/src/bson/bson-stdint.h
|
||||
${PROJECT_BINARY_DIR}/src/bson/bson-version.h
|
||||
${SOURCE_DIR}/src/bson/bcon.h
|
||||
${SOURCE_DIR}/src/bson/bson-atomic.h
|
||||
${SOURCE_DIR}/src/bson/bson-clock.h
|
||||
${SOURCE_DIR}/src/bson/bson-compat.h
|
||||
${SOURCE_DIR}/src/bson/bson-context.h
|
||||
${SOURCE_DIR}/src/bson/bson-endian.h
|
||||
${SOURCE_DIR}/src/bson/bson-error.h
|
||||
${SOURCE_DIR}/src/bson/bson.h
|
||||
${SOURCE_DIR}/src/bson/bson-iter.h
|
||||
${SOURCE_DIR}/src/bson/bson-json.h
|
||||
${SOURCE_DIR}/src/bson/bson-keys.h
|
||||
${SOURCE_DIR}/src/bson/bson-macros.h
|
||||
${SOURCE_DIR}/src/bson/bson-md5.h
|
||||
${SOURCE_DIR}/src/bson/bson-memory.h
|
||||
${SOURCE_DIR}/src/bson/bson-oid.h
|
||||
${SOURCE_DIR}/src/bson/bson-reader.h
|
||||
${SOURCE_DIR}/src/bson/bson-stdint-win32.h
|
||||
${SOURCE_DIR}/src/bson/bson-string.h
|
||||
${SOURCE_DIR}/src/bson/bson-types.h
|
||||
${SOURCE_DIR}/src/bson/bson-utf8.h
|
||||
${SOURCE_DIR}/src/bson/bson-value.h
|
||||
${SOURCE_DIR}/src/bson/bson-version-functions.h
|
||||
${SOURCE_DIR}/src/bson/bson-writer.h
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
set(BSON_SHARED_SOURCES ${SOURCES} ${PROJECT_SOURCE_DIR}/cmake/libbson.def)
|
||||
else()
|
||||
set(BSON_SHARED_SOURCES ${SOURCES})
|
||||
endif()
|
||||
|
||||
add_library(bson_shared SHARED ${BSON_SHARED_SOURCES} ${HEADERS})
|
||||
add_library(bson_static STATIC ${SOURCES} ${HEADERS})
|
||||
|
||||
set_target_properties(bson_shared PROPERTIES COMPILE_DEFINITIONS "BSON_COMPILATION")
|
||||
set_target_properties(bson_static PROPERTIES COMPILE_DEFINITIONS "BSON_COMPILATION")
|
||||
|
||||
set_target_properties(bson_shared PROPERTIES VERSION ${BSON_VERSION} SOVERSION ${BSON_MAJOR_VERSION})
|
||||
set_target_properties(bson_static PROPERTIES VERSION ${BSON_VERSION} SOVERSION ${BSON_MAJOR_VERSION})
|
||||
|
||||
set_target_properties(bson_shared PROPERTIES OUTPUT_NAME "bson-${BSON_API_VERSION}" PREFIX "lib")
|
||||
set_target_properties(bson_static PROPERTIES OUTPUT_NAME "bson-static-${BSON_API_VERSION}")
|
||||
|
||||
if (RT_LIBRARY)
|
||||
target_link_libraries (bson_shared ${RT_LIBRARY})
|
||||
target_link_libraries (bson_static ${RT_LIBRARY})
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries (bson_shared ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries (bson_static ${CMAKE_THREAD_LIBS_INIT})
|
||||
else()
|
||||
target_link_libraries (bson_shared ws2_32)
|
||||
target_link_libraries (bson_static ws2_32)
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS bson_shared bson_static
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
install(
|
||||
FILES ${HEADERS}
|
||||
DESTINATION "include/libbson-${BSON_API_VERSION}"
|
||||
)
|
||||
|
||||
set(VERSION "${BSON_VERSION}")
|
||||
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
||||
set(libdir "\${prefix}/lib")
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/libbson-1.0.pc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/libbson-1.0.pc
|
||||
@ONLY)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/libbson-1.0.pc
|
||||
DESTINATION lib/pkgconfig
|
||||
)
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,796 @@
|
||||
Libbson-1.3.5
|
||||
=============
|
||||
|
||||
No change since 1.3.4; released to keep pace with libmongoc's version.
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.3.4
|
||||
=============
|
||||
|
||||
No change since 1.3.3; released to keep pace with libmongoc's version.
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.3.3
|
||||
=============
|
||||
|
||||
No change since 1.3.2; released to keep pace with libmongoc's version.
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.3.2
|
||||
=============
|
||||
|
||||
This is a patch release with a fix for the build system:
|
||||
|
||||
* man pages couldn't be built from a distribution tarball.
|
||||
|
||||
Peace,
|
||||
|
||||
A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.3.1
|
||||
=============
|
||||
|
||||
It is my pleasure to announce Libbson-1.3.1. This is a bugfix release:
|
||||
|
||||
* bson_strnlen is off by one on Windows.
|
||||
* BSON_HAVE_STRNLEN config check used incorrectly.
|
||||
* Incompatibility with older CMake versions.
|
||||
* Wrong-sized allocation in bson_json_reader_new.
|
||||
|
||||
Thanks to everyone who contributed to the development of this release.
|
||||
|
||||
* A. Jesse Jiryu Davis
|
||||
* Alex Bishop
|
||||
* Jeroen Ooms
|
||||
|
||||
Peace,
|
||||
|
||||
A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.3.0
|
||||
=============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.3.0. Since the
|
||||
release candidate 1.3.0-rc0, the only changes have been fixes for compiler
|
||||
warnings and errors on various platforms.
|
||||
|
||||
All changes since the previous stable release, 1.2.1:
|
||||
|
||||
* Fix potential crash in bson_strncpy on Windows.
|
||||
* Parse DBRefs correctly from JSON.
|
||||
* CMake option to disable building tests: "cmake -DENABLE_TESTS:BOOL=OFF".
|
||||
* Refactor the build system to declare library version in one place.
|
||||
* Fix compiler warnings and errors, especially with Visual Studio 2015
|
||||
and IBM XL C.
|
||||
* Combine environment's CFLAGS with configure options when building.
|
||||
|
||||
Thanks to everyone who contributed to the development of this release.
|
||||
|
||||
* A. Jesse Jiryu Davis
|
||||
* Hannes Magnusson
|
||||
* Mark Benvenuto
|
||||
* Petr Písař
|
||||
* xpol
|
||||
* Jose Sebastian Battig
|
||||
* Jeroen Ooms
|
||||
|
||||
Peace,
|
||||
|
||||
A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.3.0-rc0
|
||||
=================
|
||||
|
||||
It is my pleasure to announce to you first release candidate of Libbson-1.3.0.
|
||||
|
||||
Changes since 1.3.0-beta0:
|
||||
|
||||
* Parse DBRefs correctly from JSON.
|
||||
* CMake option to disable building tests: "cmake -DENABLE_TESTS:BOOL=OFF".
|
||||
* Fix build warnings on some platforms, and refactor the build system.
|
||||
|
||||
Thanks to everyone who contributed to the development of this release.
|
||||
|
||||
* A. Jesse Jiryu Davis
|
||||
* Hannes Magnusson
|
||||
* Jose Sebastian Battig
|
||||
|
||||
Peace,
|
||||
|
||||
A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.3.0-beta0
|
||||
===================
|
||||
|
||||
It is my pleasure to announce to you the beta release of Libbson-1.3.0.
|
||||
|
||||
Changes since the previous stable release, 1.2.1:
|
||||
|
||||
* Fix potential crash in bson_strncpy on Windows.
|
||||
* Fix compiler warnings and errors, especially with Visual Studio 2015
|
||||
and IBM XL C.
|
||||
* Combine environment's CFLAGS with configure options when building.
|
||||
|
||||
Thanks to everyone who contributed to the development of this release.
|
||||
|
||||
* Hannes Magnusson
|
||||
* A. Jesse Jiryu Davis
|
||||
* Jeroen Ooms
|
||||
* Petr Písař
|
||||
* xpol
|
||||
|
||||
Peace,
|
||||
|
||||
A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.2.1
|
||||
=============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.2.1.
|
||||
|
||||
Changes since the previous stable release, 1.2.0 are solely in the content
|
||||
and format of documentation.
|
||||
|
||||
Peace,
|
||||
|
||||
A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.2.0
|
||||
=============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.2.0.
|
||||
|
||||
Changes since the previous stable release, 1.1.11:
|
||||
|
||||
* Add bson_mem_restore_vtable(), the inverse of bson_mem_set_vtable().
|
||||
* Enable runtime asserts in release build.
|
||||
* Fixed compiler warnings and build failures on various platforms.
|
||||
* Improvements to the formatting and contents of the documentation.
|
||||
|
||||
Thanks to everyone who contributed to the development of this release.
|
||||
|
||||
* A. Jesse Jiryu Davis
|
||||
* Hannes Magnusson
|
||||
* Jason Carey
|
||||
* Kyle Suarez
|
||||
* Derick Rethans
|
||||
* David Hatch
|
||||
|
||||
Peace,
|
||||
|
||||
A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson 1.2.0-rc0
|
||||
==================
|
||||
|
||||
It is my pleasure to announce to you the release candidate of Libbson-1.2.0.
|
||||
|
||||
Changes:
|
||||
|
||||
* Merge changes from 1.1.11.
|
||||
* Enable runtime asserts in release build.
|
||||
|
||||
Thanks to everyone who contributed to the development of this release candidate.
|
||||
|
||||
* A. Jesse Jiryu Davis
|
||||
* Hannes Magnusson
|
||||
* Kyle Suarez
|
||||
* Jason Carey
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson 1.2.0-beta
|
||||
==================
|
||||
|
||||
It is my pleasure to announce to you the beta of Libbson-1.2.0.
|
||||
|
||||
This release adds the bson_mem_restore_vtable() function to undo the effect
|
||||
of bson_mem_set_vtable().
|
||||
|
||||
Thanks to everyone who contributed to the development of this beta.
|
||||
|
||||
* Jason Carey
|
||||
* Hannes Magnusson
|
||||
|
||||
|
||||
Libbson-1.1.11
|
||||
==============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.1.11.
|
||||
|
||||
This is a patch release with improvements to the documentation:
|
||||
|
||||
* Document bson streaming reads with an example,
|
||||
bson-streaming-reader.c.
|
||||
* Document callback function types bson_reader_destroy_func_t and
|
||||
bson_reader_read_func_t.
|
||||
|
||||
Thanks to Kyle Suarez for his contributions to this version of Libbson.
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.1.10
|
||||
==============
|
||||
|
||||
No change since 1.1.9; released to keep pace with libmongoc's version.
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.1.9
|
||||
=============
|
||||
|
||||
This is a patch release with a fix for the build system:
|
||||
|
||||
* "./configure --enable-coverage" works now.
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.1.8
|
||||
=============
|
||||
|
||||
No change since 1.1.7; released to keep pace with libmongoc's version.
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.1.7
|
||||
=============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.1.7.
|
||||
|
||||
This is a patch release with bug fixes:
|
||||
|
||||
* Unchecked error in bson_utf8_escape_for_json caused unbounded memory growth
|
||||
and a crash.
|
||||
* Nicer floating-point formatting in bson_as_json.
|
||||
* Link error with CMake on Mac.
|
||||
|
||||
Thanks to everyone who contributed to this version of Libbson.
|
||||
|
||||
* A. Jesse Jiryu Davis
|
||||
* Jason Carey
|
||||
* Jeroen Ooms
|
||||
* Hannes Magnusson
|
||||
* Hendrik Dahlkamp
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson-1.1.6
|
||||
=============
|
||||
|
||||
No change since 1.1.5; released to keep pace with libmongoc's version.
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
|
||||
Libbson 1.1.5
|
||||
=============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.1.5.
|
||||
|
||||
This is a patch release with small bug fixes:
|
||||
|
||||
* Fix link error "missing __sync_add_and_fetch_4" in GCC on i386 -
|
||||
the functions bson_atomic_int_add and bson_atomic_int64_add are now
|
||||
compiled and exported if needed in i386 mode
|
||||
* Fix version check for GCC 5 and future versions of Clang
|
||||
* Fix warnings and errors building on various platforms
|
||||
|
||||
With this release, Libbson abandons the convention that odd-numbered patch
|
||||
versions indicate unstable releases. We switch to simple semantic versioning:
|
||||
1.1.5 is a stable release with bug fixes since 1.1.4. During subsequent
|
||||
development the version will be "1.1.6-dev".
|
||||
|
||||
Thanks to everyone who contributed to this version of Libbson.
|
||||
|
||||
* A. Jesse Jiryu Davis
|
||||
* Christian Hergert
|
||||
* Jason Carey
|
||||
* Hannes Magnusson
|
||||
* Paul Melnikow
|
||||
|
||||
-- A. Jesse Jiryu Davis
|
||||
|
||||
Libbson 1.1.4
|
||||
=============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.1.4.
|
||||
|
||||
This release is a minor patch release with one bug fix for bson_iter_timeval
|
||||
|
||||
Thanks to everyone who contributed to the development of this release candidate for
|
||||
Libbson.
|
||||
|
||||
* Jason Carey
|
||||
* A. Jesse Jiryu Davis
|
||||
* Vladimir Zidar
|
||||
|
||||
-- Jason Carey
|
||||
|
||||
Libbson 1.1.2
|
||||
=============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.1.2.
|
||||
|
||||
This release is a minor patch release with one bug fix for mingw.
|
||||
|
||||
* sscanf_s doesn't exist for mingw.
|
||||
|
||||
-- Jason Carey
|
||||
|
||||
Libbson 1.1.0
|
||||
=============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.1.0.
|
||||
|
||||
This release is a stable release with some ABI additions and bugfixes.
|
||||
|
||||
The below changes include the changes mentioned in the rc0.
|
||||
|
||||
ABI/API changes include:
|
||||
* RC0
|
||||
* Deprecation of bson_copy_to_excluding
|
||||
* Addition of bson_copy_to_excluding_noinit
|
||||
* Removal of MIN, MAX and ABS macros in favor of BSON_MIN, BSON_MAX and
|
||||
BSON_ABS. Note this is a breaking source level change if you relied on
|
||||
these from bson.h. Also note that this is not a breaking ABI change.
|
||||
* Addition of BSON_ERROR_BUFFER_SIZE macro
|
||||
|
||||
Other changes include:
|
||||
* RC0
|
||||
* Addition of a versioned ABI for the libbson shared library
|
||||
* fixed bson_get_monotonic_time fallback when a system monotonic clock can not
|
||||
be found. Formerly failed to compile with an incorrect call to
|
||||
bson_gettimeofday
|
||||
* Allow the "dbref" convention in bson_validate when BSON_VALIDATE_DOLLAR_KEYS
|
||||
is present
|
||||
* Support for ISO-8601 or $numberLong dates in bson <-> json parsing
|
||||
* Quiet various compiler warnings
|
||||
|
||||
Thanks to everyone who contributed to the development of this release candidate for
|
||||
Libbson.
|
||||
|
||||
* Adam Midvidy
|
||||
* Christian Hergert
|
||||
* Daniel Colchete
|
||||
* Ivan Suvorov
|
||||
* Hannes Magnusson
|
||||
* Jason Carey
|
||||
* Jérôme Lebel
|
||||
* Samantha Ritter
|
||||
|
||||
-- Jason Carey
|
||||
|
||||
Libbson 1.1.0-rc0
|
||||
=================
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.1.0-rc0.
|
||||
|
||||
This release is a release candidate release with some ABI additions and bugfixes.
|
||||
|
||||
ABI changes include:
|
||||
* Deprecation of bson_copy_to_excluding
|
||||
* Addition of bson_copy_to_excluding_noinit
|
||||
|
||||
Other changes include:
|
||||
* Addition of a versioned ABI for the libbson shared library
|
||||
* fixed bson_get_monotonic_time fallback when a system monotonic clock can not
|
||||
be found. Formerly failed to compile with an incorrect call to
|
||||
bson_gettimeofday
|
||||
* Allow the "dbref" convention in bson_validate when BSON_VALIDATE_DOLLAR_KEYS
|
||||
is present
|
||||
* Support for ISO-8601 or $numberLong dates in bson <-> json parsing
|
||||
* Quiet various compiler warnings
|
||||
|
||||
Thanks to everyone who contributed to the development of this release candidate for
|
||||
Libbson.
|
||||
|
||||
* Adam Midvidy
|
||||
* Christian Hergert
|
||||
* Daniel Colchete
|
||||
* Ivan Suvorov
|
||||
* Jason Carey
|
||||
* Jérôme Lebel
|
||||
|
||||
-- Jason Carey
|
||||
|
||||
Libbson 1.0.2
|
||||
=============
|
||||
|
||||
It is my pleasure to announce to you the release of Libbson-1.0.2.
|
||||
|
||||
This release is a minor point release with no ABI changes and mostly small
|
||||
bugfixes.
|
||||
|
||||
Changes include:
|
||||
* bson_init_from_json supports top level arrays
|
||||
* fixes for bson_strerror_r
|
||||
* fix for timeouts on OS X
|
||||
* house cleaning for various integer types
|
||||
|
||||
Thanks to everyone who contributed to the development of this point release for
|
||||
Libbson.
|
||||
|
||||
* Adam Midvidy
|
||||
* Christian Hergert
|
||||
* Jason Carey
|
||||
* Jérôme Lebel
|
||||
* Tyler Brock
|
||||
|
||||
-- Jason Carey
|
||||
|
||||
Libbson 1.0.0
|
||||
=============
|
||||
|
||||
It is my very distinct pleasure to announce to you the release of
|
||||
Libbson-1.0.0!
|
||||
|
||||
This is the culmination of just over a year of work and could not have been
|
||||
done without the help of our wonderful community.
|
||||
|
||||
Thanks to everyone who contributed to the development of Libbson!
|
||||
|
||||
* Christian Hergert
|
||||
* Jason Carey
|
||||
* Jose Sebastian Battig
|
||||
* Maxim Zakharov
|
||||
* Jérôme Lebel
|
||||
* Itay Neeman
|
||||
* Mike Manilone
|
||||
* Michael Kuhn
|
||||
* Kyle Suarez
|
||||
* Josh Blum
|
||||
* Jason Choy
|
||||
* mntmnt7@gmail.com
|
||||
* Tyler Brock
|
||||
* Stefan Kaes
|
||||
* Paul Melnikow
|
||||
* Matt Cotter
|
||||
* Gary J. Murakami
|
||||
* Toon Schoenmakers
|
||||
* Máximo Cuadros
|
||||
* Michael Whittaker
|
||||
* Kota Yamaguchi
|
||||
* Justin Case
|
||||
* Jeff Yemin
|
||||
* Ivan Suvorov
|
||||
* Hannes Magnusson
|
||||
* Eric Daniels
|
||||
* Anil Kumar
|
||||
* A. Jesse Jiryu Davis
|
||||
|
||||
Happy Hacking!
|
||||
|
||||
-- Christian Hergert
|
||||
|
||||
|
||||
Libbson 0.98.0
|
||||
==============
|
||||
|
||||
One more step closer to a 1.0!
|
||||
|
||||
This release has a few fixes as we near the finish line of a 1.0 release.
|
||||
We have bumped the version to 0.98.0 to sync up with MongoDB C driver, which
|
||||
is the primary consumer of this library.
|
||||
|
||||
This release includes a new memory callback vtable to help in embedding
|
||||
situations that have their own custom allocator such as various language
|
||||
runtimes.
|
||||
|
||||
A few compilation fixes for various C++ compilers have also been included.
|
||||
|
||||
A special thanks to:
|
||||
|
||||
* Itay Neeman
|
||||
* Michael Whittaker
|
||||
|
||||
Happy Hacking!
|
||||
|
||||
-- Christian
|
||||
|
||||
|
||||
Libbson 0.8.4
|
||||
=============
|
||||
|
||||
Another incremental release with a couple of new functions and bugfixes.
|
||||
|
||||
In this release you will find the following changes:
|
||||
|
||||
* Alignment fixes for Solaris Studio C compiler.
|
||||
* RPM and Debian packaging helpers.
|
||||
* bson_gettimeofday() has dropped the deprecated timezone field used
|
||||
when calling posix gettimeofday(). This eases portability concerns.
|
||||
It is technically an ABI break, but since the field was never set,
|
||||
in reality it shouldn't be an issue.
|
||||
* Multi-byte optimizations for bson_oid_to_string() have been disabled
|
||||
on non-x86 based platforms. This should aid in architecture portability.
|
||||
* The JSON parser can now support $numberLong.
|
||||
* bson_ascii_strtoll() has been added, which is a portable strtoll()
|
||||
implementation. This is primarily useful for Windows users and is
|
||||
used by the JSON parser.
|
||||
* A bug was fixed in bson_iter_find_descendent() where the wrong field
|
||||
could be matched if it's prefix matched the query.
|
||||
* bson_array_as_json() has been added to convert a bson_t as a top-level
|
||||
array.
|
||||
|
||||
Thanks to:
|
||||
* Kyle Suarez
|
||||
* Itay Neeman
|
||||
|
||||
Happy Hacking!
|
||||
|
||||
|
||||
Libbson 0.8.2
|
||||
=============
|
||||
|
||||
A bugfix release is here as a follow up to 0.8.0.
|
||||
|
||||
In this release you will find the following changes:
|
||||
|
||||
* A fix for BCON when used from C++.
|
||||
* Change bson_next_power_of_two() to accept size_t. This should not be
|
||||
an ABI break since it is static inline.
|
||||
|
||||
Happy Hacking!
|
||||
|
||||
|
||||
Libbson 0.8.0
|
||||
=============
|
||||
|
||||
It's that time again, time for another Libbson release!
|
||||
|
||||
This cycle includes much, much more documentation for your perusing. There is
|
||||
much more cross-referencing and structure for your navigation pleasure.
|
||||
|
||||
We've improved support for Libbson on a few more exotic platforms. SPARC
|
||||
support is looking pretty good these days.
|
||||
|
||||
You'll also find some new examples in this release to help you get started a
|
||||
bit faster. If there is something you'd like to see, just ask!
|
||||
|
||||
There are a few ABI breaks this cycle, as we are well on the road to a 1.0 and
|
||||
would like things as clean as possible. I anticipate a few more during the next
|
||||
couple of cycles, but we will try to keep them to a minimum. With that said,
|
||||
you *WILL* need to recompile your application against 0.8.0.
|
||||
|
||||
Happy Hacking!
|
||||
|
||||
|
||||
Libbson 0.6.8
|
||||
=============
|
||||
|
||||
Quickly following up on the 0.6.6 release is 0.6.8. This release contains
|
||||
a couple of bugfixes and more support for older architectures.
|
||||
|
||||
On big-endian systems, bson_append_date_time() was not properly converting
|
||||
to little-endian. This is now fixed.
|
||||
|
||||
We've added support for Sun Pro C Compiler on Solaris 10 and 11. This includes
|
||||
support for SPARC systems as well as x86_64. In particular, intrinsics were
|
||||
added for the Solaris/SPARC/SunProC combination. If you are running SunProC
|
||||
on a non-Solaris platform, a fallback path will be used which is slower than
|
||||
native support for atomics. Additionally, bson_gettimeofday() does not fully
|
||||
support timezones under SunProC as struct timezone is not defined.
|
||||
|
||||
Libbson will now check for GLibc 2.19 to remove various warnings with both
|
||||
_GNU_SOURCE and _BSD_SOURCE defined.
|
||||
|
||||
Happy Hacking!
|
||||
|
||||
|
||||
Libbson 0.6.6
|
||||
=============
|
||||
|
||||
Another release for your hacking pleasure!
|
||||
|
||||
First off, note that there are two ABI breaks as part of this release. We
|
||||
felt they were important as they will help us stablize towards a 1.0 release.
|
||||
It is recommended that you recompile against this version of libbson.
|
||||
|
||||
Lots of small fixes went into this release to help get things building better
|
||||
on various platforms. Windows support should be improved and many warnings have
|
||||
been cleaned up.
|
||||
|
||||
The signature of bson_realloc_func has changed to allow for context to be
|
||||
provided. This should help in situations where a pointer to the memory pool is
|
||||
required.
|
||||
|
||||
bson_destroy_with_steal() has been added so that you can steal a buffer instead
|
||||
of freeing it when bson_destroy() is called.
|
||||
|
||||
bson_new_from_buffer() has been added so that you can provide your own realloc
|
||||
function to manage the underlying buffer. This will be useful for bindings that
|
||||
want to integrate their memory manager for bson documents.
|
||||
|
||||
bson_value_t is a new container type that can hold any bson type.
|
||||
|
||||
I'd like to thank everyone who contributed to this release.
|
||||
|
||||
Gary Murakami
|
||||
Jason Carey
|
||||
Jose Sebastian Battig
|
||||
Máximo Cuadros
|
||||
Paul Melnikow
|
||||
Stefan Kaes
|
||||
|
||||
Happy hacking!
|
||||
|
||||
Libbson 0.6.4
|
||||
=============
|
||||
|
||||
This is just a followup release of libbson as we work towards stablizing for
|
||||
the new mongo-c-driver release. In fact, it only includes build work and a
|
||||
new macro, bson_clear().
|
||||
|
||||
Happy hacking!
|
||||
|
||||
|
||||
Libbson 0.6.2
|
||||
=============
|
||||
|
||||
A new Libbson release is already here as a follow up to the 0.6.0 release.
|
||||
|
||||
This release includes a few build and installation fixes. In particular,
|
||||
|
||||
* Windows build fixes
|
||||
* CMake build fixes
|
||||
* C++ build fixes.
|
||||
|
||||
The monotonic clock is now more accurately calculated on Windows as well.
|
||||
If you'd like to build on Windows, check out the section in README.md for
|
||||
information on how to do so.
|
||||
|
||||
Happy hacking!
|
||||
|
||||
|
||||
Libbson 0.6.0
|
||||
=============
|
||||
|
||||
Many changes have gone into this release!
|
||||
|
||||
TL;DR
|
||||
|
||||
* C99 types (from C89).
|
||||
* JSON parsing.
|
||||
* Lots of Operating System support, including Windows.
|
||||
* Parallel Test Suite.
|
||||
* Revamped build system.
|
||||
* A couple ABI breaks.
|
||||
|
||||
First off, 0.6.0 has gone through a significant amount of build system cleanup.
|
||||
This should simplify using libbson as a submodule for those that wish to do so.
|
||||
For example, the mongo-c-driver now does this using autotools.
|
||||
|
||||
Windows Vista and higher is now supported as a build target through the use of
|
||||
cmake. See README.md for the instructions. Other platforms should continue to
|
||||
use autotools.
|
||||
|
||||
The test suite has been improved and more tests added. We now generate random
|
||||
seeds on every run to help catch more errors with additional fuzzing passes.
|
||||
By default, the test suite will run all tests in parallel with subprocesses.
|
||||
This should speed up execution of `make test' for contributors.
|
||||
|
||||
bson_string_t went through an ABI break to support power-of-two growth.
|
||||
|
||||
JSON parsing has been added through the bson_json_reader_t type. You can also
|
||||
now use bson_init_from_json() for a simplified interface.
|
||||
|
||||
Types were revamped to appear to be using C99 types. If C99 types are
|
||||
available, they will be used. If not, they will be emulated. This means you
|
||||
can just go on using uint64_t and similar. We even use bool now.
|
||||
|
||||
Many functions have been made portable to deal with inconsistencies with Win32.
|
||||
|
||||
This release has been tested on the following operating systems:
|
||||
|
||||
* RedHat Enterprise 5, 6, and 7 beta.
|
||||
* CentOS 6.5
|
||||
* Ubuntu 12.04 LTS
|
||||
* Fedora 20
|
||||
* Windows 7
|
||||
* FreeBSD 10
|
||||
* DragonFly BSD
|
||||
* Solaris 11
|
||||
* SmartOS
|
||||
* mingw64
|
||||
|
||||
Thanks again and enjoy using libbson!
|
||||
|
||||
Libbson 0.4.0
|
||||
=============
|
||||
|
||||
This release includes a few bug fixes and copious documentation. Additionally,
|
||||
we improved our fuzz testing and found a couple issues in the process. It is
|
||||
suggested that everyone upgrade their installations to 0.4.0.
|
||||
|
||||
We have been busy adding a lot of documentation that we hope you will like.
|
||||
Many `man' pages have been added for various API endpoints and structures. If
|
||||
you use vim, remember that you can jump to the documentation with <shift>k
|
||||
while on a symbol.
|
||||
|
||||
Thanks and enjoy using libbson!
|
||||
|
||||
Libbson 0.2.4
|
||||
=============
|
||||
|
||||
This release includes some more performance improvements and bug fixes.
|
||||
|
||||
It contains an important fix for dealing with invalid string lengths that could
|
||||
cause an integer overflow when checking to see if the string length fits within
|
||||
the end of the buffer.
|
||||
|
||||
There is preliminary support for Solaris on x86_64 and SPARC.
|
||||
|
||||
Generating OIDs is now simpler with the use of bson_context_get_default(). This
|
||||
function will return a thread-safe generic bson_context_t implementation.
|
||||
Alternatively, you may pass NULL to bson_oid_init() for the context and the
|
||||
default context is automatically used.
|
||||
|
||||
The fuzz tests now use srand() with a 32-bit integer derived from /dev/urandom.
|
||||
|
||||
Endianess conversions are now performed by __builtin_bswap*() functions when
|
||||
available with the GCC compiler.
|
||||
|
||||
Endianness conversions for the double type are now properly handled on
|
||||
big-endian systems.
|
||||
|
||||
bson_reinit() has been added to cleanup code that needs to destroy and then
|
||||
initialize a bson_t.
|
||||
|
||||
Validation of Code with Scope fields was absent from bson_validate(). This is
|
||||
now supported.
|
||||
|
||||
Libbson 0.2.2
|
||||
=============
|
||||
|
||||
This release includes a few performance improvements and bug fixes.
|
||||
|
||||
The bson_t structure is more efficient when growing allocated buffers.
|
||||
The use of memalign() was unnecessary for allocated bson_t structures
|
||||
and has therefore been removed. Performance sensitive allocations now
|
||||
use bson_malloc() instead of calloc() and initialize fields directly.
|
||||
Stack alignment of bson_t is now enforced through compiler intrinsics.
|
||||
|
||||
The unit tests can now support running inside of valgrind to check for
|
||||
various memory leaks. Simply defing VALGRIND=valgrind when running
|
||||
`make test`.
|
||||
|
||||
Enjoy libbson-0.2.2!
|
||||
|
||||
|
||||
Libbson 0.2.0
|
||||
=============
|
||||
|
||||
This is the initial release of Libbson. It has not yet reached API and ABI
|
||||
maturity and is therefore subject to change without notice. Developers are
|
||||
encouraged to start using Libbson as we journey on the road to 1.0, where ABI
|
||||
stability will be guaranteed.
|
||||
|
||||
Libbson is Apache 2.0 licensed so that it can be embedded in a multitude of
|
||||
scenarios. This means that we try hard to not rely on external libraries.
|
||||
Therefore, Libbson contains useful routines to help in portability as well
|
||||
as BSON support.
|
||||
|
||||
Libbson is the basis of a new MongoDB C driver that will follow shortly.
|
||||
|
||||
Please see the doc/ directory for documentation on how to use Libbson. We
|
||||
would love for you to contribute to Libbson, whether that is code,
|
||||
documentation or packaging.
|
||||
@@ -0,0 +1 @@
|
||||
1.3.5
|
||||
@@ -0,0 +1 @@
|
||||
1.3.5
|
||||
@@ -0,0 +1,36 @@
|
||||
function(LoadVersion FILEPATH PREFIX)
|
||||
# E.g., "BSON_VERSION".
|
||||
string(REPLACE ";" "" VERSION_NAME ${PREFIX} _VERSION)
|
||||
|
||||
file(STRINGS ${FILEPATH} VERSION_CONTENTS)
|
||||
|
||||
# A list of version components separated by dots and dashes: "1.3.0-dev"
|
||||
string(REGEX MATCHALL "[^.-]+" VERSION ${VERSION_CONTENTS})
|
||||
|
||||
list(GET VERSION 0 MAJOR_VERSION)
|
||||
string(REPLACE ";" "" MAJOR_VERSION_NAME ${PREFIX} _MAJOR_VERSION)
|
||||
set(${MAJOR_VERSION_NAME} ${MAJOR_VERSION} PARENT_SCOPE)
|
||||
|
||||
list(GET VERSION 1 MINOR_VERSION)
|
||||
string(REPLACE ";" "" MINOR_VERSION_NAME ${PREFIX} _MINOR_VERSION)
|
||||
set(${MINOR_VERSION_NAME} ${MINOR_VERSION} PARENT_SCOPE)
|
||||
|
||||
list(GET VERSION 2 MICRO_VERSION)
|
||||
string(REPLACE ";" "" MICRO_VERSION_NAME ${PREFIX} _MICRO_VERSION)
|
||||
set(${MICRO_VERSION_NAME} ${MICRO_VERSION} PARENT_SCOPE)
|
||||
|
||||
string(REPLACE ";" "" PRERELEASE_VERSION_NAME ${PREFIX} _PRERELEASE_VERSION)
|
||||
list(LENGTH VERSION VERSION_LENGTH)
|
||||
if(VERSION_LENGTH GREATER 3)
|
||||
list(GET VERSION 3 PRERELEASE_VERSION)
|
||||
set(${PRERELEASE_VERSION_NAME} ${PRERELEASE_VERSION} PARENT_SCOPE)
|
||||
set(${VERSION_NAME}
|
||||
"${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}-${PRERELEASE_VERSION}"
|
||||
PARENT_SCOPE)
|
||||
else()
|
||||
set(${PRERELEASE_VERSION_NAME} "" PARENT_SCOPE)
|
||||
set(${VERSION_NAME}
|
||||
"${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}"
|
||||
PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction(LoadVersion)
|
||||
@@ -0,0 +1 @@
|
||||
#include <stdint.h>
|
||||
@@ -0,0 +1,183 @@
|
||||
EXPORTS
|
||||
bcon_append
|
||||
bcon_append_ctx
|
||||
bcon_append_ctx_init
|
||||
bcon_append_ctx_va
|
||||
bcon_new
|
||||
bcon_extract
|
||||
bcon_extract_ctx
|
||||
bcon_extract_ctx_init
|
||||
bcon_extract_ctx_va
|
||||
bson_append_array
|
||||
bson_append_array_begin
|
||||
bson_append_array_end
|
||||
bson_append_binary
|
||||
bson_append_bool
|
||||
bson_append_code
|
||||
bson_append_code_with_scope
|
||||
bson_append_date_time
|
||||
bson_append_dbpointer
|
||||
bson_append_document
|
||||
bson_append_document_begin
|
||||
bson_append_document_end
|
||||
bson_append_double
|
||||
bson_append_int32
|
||||
bson_append_int64
|
||||
bson_append_iter
|
||||
bson_append_maxkey
|
||||
bson_append_minkey
|
||||
bson_append_now_utc
|
||||
bson_append_null
|
||||
bson_append_oid
|
||||
bson_append_regex
|
||||
bson_append_symbol
|
||||
bson_append_timestamp
|
||||
bson_append_time_t
|
||||
bson_append_timeval
|
||||
bson_append_undefined
|
||||
bson_append_utf8
|
||||
bson_append_value
|
||||
bson_array_as_json
|
||||
bson_as_json
|
||||
bson_ascii_strtoll
|
||||
bson_bcon_magic
|
||||
bson_bcone_magic
|
||||
bson_check_version
|
||||
bson_compare
|
||||
bson_concat
|
||||
bson_context_destroy
|
||||
bson_context_new
|
||||
bson_context_get_default
|
||||
bson_copy
|
||||
bson_copy_to
|
||||
bson_copy_to_excluding
|
||||
bson_copy_to_excluding_noinit
|
||||
bson_count_keys
|
||||
bson_destroy
|
||||
bson_destroy_with_steal
|
||||
bson_equal
|
||||
bson_free
|
||||
bson_get_data
|
||||
bson_get_major_version
|
||||
bson_get_micro_version
|
||||
bson_get_minor_version
|
||||
bson_get_monotonic_time
|
||||
bson_get_version
|
||||
bson_gettimeofday
|
||||
bson_has_field
|
||||
bson_init
|
||||
bson_init_from_json
|
||||
bson_init_static
|
||||
bson_iter_array
|
||||
bson_iter_as_bool
|
||||
bson_iter_as_int64
|
||||
bson_iter_binary
|
||||
bson_iter_bool
|
||||
bson_iter_code
|
||||
bson_iter_codewscope
|
||||
bson_iter_date_time
|
||||
bson_iter_dbpointer
|
||||
bson_iter_document
|
||||
bson_iter_double
|
||||
bson_iter_dup_utf8
|
||||
bson_iter_find
|
||||
bson_iter_find_case
|
||||
bson_iter_find_descendant
|
||||
bson_iter_init
|
||||
bson_iter_init_find
|
||||
bson_iter_init_find_case
|
||||
bson_iter_int32
|
||||
bson_iter_int64
|
||||
bson_iter_key
|
||||
bson_iter_next
|
||||
bson_iter_oid
|
||||
bson_iter_overwrite_bool
|
||||
bson_iter_overwrite_double
|
||||
bson_iter_overwrite_int32
|
||||
bson_iter_overwrite_int64
|
||||
bson_iter_recurse
|
||||
bson_iter_regex
|
||||
bson_iter_symbol
|
||||
bson_iter_timestamp
|
||||
bson_iter_time_t
|
||||
bson_iter_timeval
|
||||
bson_iter_type
|
||||
bson_iter_utf8
|
||||
bson_iter_value
|
||||
bson_iter_visit_all
|
||||
bson_json_data_reader_ingest
|
||||
bson_json_data_reader_new
|
||||
bson_json_reader_destroy
|
||||
bson_json_reader_new
|
||||
bson_json_reader_new_from_fd
|
||||
bson_json_reader_new_from_file
|
||||
bson_json_reader_read
|
||||
bson_malloc
|
||||
bson_malloc0
|
||||
bson_md5_init
|
||||
bson_md5_finish
|
||||
bson_md5_append
|
||||
bson_mem_set_vtable
|
||||
bson_mem_restore_vtable
|
||||
bson_new
|
||||
bson_new_from_buffer
|
||||
bson_new_from_data
|
||||
bson_new_from_json
|
||||
bson_oid_compare
|
||||
bson_oid_copy
|
||||
bson_oid_equal
|
||||
bson_oid_get_time_t
|
||||
bson_oid_hash
|
||||
bson_oid_init
|
||||
bson_oid_init_from_data
|
||||
bson_oid_init_from_string
|
||||
bson_oid_init_sequence
|
||||
bson_oid_is_valid
|
||||
bson_oid_to_string
|
||||
bson_reader_destroy
|
||||
bson_reader_new_from_data
|
||||
bson_reader_new_from_fd
|
||||
bson_reader_new_from_file
|
||||
bson_reader_new_from_handle
|
||||
bson_reader_read
|
||||
bson_reader_set_read_func
|
||||
bson_reader_set_destroy_func
|
||||
bson_reader_tell
|
||||
bson_realloc
|
||||
bson_realloc_ctx
|
||||
bson_reinit
|
||||
bson_set_error
|
||||
bson_sized_new
|
||||
bson_snprintf
|
||||
bson_strdup
|
||||
bson_strdup_printf
|
||||
bson_strdupv_printf
|
||||
bson_strfreev
|
||||
bson_strerror_r
|
||||
bson_string_append
|
||||
bson_string_append_c
|
||||
bson_string_append_printf
|
||||
bson_string_append_unichar
|
||||
bson_string_free
|
||||
bson_string_new
|
||||
bson_string_truncate
|
||||
bson_strncpy
|
||||
bson_strndup
|
||||
bson_strnlen
|
||||
bson_uint32_to_string
|
||||
bson_utf8_escape_for_json
|
||||
bson_utf8_from_unichar
|
||||
bson_utf8_get_char
|
||||
bson_utf8_next_char
|
||||
bson_utf8_validate
|
||||
bson_validate
|
||||
bson_value_copy
|
||||
bson_value_destroy
|
||||
bson_vsnprintf
|
||||
bson_writer_begin
|
||||
bson_writer_destroy
|
||||
bson_writer_end
|
||||
bson_writer_get_length
|
||||
bson_writer_new
|
||||
bson_writer_rollback
|
||||
bson_zero_free
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1998 by Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright (c) 1995 by International Business Machines, Inc.
|
||||
*
|
||||
* International Business Machines, Inc. (hereinafter called IBM) grants
|
||||
* permission under its copyrights to use, copy, modify, and distribute this
|
||||
* Software with or without fee, provided that the above copyright notice and
|
||||
* all paragraphs of this notice appear in all copies, and that the name of IBM
|
||||
* not be used in connection with the marketing of any product incorporating
|
||||
* the Software or modifications thereof, without specific, written prior
|
||||
* permission.
|
||||
*
|
||||
* To the extent it has a right to do so, IBM grants an immunity from suit
|
||||
* under its patents, if any, for the use, sale or manufacture of products to
|
||||
* the extent that such products are used for performing Domain Name System
|
||||
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
|
||||
* granted for any product per se or for any other function of any product.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
|
||||
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
|
||||
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
#define Assert(Cond) if (!(Cond)) abort ()
|
||||
|
||||
static const char Base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char Pad64 = '=';
|
||||
|
||||
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
|
||||
* The following encoding technique is taken from RFC 1521 by Borenstein
|
||||
* and Freed. It is reproduced here in a slightly edited form for
|
||||
* convenience.
|
||||
*
|
||||
* A 65-character subset of US-ASCII is used, enabling 6 bits to be
|
||||
* represented per printable character. (The extra 65th character, "=",
|
||||
* is used to signify a special processing function.)
|
||||
*
|
||||
* The encoding process represents 24-bit groups of input bits as output
|
||||
* strings of 4 encoded characters. Proceeding from left to right, a
|
||||
* 24-bit input group is formed by concatenating 3 8-bit input groups.
|
||||
* These 24 bits are then treated as 4 concatenated 6-bit groups, each
|
||||
* of which is translated into a single digit in the base64 alphabet.
|
||||
*
|
||||
* Each 6-bit group is used as an index into an array of 64 printable
|
||||
* characters. The character referenced by the index is placed in the
|
||||
* output string.
|
||||
*
|
||||
* Table 1: The Base64 Alphabet
|
||||
*
|
||||
* Value Encoding Value Encoding Value Encoding Value Encoding
|
||||
* 0 A 17 R 34 i 51 z
|
||||
* 1 B 18 S 35 j 52 0
|
||||
* 2 C 19 T 36 k 53 1
|
||||
* 3 D 20 U 37 l 54 2
|
||||
* 4 E 21 V 38 m 55 3
|
||||
* 5 F 22 W 39 n 56 4
|
||||
* 6 G 23 X 40 o 57 5
|
||||
* 7 H 24 Y 41 p 58 6
|
||||
* 8 I 25 Z 42 q 59 7
|
||||
* 9 J 26 a 43 r 60 8
|
||||
* 10 K 27 b 44 s 61 9
|
||||
* 11 L 28 c 45 t 62 +
|
||||
* 12 M 29 d 46 u 63 /
|
||||
* 13 N 30 e 47 v
|
||||
* 14 O 31 f 48 w (pad) =
|
||||
* 15 P 32 g 49 x
|
||||
* 16 Q 33 h 50 y
|
||||
*
|
||||
* Special processing is performed if fewer than 24 bits are available
|
||||
* at the end of the data being encoded. A full encoding quantum is
|
||||
* always completed at the end of a quantity. When fewer than 24 input
|
||||
* bits are available in an input group, zero bits are added (on the
|
||||
* right) to form an integral number of 6-bit groups. Padding at the
|
||||
* end of the data is performed using the '=' character.
|
||||
*
|
||||
* Since all base64 input is an integral number of octets, only the
|
||||
* following cases can arise:
|
||||
*
|
||||
* (1) the final quantum of encoding input is an integral
|
||||
* multiple of 24 bits; here, the final unit of encoded
|
||||
* output will be an integral multiple of 4 characters
|
||||
* with no "=" padding,
|
||||
* (2) the final quantum of encoding input is exactly 8 bits;
|
||||
* here, the final unit of encoded output will be two
|
||||
* characters followed by two "=" padding characters, or
|
||||
* (3) the final quantum of encoding input is exactly 16 bits;
|
||||
* here, the final unit of encoded output will be three
|
||||
* characters followed by one "=" padding character.
|
||||
*/
|
||||
|
||||
static ssize_t
|
||||
b64_ntop (uint8_t const *src,
|
||||
size_t srclength,
|
||||
char *target,
|
||||
size_t targsize)
|
||||
{
|
||||
size_t datalength = 0;
|
||||
uint8_t input[3];
|
||||
uint8_t output[4];
|
||||
size_t i;
|
||||
|
||||
while (2 < srclength) {
|
||||
input[0] = *src++;
|
||||
input[1] = *src++;
|
||||
input[2] = *src++;
|
||||
srclength -= 3;
|
||||
|
||||
output[0] = input[0] >> 2;
|
||||
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
||||
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
||||
output[3] = input[2] & 0x3f;
|
||||
Assert (output[0] < 64);
|
||||
Assert (output[1] < 64);
|
||||
Assert (output[2] < 64);
|
||||
Assert (output[3] < 64);
|
||||
|
||||
if (datalength + 4 > targsize) {
|
||||
return -1;
|
||||
}
|
||||
target[datalength++] = Base64[output[0]];
|
||||
target[datalength++] = Base64[output[1]];
|
||||
target[datalength++] = Base64[output[2]];
|
||||
target[datalength++] = Base64[output[3]];
|
||||
}
|
||||
|
||||
/* Now we worry about padding. */
|
||||
if (0 != srclength) {
|
||||
/* Get what's left. */
|
||||
input[0] = input[1] = input[2] = '\0';
|
||||
|
||||
for (i = 0; i < srclength; i++) {
|
||||
input[i] = *src++;
|
||||
}
|
||||
output[0] = input[0] >> 2;
|
||||
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
||||
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
||||
Assert (output[0] < 64);
|
||||
Assert (output[1] < 64);
|
||||
Assert (output[2] < 64);
|
||||
|
||||
if (datalength + 4 > targsize) {
|
||||
return -1;
|
||||
}
|
||||
target[datalength++] = Base64[output[0]];
|
||||
target[datalength++] = Base64[output[1]];
|
||||
|
||||
if (srclength == 1) {
|
||||
target[datalength++] = Pad64;
|
||||
} else{
|
||||
target[datalength++] = Base64[output[2]];
|
||||
}
|
||||
target[datalength++] = Pad64;
|
||||
}
|
||||
|
||||
if (datalength >= targsize) {
|
||||
return -1;
|
||||
}
|
||||
target[datalength] = '\0'; /* Returned value doesn't count \0. */
|
||||
return datalength;
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1998 by Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright (c) 1995 by International Business Machines, Inc.
|
||||
*
|
||||
* International Business Machines, Inc. (hereinafter called IBM) grants
|
||||
* permission under its copyrights to use, copy, modify, and distribute this
|
||||
* Software with or without fee, provided that the above copyright notice and
|
||||
* all paragraphs of this notice appear in all copies, and that the name of IBM
|
||||
* not be used in connection with the marketing of any product incorporating
|
||||
* the Software or modifications thereof, without specific, written prior
|
||||
* permission.
|
||||
*
|
||||
* To the extent it has a right to do so, IBM grants an immunity from suit
|
||||
* under its patents, if any, for the use, sale or manufacture of products to
|
||||
* the extent that such products are used for performing Domain Name System
|
||||
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
|
||||
* granted for any product per se or for any other function of any product.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
|
||||
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
|
||||
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include "bson-compat.h"
|
||||
|
||||
#define Assert(Cond) if (!(Cond)) abort()
|
||||
|
||||
static const char Base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char Pad64 = '=';
|
||||
|
||||
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
|
||||
The following encoding technique is taken from RFC 1521 by Borenstein
|
||||
and Freed. It is reproduced here in a slightly edited form for
|
||||
convenience.
|
||||
|
||||
A 65-character subset of US-ASCII is used, enabling 6 bits to be
|
||||
represented per printable character. (The extra 65th character, "=",
|
||||
is used to signify a special processing function.)
|
||||
|
||||
The encoding process represents 24-bit groups of input bits as output
|
||||
strings of 4 encoded characters. Proceeding from left to right, a
|
||||
24-bit input group is formed by concatenating 3 8-bit input groups.
|
||||
These 24 bits are then treated as 4 concatenated 6-bit groups, each
|
||||
of which is translated into a single digit in the base64 alphabet.
|
||||
|
||||
Each 6-bit group is used as an index into an array of 64 printable
|
||||
characters. The character referenced by the index is placed in the
|
||||
output string.
|
||||
|
||||
Table 1: The Base64 Alphabet
|
||||
|
||||
Value Encoding Value Encoding Value Encoding Value Encoding
|
||||
0 A 17 R 34 i 51 z
|
||||
1 B 18 S 35 j 52 0
|
||||
2 C 19 T 36 k 53 1
|
||||
3 D 20 U 37 l 54 2
|
||||
4 E 21 V 38 m 55 3
|
||||
5 F 22 W 39 n 56 4
|
||||
6 G 23 X 40 o 57 5
|
||||
7 H 24 Y 41 p 58 6
|
||||
8 I 25 Z 42 q 59 7
|
||||
9 J 26 a 43 r 60 8
|
||||
10 K 27 b 44 s 61 9
|
||||
11 L 28 c 45 t 62 +
|
||||
12 M 29 d 46 u 63 /
|
||||
13 N 30 e 47 v
|
||||
14 O 31 f 48 w (pad) =
|
||||
15 P 32 g 49 x
|
||||
16 Q 33 h 50 y
|
||||
|
||||
Special processing is performed if fewer than 24 bits are available
|
||||
at the end of the data being encoded. A full encoding quantum is
|
||||
always completed at the end of a quantity. When fewer than 24 input
|
||||
bits are available in an input group, zero bits are added (on the
|
||||
right) to form an integral number of 6-bit groups. Padding at the
|
||||
end of the data is performed using the '=' character.
|
||||
|
||||
Since all base64 input is an integral number of octets, only the
|
||||
following cases can arise:
|
||||
|
||||
(1) the final quantum of encoding input is an integral
|
||||
multiple of 24 bits; here, the final unit of encoded
|
||||
output will be an integral multiple of 4 characters
|
||||
with no "=" padding,
|
||||
(2) the final quantum of encoding input is exactly 8 bits;
|
||||
here, the final unit of encoded output will be two
|
||||
characters followed by two "=" padding characters, or
|
||||
(3) the final quantum of encoding input is exactly 16 bits;
|
||||
here, the final unit of encoded output will be three
|
||||
characters followed by one "=" padding character.
|
||||
*/
|
||||
|
||||
/* skips all whitespace anywhere.
|
||||
converts characters, four at a time, starting at (or after)
|
||||
src from base - 64 numbers into three 8 bit bytes in the target area.
|
||||
it returns the number of data bytes stored at the target, or -1 on error.
|
||||
*/
|
||||
|
||||
static int b64rmap_initialized = 0;
|
||||
static uint8_t b64rmap[256];
|
||||
|
||||
static const uint8_t b64rmap_special = 0xf0;
|
||||
static const uint8_t b64rmap_end = 0xfd;
|
||||
static const uint8_t b64rmap_space = 0xfe;
|
||||
static const uint8_t b64rmap_invalid = 0xff;
|
||||
|
||||
/**
|
||||
* Initializing the reverse map is not thread safe.
|
||||
* Which is fine for NSD. For now...
|
||||
**/
|
||||
static void
|
||||
b64_initialize_rmap ()
|
||||
{
|
||||
int i;
|
||||
unsigned char ch;
|
||||
|
||||
/* Null: end of string, stop parsing */
|
||||
b64rmap[0] = b64rmap_end;
|
||||
|
||||
for (i = 1; i < 256; ++i) {
|
||||
ch = (unsigned char)i;
|
||||
/* Whitespaces */
|
||||
if (isspace(ch))
|
||||
b64rmap[i] = b64rmap_space;
|
||||
/* Padding: stop parsing */
|
||||
else if (ch == Pad64)
|
||||
b64rmap[i] = b64rmap_end;
|
||||
/* Non-base64 char */
|
||||
else
|
||||
b64rmap[i] = b64rmap_invalid;
|
||||
}
|
||||
|
||||
/* Fill reverse mapping for base64 chars */
|
||||
for (i = 0; Base64[i] != '\0'; ++i)
|
||||
b64rmap[(uint8_t)Base64[i]] = i;
|
||||
|
||||
b64rmap_initialized = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
b64_pton_do(char const *src, uint8_t *target, size_t targsize)
|
||||
{
|
||||
int tarindex, state, ch;
|
||||
uint8_t ofs;
|
||||
|
||||
state = 0;
|
||||
tarindex = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ch = *src++;
|
||||
ofs = b64rmap[ch];
|
||||
|
||||
if (ofs >= b64rmap_special) {
|
||||
/* Ignore whitespaces */
|
||||
if (ofs == b64rmap_space)
|
||||
continue;
|
||||
/* End of base64 characters */
|
||||
if (ofs == b64rmap_end)
|
||||
break;
|
||||
/* A non-base64 character. */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
if ((size_t)tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] = ofs << 2;
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
if ((size_t)tarindex + 1 >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= ofs >> 4;
|
||||
target[tarindex+1] = (ofs & 0x0f)
|
||||
<< 4 ;
|
||||
tarindex++;
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
if ((size_t)tarindex + 1 >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= ofs >> 2;
|
||||
target[tarindex+1] = (ofs & 0x03)
|
||||
<< 6;
|
||||
tarindex++;
|
||||
state = 3;
|
||||
break;
|
||||
case 3:
|
||||
if ((size_t)tarindex >= targsize)
|
||||
return (-1);
|
||||
target[tarindex] |= ofs;
|
||||
tarindex++;
|
||||
state = 0;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We are done decoding Base-64 chars. Let's see if we ended
|
||||
* on a byte boundary, and/or with erroneous trailing characters.
|
||||
*/
|
||||
|
||||
if (ch == Pad64) { /* We got a pad char. */
|
||||
ch = *src++; /* Skip it, get next. */
|
||||
switch (state) {
|
||||
case 0: /* Invalid = in first position */
|
||||
case 1: /* Invalid = in second position */
|
||||
return (-1);
|
||||
|
||||
case 2: /* Valid, means one byte of info */
|
||||
/* Skip any number of spaces. */
|
||||
for ((void)NULL; ch != '\0'; ch = *src++)
|
||||
if (b64rmap[ch] != b64rmap_space)
|
||||
break;
|
||||
/* Make sure there is another trailing = sign. */
|
||||
if (ch != Pad64)
|
||||
return (-1);
|
||||
ch = *src++; /* Skip the = */
|
||||
/* Fall through to "single trailing =" case. */
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case 3: /* Valid, means two bytes of info */
|
||||
/*
|
||||
* We know this char is an =. Is there anything but
|
||||
* whitespace after it?
|
||||
*/
|
||||
for ((void)NULL; ch != '\0'; ch = *src++)
|
||||
if (b64rmap[ch] != b64rmap_space)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Now make sure for cases 2 and 3 that the "extra"
|
||||
* bits that slopped past the last full byte were
|
||||
* zeros. If we don't check them, they become a
|
||||
* subliminal channel.
|
||||
*/
|
||||
if (target[tarindex] != 0)
|
||||
return (-1);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We ended by seeing the end of the string. Make sure we
|
||||
* have no partial bytes lying around.
|
||||
*/
|
||||
if (state != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (tarindex);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
b64_pton_len(char const *src)
|
||||
{
|
||||
int tarindex, state, ch;
|
||||
uint8_t ofs;
|
||||
|
||||
state = 0;
|
||||
tarindex = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ch = *src++;
|
||||
ofs = b64rmap[ch];
|
||||
|
||||
if (ofs >= b64rmap_special) {
|
||||
/* Ignore whitespaces */
|
||||
if (ofs == b64rmap_space)
|
||||
continue;
|
||||
/* End of base64 characters */
|
||||
if (ofs == b64rmap_end)
|
||||
break;
|
||||
/* A non-base64 character. */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
tarindex++;
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
tarindex++;
|
||||
state = 3;
|
||||
break;
|
||||
case 3:
|
||||
tarindex++;
|
||||
state = 0;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We are done decoding Base-64 chars. Let's see if we ended
|
||||
* on a byte boundary, and/or with erroneous trailing characters.
|
||||
*/
|
||||
|
||||
if (ch == Pad64) { /* We got a pad char. */
|
||||
ch = *src++; /* Skip it, get next. */
|
||||
switch (state) {
|
||||
case 0: /* Invalid = in first position */
|
||||
case 1: /* Invalid = in second position */
|
||||
return (-1);
|
||||
|
||||
case 2: /* Valid, means one byte of info */
|
||||
/* Skip any number of spaces. */
|
||||
for ((void)NULL; ch != '\0'; ch = *src++)
|
||||
if (b64rmap[ch] != b64rmap_space)
|
||||
break;
|
||||
/* Make sure there is another trailing = sign. */
|
||||
if (ch != Pad64)
|
||||
return (-1);
|
||||
ch = *src++; /* Skip the = */
|
||||
/* Fall through to "single trailing =" case. */
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case 3: /* Valid, means two bytes of info */
|
||||
/*
|
||||
* We know this char is an =. Is there anything but
|
||||
* whitespace after it?
|
||||
*/
|
||||
for ((void)NULL; ch != '\0'; ch = *src++)
|
||||
if (b64rmap[ch] != b64rmap_space)
|
||||
return (-1);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We ended by seeing the end of the string. Make sure we
|
||||
* have no partial bytes lying around.
|
||||
*/
|
||||
if (state != 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (tarindex);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
b64_pton(char const *src, uint8_t *target, size_t targsize)
|
||||
{
|
||||
if (!b64rmap_initialized)
|
||||
b64_initialize_rmap ();
|
||||
|
||||
if (target)
|
||||
return b64_pton_do (src, target, targsize);
|
||||
else
|
||||
return b64_pton_len (src);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* @file bcon.h
|
||||
* @brief BCON (BSON C Object Notation) Declarations
|
||||
*/
|
||||
|
||||
/* Copyright 2009-2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef BCON_H_
|
||||
#define BCON_H_
|
||||
|
||||
#include <bson.h>
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BCON_STACK_MAX 100
|
||||
|
||||
#define BCON_ENSURE_DECLARE(fun, type) \
|
||||
static BSON_INLINE type bcon_ensure_##fun (type _t) { return _t; }
|
||||
|
||||
#define BCON_ENSURE(fun, val) \
|
||||
bcon_ensure_##fun (val)
|
||||
|
||||
#define BCON_ENSURE_STORAGE(fun, val) \
|
||||
bcon_ensure_##fun (&(val))
|
||||
|
||||
BCON_ENSURE_DECLARE (const_char_ptr, const char *)
|
||||
BCON_ENSURE_DECLARE (const_char_ptr_ptr, const char **)
|
||||
BCON_ENSURE_DECLARE (double, double)
|
||||
BCON_ENSURE_DECLARE (double_ptr, double *)
|
||||
BCON_ENSURE_DECLARE (const_bson_ptr, const bson_t *)
|
||||
BCON_ENSURE_DECLARE (bson_ptr, bson_t *)
|
||||
BCON_ENSURE_DECLARE (subtype, bson_subtype_t)
|
||||
BCON_ENSURE_DECLARE (subtype_ptr, bson_subtype_t *)
|
||||
BCON_ENSURE_DECLARE (const_uint8_ptr, const uint8_t *)
|
||||
BCON_ENSURE_DECLARE (const_uint8_ptr_ptr, const uint8_t **)
|
||||
BCON_ENSURE_DECLARE (uint32, uint32_t)
|
||||
BCON_ENSURE_DECLARE (uint32_ptr, uint32_t *)
|
||||
BCON_ENSURE_DECLARE (const_oid_ptr, const bson_oid_t *)
|
||||
BCON_ENSURE_DECLARE (const_oid_ptr_ptr, const bson_oid_t **)
|
||||
BCON_ENSURE_DECLARE (int32, int32_t)
|
||||
BCON_ENSURE_DECLARE (int32_ptr, int32_t *)
|
||||
BCON_ENSURE_DECLARE (int64, int64_t)
|
||||
BCON_ENSURE_DECLARE (int64_ptr, int64_t *)
|
||||
BCON_ENSURE_DECLARE (bool, bool)
|
||||
BCON_ENSURE_DECLARE (bool_ptr, bool *)
|
||||
BCON_ENSURE_DECLARE (bson_type, bson_type_t)
|
||||
BCON_ENSURE_DECLARE (bson_iter_ptr, bson_iter_t *)
|
||||
BCON_ENSURE_DECLARE (const_bson_iter_ptr, const bson_iter_t *)
|
||||
|
||||
#define BCON_UTF8(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_UTF8, BCON_ENSURE (const_char_ptr, (_val))
|
||||
#define BCON_DOUBLE(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_DOUBLE, BCON_ENSURE (double, (_val))
|
||||
#define BCON_DOCUMENT(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_DOCUMENT, BCON_ENSURE (const_bson_ptr, (_val))
|
||||
#define BCON_ARRAY(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_ARRAY, BCON_ENSURE (const_bson_ptr, (_val))
|
||||
#define BCON_BIN(_subtype, _binary, _length) \
|
||||
BCON_MAGIC, BCON_TYPE_BIN, \
|
||||
BCON_ENSURE (subtype, (_subtype)), \
|
||||
BCON_ENSURE (const_uint8_ptr, (_binary)), \
|
||||
BCON_ENSURE (uint32, (_length))
|
||||
#define BCON_UNDEFINED BCON_MAGIC, BCON_TYPE_UNDEFINED
|
||||
#define BCON_OID(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_OID, BCON_ENSURE (const_oid_ptr, (_val))
|
||||
#define BCON_BOOL(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_BOOL, BCON_ENSURE (bool, (_val))
|
||||
#define BCON_DATE_TIME(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_DATE_TIME, BCON_ENSURE (int64, (_val))
|
||||
#define BCON_NULL BCON_MAGIC, BCON_TYPE_NULL
|
||||
#define BCON_REGEX(_regex, _flags) \
|
||||
BCON_MAGIC, BCON_TYPE_REGEX, \
|
||||
BCON_ENSURE (const_char_ptr, (_regex)), \
|
||||
BCON_ENSURE (const_char_ptr, (_flags))
|
||||
#define BCON_DBPOINTER(_collection, _oid) \
|
||||
BCON_MAGIC, BCON_TYPE_DBPOINTER, \
|
||||
BCON_ENSURE (const_char_ptr, (_collection)), \
|
||||
BCON_ENSURE (const_oid_ptr, (_oid))
|
||||
#define BCON_CODE(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_CODE, BCON_ENSURE (const_char_ptr, (_val))
|
||||
#define BCON_SYMBOL(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_SYMBOL, BCON_ENSURE (const_char_ptr, (_val))
|
||||
#define BCON_CODEWSCOPE(_js, _scope) \
|
||||
BCON_MAGIC, BCON_TYPE_CODEWSCOPE, \
|
||||
BCON_ENSURE (const_char_ptr, (_js)), \
|
||||
BCON_ENSURE (const_bson_ptr, (_scope))
|
||||
#define BCON_INT32(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_INT32, BCON_ENSURE (int32, (_val))
|
||||
#define BCON_TIMESTAMP(_timestamp, _increment) \
|
||||
BCON_MAGIC, BCON_TYPE_TIMESTAMP, \
|
||||
BCON_ENSURE (int32, (_timestamp)), \
|
||||
BCON_ENSURE (int32, (_increment))
|
||||
#define BCON_INT64(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_INT64, BCON_ENSURE (int64, (_val))
|
||||
#define BCON_MAXKEY BCON_MAGIC, BCON_TYPE_MAXKEY
|
||||
#define BCON_MINKEY BCON_MAGIC, BCON_TYPE_MINKEY
|
||||
#define BCON(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_BCON, BCON_ENSURE (const_bson_ptr, (_val))
|
||||
#define BCON_ITER(_val) \
|
||||
BCON_MAGIC, BCON_TYPE_ITER, BCON_ENSURE (const_bson_iter_ptr, (_val))
|
||||
|
||||
#define BCONE_UTF8(_val) BCONE_MAGIC, BCON_TYPE_UTF8, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val))
|
||||
#define BCONE_DOUBLE(_val) BCONE_MAGIC, BCON_TYPE_DOUBLE, \
|
||||
BCON_ENSURE_STORAGE (double_ptr, (_val))
|
||||
#define BCONE_DOCUMENT(_val) BCONE_MAGIC, BCON_TYPE_DOCUMENT, \
|
||||
BCON_ENSURE_STORAGE (bson_ptr, (_val))
|
||||
#define BCONE_ARRAY(_val) BCONE_MAGIC, BCON_TYPE_ARRAY, \
|
||||
BCON_ENSURE_STORAGE (bson_ptr, (_val))
|
||||
#define BCONE_BIN(subtype, binary, length) \
|
||||
BCONE_MAGIC, BCON_TYPE_BIN, \
|
||||
BCON_ENSURE_STORAGE (subtype_ptr, (subtype)), \
|
||||
BCON_ENSURE_STORAGE (const_uint8_ptr_ptr, (binary)), \
|
||||
BCON_ENSURE_STORAGE (uint32_ptr, (length))
|
||||
#define BCONE_UNDEFINED BCONE_MAGIC, BCON_TYPE_UNDEFINED
|
||||
#define BCONE_OID(_val) BCONE_MAGIC, BCON_TYPE_OID, \
|
||||
BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_val))
|
||||
#define BCONE_BOOL(_val) BCONE_MAGIC, BCON_TYPE_BOOL, \
|
||||
BCON_ENSURE_STORAGE (bool_ptr, (_val))
|
||||
#define BCONE_DATE_TIME(_val) BCONE_MAGIC, BCON_TYPE_DATE_TIME, \
|
||||
BCON_ENSURE_STORAGE (int64_ptr, (_val))
|
||||
#define BCONE_NULL BCONE_MAGIC, BCON_TYPE_NULL
|
||||
#define BCONE_REGEX(_regex, _flags) \
|
||||
BCONE_MAGIC, BCON_TYPE_REGEX, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_regex)), \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_flags))
|
||||
#define BCONE_DBPOINTER(_collection, _oid) \
|
||||
BCONE_MAGIC, BCON_TYPE_DBPOINTER, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_collection)), \
|
||||
BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_oid))
|
||||
#define BCONE_CODE(_val) BCONE_MAGIC, BCON_TYPE_CODE, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val))
|
||||
#define BCONE_SYMBOL(_val) BCONE_MAGIC, BCON_TYPE_SYMBOL, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val))
|
||||
#define BCONE_CODEWSCOPE(_js, _scope) \
|
||||
BCONE_MAGIC, BCON_TYPE_CODEWSCOPE, \
|
||||
BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_js)), \
|
||||
BCON_ENSURE_STORAGE (bson_ptr, (_scope))
|
||||
#define BCONE_INT32(_val) BCONE_MAGIC, BCON_TYPE_INT32, \
|
||||
BCON_ENSURE_STORAGE (int32_ptr, (_val))
|
||||
#define BCONE_TIMESTAMP(_timestamp, _increment) \
|
||||
BCONE_MAGIC, BCON_TYPE_TIMESTAMP, \
|
||||
BCON_ENSURE_STORAGE (int32_ptr, (_timestamp)), \
|
||||
BCON_ENSURE_STORAGE (int32_ptr, (_increment))
|
||||
#define BCONE_INT64(_val) BCONE_MAGIC, BCON_TYPE_INT64, \
|
||||
BCON_ENSURE_STORAGE (int64_ptr, (_val))
|
||||
#define BCONE_MAXKEY BCONE_MAGIC, BCON_TYPE_MAXKEY
|
||||
#define BCONE_MINKEY BCONE_MAGIC, BCON_TYPE_MINKEY
|
||||
#define BCONE_SKIP(_val) BCONE_MAGIC, BCON_TYPE_SKIP, \
|
||||
BCON_ENSURE (bson_type, (_val))
|
||||
#define BCONE_ITER(_val) BCONE_MAGIC, BCON_TYPE_ITER, \
|
||||
BCON_ENSURE_STORAGE (bson_iter_ptr, (_val))
|
||||
|
||||
#define BCON_MAGIC bson_bcon_magic()
|
||||
#define BCONE_MAGIC bson_bcone_magic()
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BCON_TYPE_UTF8,
|
||||
BCON_TYPE_DOUBLE,
|
||||
BCON_TYPE_DOCUMENT,
|
||||
BCON_TYPE_ARRAY,
|
||||
BCON_TYPE_BIN,
|
||||
BCON_TYPE_UNDEFINED,
|
||||
BCON_TYPE_OID,
|
||||
BCON_TYPE_BOOL,
|
||||
BCON_TYPE_DATE_TIME,
|
||||
BCON_TYPE_NULL,
|
||||
BCON_TYPE_REGEX,
|
||||
BCON_TYPE_DBPOINTER,
|
||||
BCON_TYPE_CODE,
|
||||
BCON_TYPE_SYMBOL,
|
||||
BCON_TYPE_CODEWSCOPE,
|
||||
BCON_TYPE_INT32,
|
||||
BCON_TYPE_TIMESTAMP,
|
||||
BCON_TYPE_INT64,
|
||||
BCON_TYPE_MAXKEY,
|
||||
BCON_TYPE_MINKEY,
|
||||
BCON_TYPE_BCON,
|
||||
BCON_TYPE_ARRAY_START,
|
||||
BCON_TYPE_ARRAY_END,
|
||||
BCON_TYPE_DOC_START,
|
||||
BCON_TYPE_DOC_END,
|
||||
BCON_TYPE_END,
|
||||
BCON_TYPE_RAW,
|
||||
BCON_TYPE_SKIP,
|
||||
BCON_TYPE_ITER,
|
||||
BCON_TYPE_ERROR,
|
||||
} bcon_type_t;
|
||||
|
||||
typedef struct bcon_append_ctx_frame
|
||||
{
|
||||
int i;
|
||||
bool is_array;
|
||||
bson_t bson;
|
||||
} bcon_append_ctx_frame_t;
|
||||
|
||||
typedef struct bcon_extract_ctx_frame
|
||||
{
|
||||
int i;
|
||||
bool is_array;
|
||||
bson_iter_t iter;
|
||||
} bcon_extract_ctx_frame_t;
|
||||
|
||||
typedef struct _bcon_append_ctx_t
|
||||
{
|
||||
bcon_append_ctx_frame_t stack[BCON_STACK_MAX];
|
||||
int n;
|
||||
} bcon_append_ctx_t;
|
||||
|
||||
typedef struct _bcon_extract_ctx_t
|
||||
{
|
||||
bcon_extract_ctx_frame_t stack[BCON_STACK_MAX];
|
||||
int n;
|
||||
} bcon_extract_ctx_t;
|
||||
|
||||
void
|
||||
bcon_append (bson_t *bson,
|
||||
...) BSON_GNUC_NULL_TERMINATED;
|
||||
void
|
||||
bcon_append_ctx (bson_t *bson,
|
||||
bcon_append_ctx_t *ctx,
|
||||
...) BSON_GNUC_NULL_TERMINATED;
|
||||
void
|
||||
bcon_append_ctx_va (bson_t *bson,
|
||||
bcon_append_ctx_t *ctx,
|
||||
va_list *va);
|
||||
void
|
||||
bcon_append_ctx_init (bcon_append_ctx_t *ctx);
|
||||
|
||||
void
|
||||
bcon_extract_ctx_init (bcon_extract_ctx_t *ctx);
|
||||
|
||||
void
|
||||
bcon_extract_ctx (bson_t *bson,
|
||||
bcon_extract_ctx_t *ctx,
|
||||
...) BSON_GNUC_NULL_TERMINATED;
|
||||
|
||||
bool
|
||||
bcon_extract_ctx_va (bson_t *bson,
|
||||
bcon_extract_ctx_t *ctx,
|
||||
va_list *ap);
|
||||
|
||||
bool
|
||||
bcon_extract (bson_t *bson,
|
||||
...) BSON_GNUC_NULL_TERMINATED;
|
||||
|
||||
bool
|
||||
bcon_extract_va (bson_t *bson,
|
||||
bcon_extract_ctx_t *ctx,
|
||||
...) BSON_GNUC_NULL_TERMINATED;
|
||||
|
||||
bson_t *
|
||||
bcon_new (void *unused,
|
||||
...) BSON_GNUC_NULL_TERMINATED;
|
||||
|
||||
/**
|
||||
* The bcon_..() functions are all declared with __attribute__((sentinel)).
|
||||
*
|
||||
* From GCC manual for "sentinel": "A valid NULL in this context is defined as
|
||||
* zero with any pointer type. If your system defines the NULL macro with an
|
||||
* integer type then you need to add an explicit cast."
|
||||
* Case in point: GCC on Solaris (at least)
|
||||
*/
|
||||
#define BCON_APPEND(_bson, ...) \
|
||||
bcon_append ((_bson), __VA_ARGS__, (void *)NULL)
|
||||
#define BCON_APPEND_CTX(_bson, _ctx, ...) \
|
||||
bcon_append_ctx ((_bson), (_ctx), __VA_ARGS__, (void *)NULL)
|
||||
|
||||
#define BCON_EXTRACT(_bson, ...) \
|
||||
bcon_extract ((_bson), __VA_ARGS__, (void *)NULL)
|
||||
|
||||
#define BCON_EXTRACT_CTX(_bson, _ctx, ...) \
|
||||
bcon_extract ((_bson), (_ctx), __VA_ARGS__, (void *)NULL)
|
||||
|
||||
#define BCON_NEW(...) \
|
||||
bcon_new (NULL, __VA_ARGS__, (void *)NULL)
|
||||
|
||||
const char *bson_bcon_magic (void) BSON_GNUC_CONST;
|
||||
const char *bson_bcone_magic (void) BSON_GNUC_CONST;
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "bson-atomic.h"
|
||||
|
||||
|
||||
/*
|
||||
* We should only ever hit these on non-Windows systems, for which we require
|
||||
* pthread support. Therefore, we will avoid making a threading portability
|
||||
* for threads here and just use pthreads directly.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __BSON_NEED_BARRIER
|
||||
#include <pthread.h>
|
||||
static pthread_mutex_t gBarrier = PTHREAD_MUTEX_INITIALIZER;
|
||||
void
|
||||
bson_memory_barrier (void)
|
||||
{
|
||||
pthread_mutex_lock (&gBarrier);
|
||||
pthread_mutex_unlock (&gBarrier);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __BSON_NEED_ATOMIC_32
|
||||
#warning "Using mutex to emulate 32-bit atomics."
|
||||
#include <pthread.h>
|
||||
static pthread_mutex_t gSync32 = PTHREAD_MUTEX_INITIALIZER;
|
||||
int32_t
|
||||
bson_atomic_int_add (volatile int32_t *p,
|
||||
int32_t n)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pthread_mutex_lock (&gSync32);
|
||||
*p += n;
|
||||
ret = *p;
|
||||
pthread_mutex_unlock (&gSync32);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __BSON_NEED_ATOMIC_64
|
||||
#include <pthread.h>
|
||||
static pthread_mutex_t gSync64 = PTHREAD_MUTEX_INITIALIZER;
|
||||
int64_t
|
||||
bson_atomic_int64_add (volatile int64_t *p,
|
||||
int64_t n)
|
||||
{
|
||||
int64_t ret;
|
||||
|
||||
pthread_mutex_lock (&gSync64);
|
||||
*p += n;
|
||||
ret = *p;
|
||||
pthread_mutex_unlock (&gSync64);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2013-2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_ATOMIC_H
|
||||
#define BSON_ATOMIC_H
|
||||
|
||||
|
||||
#include "bson-config.h"
|
||||
#include "bson-compat.h"
|
||||
#include "bson-macros.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#if defined(__sun) && defined(__SVR4)
|
||||
/* Solaris */
|
||||
# include <atomic.h>
|
||||
# define bson_atomic_int_add(p,v) atomic_add_32_nv((volatile uint32_t *)p, (v))
|
||||
# define bson_atomic_int64_add(p,v) atomic_add_64_nv((volatile uint64_t *)p, (v))
|
||||
#elif defined(_WIN32)
|
||||
/* MSVC/MinGW */
|
||||
# define bson_atomic_int_add(p, v) (InterlockedExchangeAdd((volatile LONG *)(p), (LONG)(v)) + (LONG)(v))
|
||||
# define bson_atomic_int64_add(p, v) (InterlockedExchangeAdd64((volatile LONGLONG *)(p), (LONGLONG)(v)) + (LONGLONG)(v))
|
||||
#else
|
||||
# ifdef BSON_HAVE_ATOMIC_32_ADD_AND_FETCH
|
||||
# define bson_atomic_int_add(p,v) __sync_add_and_fetch((p), (v))
|
||||
# else
|
||||
# define __BSON_NEED_ATOMIC_32
|
||||
# endif
|
||||
# ifdef BSON_HAVE_ATOMIC_64_ADD_AND_FETCH
|
||||
# if BSON_GNUC_IS_VERSION(4, 1)
|
||||
/*
|
||||
* GCC 4.1 on i386 can generate buggy 64-bit atomic increment.
|
||||
* So we will work around with a fallback.
|
||||
*
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40693
|
||||
*/
|
||||
# define __BSON_NEED_ATOMIC_64
|
||||
# else
|
||||
# define bson_atomic_int64_add(p, v) __sync_add_and_fetch((volatile int64_t*)(p), (int64_t)(v))
|
||||
# endif
|
||||
# else
|
||||
# define __BSON_NEED_ATOMIC_64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __BSON_NEED_ATOMIC_32
|
||||
int32_t bson_atomic_int_add (volatile int32_t *p, int32_t n);
|
||||
#endif
|
||||
#ifdef __BSON_NEED_ATOMIC_64
|
||||
int64_t bson_atomic_int64_add (volatile int64_t *p, int64_t n);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define bson_memory_barrier() MemoryBarrier()
|
||||
#elif defined(__GNUC__)
|
||||
# if BSON_GNUC_CHECK_VERSION(4, 1)
|
||||
# define bson_memory_barrier() __sync_synchronize()
|
||||
# else
|
||||
# warning "GCC Pre-4.1 discovered, using inline assembly for memory barrier."
|
||||
# define bson_memory_barrier() __asm__ volatile ("":::"memory")
|
||||
# endif
|
||||
#elif defined(__SUNPRO_C)
|
||||
# include <mbarrier.h>
|
||||
# define bson_memory_barrier() __machine_rw_barrier()
|
||||
#elif defined(__xlC__)
|
||||
# define bson_memory_barrier() __sync()
|
||||
#else
|
||||
# define __BSON_NEED_BARRIER 1
|
||||
# warning "Unknown compiler, using lock for compiler barrier."
|
||||
void bson_memory_barrier (void);
|
||||
#endif
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_ATOMIC_H */
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <mach/clock.h>
|
||||
# include <mach/mach.h>
|
||||
# include <mach/mach_time.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson-config.h"
|
||||
#include "bson-compat.h"
|
||||
|
||||
|
||||
#if defined(BSON_HAVE_CLOCK_GETTIME)
|
||||
# include <time.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "bson-clock.h"
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_gettimeofday --
|
||||
*
|
||||
* A wrapper around gettimeofday() with fallback support for Windows.
|
||||
*
|
||||
* Returns:
|
||||
* 0 if successful.
|
||||
*
|
||||
* Side effects:
|
||||
* @tv is set.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
bson_gettimeofday (struct timeval *tv) /* OUT */
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
# if defined(_MSC_VER)
|
||||
# define DELTA_EPOCH_IN_MICROSEC 11644473600000000Ui64
|
||||
# else
|
||||
# define DELTA_EPOCH_IN_MICROSEC 11644473600000000ULL
|
||||
# endif
|
||||
FILETIME ft;
|
||||
uint64_t tmp = 0;
|
||||
|
||||
/*
|
||||
* The const value is shamelessy stolen from
|
||||
* http://www.boost.org/doc/libs/1_55_0/boost/chrono/detail/inlined/win/chrono.hpp
|
||||
*
|
||||
* File times are the number of 100 nanosecond intervals elapsed since
|
||||
* 12:00 am Jan 1, 1601 UTC. I haven't check the math particularly hard
|
||||
*
|
||||
* ... good luck
|
||||
*/
|
||||
|
||||
if (tv) {
|
||||
GetSystemTimeAsFileTime (&ft);
|
||||
|
||||
/* pull out of the filetime into a 64 bit uint */
|
||||
tmp |= ft.dwHighDateTime;
|
||||
tmp <<= 32;
|
||||
tmp |= ft.dwLowDateTime;
|
||||
|
||||
/* convert from 100's of nanosecs to microsecs */
|
||||
tmp /= 10;
|
||||
|
||||
/* adjust to unix epoch */
|
||||
tmp -= DELTA_EPOCH_IN_MICROSEC;
|
||||
|
||||
tv->tv_sec = (long)(tmp / 1000000UL);
|
||||
tv->tv_usec = (long)(tmp % 1000000UL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return gettimeofday (tv, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_get_monotonic_time --
|
||||
*
|
||||
* Returns the monotonic system time, if available. A best effort is
|
||||
* made to use the monotonic clock. However, some systems may not
|
||||
* support such a feature.
|
||||
*
|
||||
* Returns:
|
||||
* The monotonic clock in microseconds.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int64_t
|
||||
bson_get_monotonic_time (void)
|
||||
{
|
||||
#if defined(BSON_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
||||
struct timespec ts;
|
||||
clock_gettime (CLOCK_MONOTONIC, &ts);
|
||||
return ((ts.tv_sec * 1000000UL) + (ts.tv_nsec / 1000UL));
|
||||
#elif defined(__APPLE__)
|
||||
static mach_timebase_info_data_t info = { 0 };
|
||||
static double ratio = 0.0;
|
||||
|
||||
if (!info.denom) {
|
||||
// the value from mach_absolute_time () * info.numer / info.denom
|
||||
// is in nano seconds. So we have to divid by 1000.0 to get micro seconds
|
||||
mach_timebase_info (&info);
|
||||
ratio = (double)info.numer / (double)info.denom / 1000.0;
|
||||
}
|
||||
|
||||
return mach_absolute_time () * ratio;
|
||||
#elif defined(_WIN32)
|
||||
/* Despite it's name, this is in milliseconds! */
|
||||
int64_t ticks = GetTickCount64 ();
|
||||
return (ticks * 1000L);
|
||||
#else
|
||||
# warning "Monotonic clock is not yet supported on your platform."
|
||||
struct timeval tv;
|
||||
|
||||
bson_gettimeofday (&tv);
|
||||
return (tv.tv_sec * 1000000UL) + tv.tv_usec;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_CLOCK_H
|
||||
#define BSON_CLOCK_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
int64_t bson_get_monotonic_time (void);
|
||||
int bson_gettimeofday (struct timeval *tv);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_CLOCK_H */
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_COMPAT_H
|
||||
#define BSON_COMPAT_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
# if defined(__USE_MINGW_ANSI_STDIO)
|
||||
# if __USE_MINGW_ANSI_STDIO < 1
|
||||
# error "__USE_MINGW_ANSI_STDIO > 0 is required for correct PRI* macros"
|
||||
# endif
|
||||
# else
|
||||
# define __USE_MINGW_ANSI_STDIO 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "bson-config.h"
|
||||
#include "bson-macros.h"
|
||||
|
||||
|
||||
#ifdef BSON_OS_WIN32
|
||||
# if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600)
|
||||
# undef _WIN32_WINNT
|
||||
# endif
|
||||
# ifndef _WIN32_WINNT
|
||||
# define _WIN32_WINNT 0x0600
|
||||
# endif
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <winsock2.h>
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# undef WIN32_LEAN_AND_MEAN
|
||||
# else
|
||||
# include <windows.h>
|
||||
# endif
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef BSON_OS_UNIX
|
||||
# include <unistd.h>
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson-macros.h"
|
||||
|
||||
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include "bson-stdint-win32.h"
|
||||
# ifndef __cplusplus
|
||||
/* benign redefinition of type */
|
||||
# pragma warning (disable :4142)
|
||||
# ifndef _SSIZE_T_DEFINED
|
||||
# define _SSIZE_T_DEFINED
|
||||
typedef SSIZE_T ssize_t;
|
||||
# endif
|
||||
typedef SIZE_T size_t;
|
||||
# pragma warning (default :4142)
|
||||
# else
|
||||
/*
|
||||
* MSVC++ does not include ssize_t, just size_t.
|
||||
* So we need to synthesize that as well.
|
||||
*/
|
||||
# pragma warning (disable :4142)
|
||||
# ifndef _SSIZE_T_DEFINED
|
||||
# define _SSIZE_T_DEFINED
|
||||
typedef SSIZE_T ssize_t;
|
||||
# endif
|
||||
# pragma warning (default :4142)
|
||||
# endif
|
||||
# define PRIi32 "d"
|
||||
# define PRId32 "d"
|
||||
# define PRIu32 "u"
|
||||
# define PRIi64 "I64i"
|
||||
# define PRId64 "I64i"
|
||||
# define PRIu64 "I64u"
|
||||
#else
|
||||
# include "bson-stdint.h"
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) && ! defined(INIT_ONCE_STATIC_INIT)
|
||||
# define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT
|
||||
typedef RTL_RUN_ONCE INIT_ONCE;
|
||||
#endif
|
||||
|
||||
#ifdef BSON_HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#elif !defined(__bool_true_false_are_defined)
|
||||
# ifndef __cplusplus
|
||||
typedef signed char bool;
|
||||
# define false 0
|
||||
# define true 1
|
||||
# endif
|
||||
# define __bool_true_false_are_defined 1
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
|
||||
# define bson_sync_synchronize() __sync_synchronize()
|
||||
# elif defined(__i386__ ) || defined( __i486__ ) || defined( __i586__ ) || \
|
||||
defined( __i686__ ) || defined( __x86_64__ )
|
||||
# define bson_sync_synchronize() asm volatile("mfence":::"memory")
|
||||
# else
|
||||
# define bson_sync_synchronize() asm volatile("sync":::"memory")
|
||||
# endif
|
||||
#elif defined(_MSC_VER)
|
||||
# define bson_sync_synchronize() MemoryBarrier()
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(va_copy) && defined(_MSC_VER)
|
||||
# define va_copy(dst,src) ((dst) = (src))
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(va_copy) && defined(__GNUC__) && __GNUC__ < 3
|
||||
# define va_copy(dst,src) __va_copy(dst, src)
|
||||
#endif
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_COMPAT_H */
|
||||
@@ -0,0 +1,108 @@
|
||||
#ifndef BSON_CONFIG_H
|
||||
#define BSON_CONFIG_H
|
||||
|
||||
/*
|
||||
* Define to 1234 for Little Endian, 4321 for Big Endian.
|
||||
*/
|
||||
#define BSON_BYTE_ORDER @BSON_BYTE_ORDER@
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have stdbool.h
|
||||
*/
|
||||
#define BSON_HAVE_STDBOOL_H @BSON_HAVE_STDBOOL_H@
|
||||
#if BSON_HAVE_STDBOOL_H != 1
|
||||
# undef BSON_HAVE_STDBOOL_H
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 for POSIX-like systems, 2 for Windows.
|
||||
*/
|
||||
#define BSON_OS @BSON_OS@
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if we have access to GCC 32-bit atomic builtins.
|
||||
* While this requires GCC 4.1+ in most cases, it is also architecture
|
||||
* dependent. For example, some PPC or ARM systems may not have it even
|
||||
* if it is a recent GCC version.
|
||||
*/
|
||||
#define BSON_HAVE_ATOMIC_32_ADD_AND_FETCH @BSON_HAVE_ATOMIC_32_ADD_AND_FETCH@
|
||||
#if BSON_HAVE_ATOMIC_32_ADD_AND_FETCH != 1
|
||||
# undef BSON_HAVE_ATOMIC_32_ADD_AND_FETCH
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Similarly, define to 1 if we have access to GCC 64-bit atomic builtins.
|
||||
*/
|
||||
#define BSON_HAVE_ATOMIC_64_ADD_AND_FETCH @BSON_HAVE_ATOMIC_64_ADD_AND_FETCH@
|
||||
#if BSON_HAVE_ATOMIC_64_ADD_AND_FETCH != 1
|
||||
# undef BSON_HAVE_ATOMIC_64_ADD_AND_FETCH
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if your system requires {} around PTHREAD_ONCE_INIT.
|
||||
* This is typically just Solaris 8-10.
|
||||
*/
|
||||
#define BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES @BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES@
|
||||
#if BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES != 1
|
||||
# undef BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have clock_gettime() available.
|
||||
*/
|
||||
#define BSON_HAVE_CLOCK_GETTIME @BSON_HAVE_CLOCK_GETTIME@
|
||||
#if BSON_HAVE_CLOCK_GETTIME != 1
|
||||
# undef BSON_HAVE_CLOCK_GETTIME
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have strnlen available on your platform.
|
||||
*/
|
||||
#define BSON_HAVE_STRNLEN @BSON_HAVE_STRNLEN@
|
||||
#if BSON_HAVE_STRNLEN != 1
|
||||
# undef BSON_HAVE_STRNLEN
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have snprintf available on your platform.
|
||||
*/
|
||||
#define BSON_HAVE_SNPRINTF @BSON_HAVE_SNPRINTF@
|
||||
#if BSON_HAVE_SNPRINTF != 1
|
||||
# undef BSON_HAVE_SNPRINTF
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you have _set_output_format (VS2013 and older).
|
||||
*/
|
||||
#define BSON_NEEDS_SET_OUTPUT_FORMAT @BSON_NEEDS_SET_OUTPUT_FORMAT@
|
||||
#if BSON_NEEDS_SET_OUTPUT_FORMAT != 1
|
||||
# undef BSON_NEEDS_SET_OUTPUT_FORMAT
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define to 1 if you have struct timespec available on your platform.
|
||||
*/
|
||||
#define BSON_HAVE_TIMESPEC @BSON_HAVE_TIMESPEC@
|
||||
#if BSON_HAVE_TIMESPEC != 1
|
||||
# undef BSON_HAVE_TIMESPEC
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define to 1 if you want extra aligned types in libbson
|
||||
*/
|
||||
#define BSON_EXTRA_ALIGN @BSON_EXTRA_ALIGN@
|
||||
#if BSON_EXTRA_ALIGN != 1
|
||||
# undef BSON_EXTRA_ALIGN
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* BSON_CONFIG_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_CONTEXT_PRIVATE_H
|
||||
#define BSON_CONTEXT_PRIVATE_H
|
||||
|
||||
|
||||
#include "bson-context.h"
|
||||
#include "bson-thread-private.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
struct _bson_context_t
|
||||
{
|
||||
bson_context_flags_t flags : 7;
|
||||
bool pidbe_once : 1;
|
||||
uint8_t pidbe[2];
|
||||
uint8_t md5[3];
|
||||
int32_t seq32;
|
||||
int64_t seq64;
|
||||
|
||||
void (*oid_get_host) (bson_context_t *context,
|
||||
bson_oid_t *oid);
|
||||
void (*oid_get_pid) (bson_context_t *context,
|
||||
bson_oid_t *oid);
|
||||
void (*oid_get_seq32) (bson_context_t *context,
|
||||
bson_oid_t *oid);
|
||||
void (*oid_get_seq64) (bson_context_t *context,
|
||||
bson_oid_t *oid);
|
||||
};
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_CONTEXT_PRIVATE_H */
|
||||
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson-compat.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#include "bson-atomic.h"
|
||||
#include "bson-clock.h"
|
||||
#include "bson-context.h"
|
||||
#include "bson-context-private.h"
|
||||
#include "bson-md5.h"
|
||||
#include "bson-memory.h"
|
||||
#include "bson-thread-private.h"
|
||||
|
||||
|
||||
#ifndef HOST_NAME_MAX
|
||||
#define HOST_NAME_MAX 256
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Globals.
|
||||
*/
|
||||
static bson_context_t gContextDefault;
|
||||
|
||||
|
||||
#if defined(__linux__)
|
||||
static uint16_t
|
||||
gettid (void)
|
||||
{
|
||||
return syscall (SYS_gettid);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_context_get_oid_host --
|
||||
*
|
||||
* Retrieves the first three bytes of MD5(hostname) and assigns them
|
||||
* to the host portion of oid.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is modified.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_context_get_oid_host (bson_context_t *context, /* IN */
|
||||
bson_oid_t *oid) /* OUT */
|
||||
{
|
||||
uint8_t *bytes = (uint8_t *)oid;
|
||||
uint8_t digest[16];
|
||||
bson_md5_t md5;
|
||||
char hostname[HOST_NAME_MAX];
|
||||
|
||||
BSON_ASSERT (context);
|
||||
BSON_ASSERT (oid);
|
||||
|
||||
gethostname (hostname, sizeof hostname);
|
||||
hostname[HOST_NAME_MAX - 1] = '\0';
|
||||
|
||||
bson_md5_init (&md5);
|
||||
bson_md5_append (&md5, (const uint8_t *)hostname, (uint32_t)strlen (hostname));
|
||||
bson_md5_finish (&md5, &digest[0]);
|
||||
|
||||
bytes[4] = digest[0];
|
||||
bytes[5] = digest[1];
|
||||
bytes[6] = digest[2];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_context_get_oid_host_cached --
|
||||
*
|
||||
* Fetch the cached copy of the MD5(hostname).
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is modified.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_context_get_oid_host_cached (bson_context_t *context, /* IN */
|
||||
bson_oid_t *oid) /* OUT */
|
||||
{
|
||||
BSON_ASSERT (context);
|
||||
BSON_ASSERT (oid);
|
||||
|
||||
oid->bytes[4] = context->md5[0];
|
||||
oid->bytes[5] = context->md5[1];
|
||||
oid->bytes[6] = context->md5[2];
|
||||
}
|
||||
|
||||
|
||||
static BSON_INLINE uint16_t
|
||||
_bson_getpid (void)
|
||||
{
|
||||
uint16_t pid;
|
||||
#ifdef BSON_OS_WIN32
|
||||
DWORD real_pid;
|
||||
|
||||
real_pid = GetCurrentProcessId ();
|
||||
pid = (real_pid & 0xFFFF) ^ ((real_pid >> 16) & 0xFFFF);
|
||||
#else
|
||||
pid = getpid ();
|
||||
#endif
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_context_get_oid_pid --
|
||||
*
|
||||
* Initialize the pid field of @oid.
|
||||
*
|
||||
* The pid field is 2 bytes, big-endian for memcmp().
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is modified.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_context_get_oid_pid (bson_context_t *context, /* IN */
|
||||
bson_oid_t *oid) /* OUT */
|
||||
{
|
||||
uint16_t pid = _bson_getpid ();
|
||||
uint8_t *bytes = (uint8_t *)&pid;
|
||||
|
||||
BSON_ASSERT (context);
|
||||
BSON_ASSERT (oid);
|
||||
|
||||
pid = BSON_UINT16_TO_BE (pid);
|
||||
|
||||
oid->bytes[7] = bytes[0];
|
||||
oid->bytes[8] = bytes[1];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_context_get_oid_pid_cached --
|
||||
*
|
||||
* Fetch the cached copy of the current pid.
|
||||
* This helps avoid multiple calls to getpid() which is slower
|
||||
* on some systems.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is modified.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_context_get_oid_pid_cached (bson_context_t *context, /* IN */
|
||||
bson_oid_t *oid) /* OUT */
|
||||
{
|
||||
oid->bytes[7] = context->pidbe[0];
|
||||
oid->bytes[8] = context->pidbe[1];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_context_get_oid_seq32 --
|
||||
*
|
||||
* 32-bit sequence generator, non-thread-safe version.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is modified.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_context_get_oid_seq32 (bson_context_t *context, /* IN */
|
||||
bson_oid_t *oid) /* OUT */
|
||||
{
|
||||
uint32_t seq = context->seq32++;
|
||||
|
||||
seq = BSON_UINT32_TO_BE (seq);
|
||||
memcpy (&oid->bytes[9], ((uint8_t *)&seq) + 1, 3);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_context_get_oid_seq32_threadsafe --
|
||||
*
|
||||
* Thread-safe version of 32-bit sequence generator.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is modified.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_context_get_oid_seq32_threadsafe (bson_context_t *context, /* IN */
|
||||
bson_oid_t *oid) /* OUT */
|
||||
{
|
||||
int32_t seq = bson_atomic_int_add (&context->seq32, 1);
|
||||
|
||||
seq = BSON_UINT32_TO_BE (seq);
|
||||
memcpy (&oid->bytes[9], ((uint8_t *)&seq) + 1, 3);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_context_get_oid_seq64 --
|
||||
*
|
||||
* 64-bit oid sequence generator, non-thread-safe version.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is modified.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_context_get_oid_seq64 (bson_context_t *context, /* IN */
|
||||
bson_oid_t *oid) /* OUT */
|
||||
{
|
||||
uint64_t seq;
|
||||
|
||||
BSON_ASSERT (context);
|
||||
BSON_ASSERT (oid);
|
||||
|
||||
seq = BSON_UINT64_TO_BE (context->seq64++);
|
||||
memcpy (&oid->bytes[4], &seq, sizeof (seq));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_context_get_oid_seq64_threadsafe --
|
||||
*
|
||||
* Thread-safe 64-bit sequence generator.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is modified.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_context_get_oid_seq64_threadsafe (bson_context_t *context, /* IN */
|
||||
bson_oid_t *oid) /* OUT */
|
||||
{
|
||||
int64_t seq = bson_atomic_int64_add (&context->seq64, 1);
|
||||
|
||||
seq = BSON_UINT64_TO_BE (seq);
|
||||
memcpy (&oid->bytes[4], &seq, sizeof (seq));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_bson_context_init (bson_context_t *context, /* IN */
|
||||
bson_context_flags_t flags) /* IN */
|
||||
{
|
||||
struct timeval tv;
|
||||
uint16_t pid;
|
||||
unsigned int seed[3];
|
||||
unsigned int real_seed;
|
||||
bson_oid_t oid;
|
||||
|
||||
context->flags = flags;
|
||||
context->oid_get_host = _bson_context_get_oid_host_cached;
|
||||
context->oid_get_pid = _bson_context_get_oid_pid_cached;
|
||||
context->oid_get_seq32 = _bson_context_get_oid_seq32;
|
||||
context->oid_get_seq64 = _bson_context_get_oid_seq64;
|
||||
|
||||
/*
|
||||
* Generate a seed for our the random starting position of our increment
|
||||
* bytes. We mask off the last nibble so that the last digit of the OID will
|
||||
* start at zero. Just to be nice.
|
||||
*
|
||||
* The seed itself is made up of the current time in seconds, milliseconds,
|
||||
* and pid xored together. I welcome better solutions if at all necessary.
|
||||
*/
|
||||
bson_gettimeofday (&tv);
|
||||
seed[0] = (unsigned int)tv.tv_sec;
|
||||
seed[1] = (unsigned int)tv.tv_usec;
|
||||
seed[2] = _bson_getpid ();
|
||||
real_seed = seed[0] ^ seed[1] ^ seed[2];
|
||||
|
||||
#ifdef BSON_OS_WIN32
|
||||
/* ms's runtime is multithreaded by default, so no rand_r */
|
||||
srand(real_seed);
|
||||
context->seq32 = rand() & 0x007FFFF0;
|
||||
#else
|
||||
context->seq32 = rand_r (&real_seed) & 0x007FFFF0;
|
||||
#endif
|
||||
|
||||
if ((flags & BSON_CONTEXT_DISABLE_HOST_CACHE)) {
|
||||
context->oid_get_host = _bson_context_get_oid_host;
|
||||
} else {
|
||||
_bson_context_get_oid_host (context, &oid);
|
||||
context->md5[0] = oid.bytes[4];
|
||||
context->md5[1] = oid.bytes[5];
|
||||
context->md5[2] = oid.bytes[6];
|
||||
}
|
||||
|
||||
if ((flags & BSON_CONTEXT_THREAD_SAFE)) {
|
||||
context->oid_get_seq32 = _bson_context_get_oid_seq32_threadsafe;
|
||||
context->oid_get_seq64 = _bson_context_get_oid_seq64_threadsafe;
|
||||
}
|
||||
|
||||
if ((flags & BSON_CONTEXT_DISABLE_PID_CACHE)) {
|
||||
context->oid_get_pid = _bson_context_get_oid_pid;
|
||||
} else {
|
||||
pid = BSON_UINT16_TO_BE (_bson_getpid());
|
||||
#if defined(__linux__)
|
||||
|
||||
if ((flags & BSON_CONTEXT_USE_TASK_ID)) {
|
||||
int32_t tid;
|
||||
|
||||
if ((tid = gettid ())) {
|
||||
pid = BSON_UINT16_TO_BE (tid);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
memcpy (&context->pidbe[0], &pid, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_context_new --
|
||||
*
|
||||
* Initializes a new context with the flags specified.
|
||||
*
|
||||
* In most cases, you want to call this with @flags set to
|
||||
* BSON_CONTEXT_NONE.
|
||||
*
|
||||
* If you are running on Linux, %BSON_CONTEXT_USE_TASK_ID can result
|
||||
* in a healthy speedup for multi-threaded scenarios.
|
||||
*
|
||||
* If you absolutely must have a single context for your application
|
||||
* and use more than one thread, then %BSON_CONTEXT_THREAD_SAFE should
|
||||
* be bitwise-or'd with your flags. This requires synchronization
|
||||
* between threads.
|
||||
*
|
||||
* If you expect your hostname to change often, you may consider
|
||||
* specifying %BSON_CONTEXT_DISABLE_HOST_CACHE so that gethostname()
|
||||
* is called for every OID generated. This is much slower.
|
||||
*
|
||||
* If you expect your pid to change without notice, such as from an
|
||||
* unexpected call to fork(), then specify
|
||||
* %BSON_CONTEXT_DISABLE_PID_CACHE.
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated bson_context_t that should be freed with
|
||||
* bson_context_destroy().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bson_context_t *
|
||||
bson_context_new (bson_context_flags_t flags)
|
||||
{
|
||||
bson_context_t *context;
|
||||
|
||||
context = bson_malloc0 (sizeof *context);
|
||||
_bson_context_init (context, flags);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_context_destroy --
|
||||
*
|
||||
* Cleans up a bson_context_t and releases any associated resources.
|
||||
* This should be called when you are done using @context.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_context_destroy (bson_context_t *context) /* IN */
|
||||
{
|
||||
if (context != &gContextDefault) {
|
||||
memset (context, 0, sizeof *context);
|
||||
bson_free (context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
BSON_ONCE_FUN(_bson_context_init_default)
|
||||
{
|
||||
_bson_context_init (&gContextDefault,
|
||||
(BSON_CONTEXT_THREAD_SAFE |
|
||||
BSON_CONTEXT_DISABLE_PID_CACHE));
|
||||
BSON_ONCE_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_context_get_default --
|
||||
*
|
||||
* Fetches the default, thread-safe implementation of #bson_context_t.
|
||||
* If you need faster generation, it is recommended you create your
|
||||
* own #bson_context_t with bson_context_new().
|
||||
*
|
||||
* Returns:
|
||||
* A shared instance to the default #bson_context_t. This should not
|
||||
* be modified or freed.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bson_context_t *
|
||||
bson_context_get_default (void)
|
||||
{
|
||||
static bson_once_t once = BSON_ONCE_INIT;
|
||||
|
||||
bson_once (&once, _bson_context_init_default);
|
||||
|
||||
return &gContextDefault;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_CONTEXT_H
|
||||
#define BSON_CONTEXT_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
bson_context_t *bson_context_new (bson_context_flags_t flags);
|
||||
void bson_context_destroy (bson_context_t *context);
|
||||
bson_context_t *bson_context_get_default (void) BSON_GNUC_CONST;
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_CONTEXT_H */
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_ENDIAN_H
|
||||
#define BSON_ENDIAN_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__sun)
|
||||
# include <sys/byteorder.h>
|
||||
#endif
|
||||
|
||||
#include "bson-config.h"
|
||||
#include "bson-macros.h"
|
||||
#include "bson-compat.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BSON_BIG_ENDIAN 4321
|
||||
#define BSON_LITTLE_ENDIAN 1234
|
||||
|
||||
|
||||
#if defined(__sun)
|
||||
# define BSON_UINT16_SWAP_LE_BE(v) BSWAP_16((uint16_t)v)
|
||||
# define BSON_UINT32_SWAP_LE_BE(v) BSWAP_32((uint32_t)v)
|
||||
# define BSON_UINT64_SWAP_LE_BE(v) BSWAP_64((uint64_t)v)
|
||||
#elif defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) && \
|
||||
(__clang_major__ >= 3) && (__clang_minor__ >= 1)
|
||||
# if __has_builtin(__builtin_bswap16)
|
||||
# define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16(v)
|
||||
# endif
|
||||
# if __has_builtin(__builtin_bswap32)
|
||||
# define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32(v)
|
||||
# endif
|
||||
# if __has_builtin(__builtin_bswap64)
|
||||
# define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64(v)
|
||||
# endif
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
# if __GNUC__ >= 4 && defined (__GNUC_MINOR__) && __GNUC_MINOR__ >= 3
|
||||
# define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 ((uint32_t)v)
|
||||
# define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 ((uint64_t)v)
|
||||
# endif
|
||||
# if __GNUC__ >= 4 && defined (__GNUC_MINOR__) && __GNUC_MINOR__ >= 8
|
||||
# define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16 ((uint32_t)v)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_UINT16_SWAP_LE_BE
|
||||
# define BSON_UINT16_SWAP_LE_BE(v) __bson_uint16_swap_slow ((uint16_t)v)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_UINT32_SWAP_LE_BE
|
||||
# define BSON_UINT32_SWAP_LE_BE(v) __bson_uint32_swap_slow ((uint32_t)v)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_UINT64_SWAP_LE_BE
|
||||
# define BSON_UINT64_SWAP_LE_BE(v) __bson_uint64_swap_slow ((uint64_t)v)
|
||||
#endif
|
||||
|
||||
|
||||
#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN
|
||||
# define BSON_UINT16_FROM_LE(v) ((uint16_t)v)
|
||||
# define BSON_UINT16_TO_LE(v) ((uint16_t)v)
|
||||
# define BSON_UINT16_FROM_BE(v) BSON_UINT16_SWAP_LE_BE (v)
|
||||
# define BSON_UINT16_TO_BE(v) BSON_UINT16_SWAP_LE_BE (v)
|
||||
# define BSON_UINT32_FROM_LE(v) ((uint32_t)v)
|
||||
# define BSON_UINT32_TO_LE(v) ((uint32_t)v)
|
||||
# define BSON_UINT32_FROM_BE(v) BSON_UINT32_SWAP_LE_BE (v)
|
||||
# define BSON_UINT32_TO_BE(v) BSON_UINT32_SWAP_LE_BE (v)
|
||||
# define BSON_UINT64_FROM_LE(v) ((uint64_t)v)
|
||||
# define BSON_UINT64_TO_LE(v) ((uint64_t)v)
|
||||
# define BSON_UINT64_FROM_BE(v) BSON_UINT64_SWAP_LE_BE (v)
|
||||
# define BSON_UINT64_TO_BE(v) BSON_UINT64_SWAP_LE_BE (v)
|
||||
# define BSON_DOUBLE_FROM_LE(v) ((double)v)
|
||||
# define BSON_DOUBLE_TO_LE(v) ((double)v)
|
||||
#elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN
|
||||
# define BSON_UINT16_FROM_LE(v) BSON_UINT16_SWAP_LE_BE (v)
|
||||
# define BSON_UINT16_TO_LE(v) BSON_UINT16_SWAP_LE_BE (v)
|
||||
# define BSON_UINT16_FROM_BE(v) ((uint16_t)v)
|
||||
# define BSON_UINT16_TO_BE(v) ((uint16_t)v)
|
||||
# define BSON_UINT32_FROM_LE(v) BSON_UINT32_SWAP_LE_BE (v)
|
||||
# define BSON_UINT32_TO_LE(v) BSON_UINT32_SWAP_LE_BE (v)
|
||||
# define BSON_UINT32_FROM_BE(v) ((uint32_t)v)
|
||||
# define BSON_UINT32_TO_BE(v) ((uint32_t)v)
|
||||
# define BSON_UINT64_FROM_LE(v) BSON_UINT64_SWAP_LE_BE (v)
|
||||
# define BSON_UINT64_TO_LE(v) BSON_UINT64_SWAP_LE_BE (v)
|
||||
# define BSON_UINT64_FROM_BE(v) ((uint64_t)v)
|
||||
# define BSON_UINT64_TO_BE(v) ((uint64_t)v)
|
||||
# define BSON_DOUBLE_FROM_LE(v) (__bson_double_swap_slow (v))
|
||||
# define BSON_DOUBLE_TO_LE(v) (__bson_double_swap_slow (v))
|
||||
#else
|
||||
# error "The endianness of target architecture is unknown."
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* __bson_uint16_swap_slow --
|
||||
*
|
||||
* Fallback endianness conversion for 16-bit integers.
|
||||
*
|
||||
* Returns:
|
||||
* The endian swapped version.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static BSON_INLINE uint16_t
|
||||
__bson_uint16_swap_slow (uint16_t v) /* IN */
|
||||
{
|
||||
return ((v & 0x00FF) << 8) |
|
||||
((v & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* __bson_uint32_swap_slow --
|
||||
*
|
||||
* Fallback endianness conversion for 32-bit integers.
|
||||
*
|
||||
* Returns:
|
||||
* The endian swapped version.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static BSON_INLINE uint32_t
|
||||
__bson_uint32_swap_slow (uint32_t v) /* IN */
|
||||
{
|
||||
return ((v & 0x000000FFU) << 24) |
|
||||
((v & 0x0000FF00U) << 8) |
|
||||
((v & 0x00FF0000U) >> 8) |
|
||||
((v & 0xFF000000U) >> 24);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* __bson_uint64_swap_slow --
|
||||
*
|
||||
* Fallback endianness conversion for 64-bit integers.
|
||||
*
|
||||
* Returns:
|
||||
* The endian swapped version.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static BSON_INLINE uint64_t
|
||||
__bson_uint64_swap_slow (uint64_t v) /* IN */
|
||||
{
|
||||
return ((v & 0x00000000000000FFULL) << 56) |
|
||||
((v & 0x000000000000FF00ULL) << 40) |
|
||||
((v & 0x0000000000FF0000ULL) << 24) |
|
||||
((v & 0x00000000FF000000ULL) << 8) |
|
||||
((v & 0x000000FF00000000ULL) >> 8) |
|
||||
((v & 0x0000FF0000000000ULL) >> 24) |
|
||||
((v & 0x00FF000000000000ULL) >> 40) |
|
||||
((v & 0xFF00000000000000ULL) >> 56);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* __bson_double_swap_slow --
|
||||
*
|
||||
* Fallback endianness conversion for double floating point.
|
||||
*
|
||||
* Returns:
|
||||
* The endian swapped version.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
BSON_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t));
|
||||
|
||||
static BSON_INLINE double
|
||||
__bson_double_swap_slow (double v) /* IN */
|
||||
{
|
||||
uint64_t uv;
|
||||
|
||||
memcpy(&uv, &v, sizeof(v));
|
||||
uv = BSON_UINT64_SWAP_LE_BE(uv);
|
||||
memcpy(&v, &uv, sizeof(v));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_ENDIAN_H */
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-config.h"
|
||||
#include "bson-error.h"
|
||||
#include "bson-memory.h"
|
||||
#include "bson-string.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_set_error --
|
||||
*
|
||||
* Initializes @error using the parameters specified.
|
||||
*
|
||||
* @domain is an application specific error domain which should
|
||||
* describe which module initiated the error. Think of this as the
|
||||
* exception type.
|
||||
*
|
||||
* @code is the @domain specific error code.
|
||||
*
|
||||
* @format is used to generate the format string. It uses vsnprintf()
|
||||
* internally so the format should match what you would use there.
|
||||
*
|
||||
* Parameters:
|
||||
* @error: A #bson_error_t.
|
||||
* @domain: The error domain.
|
||||
* @code: The error code.
|
||||
* @format: A printf style format string.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @error is initialized.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_set_error (bson_error_t *error, /* OUT */
|
||||
uint32_t domain, /* IN */
|
||||
uint32_t code, /* IN */
|
||||
const char *format, /* IN */
|
||||
...) /* IN */
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (error) {
|
||||
error->domain = domain;
|
||||
error->code = code;
|
||||
|
||||
va_start (args, format);
|
||||
bson_vsnprintf (error->message, sizeof error->message, format, args);
|
||||
va_end (args);
|
||||
|
||||
error->message[sizeof error->message - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_strerror_r --
|
||||
*
|
||||
* This is a reentrant safe macro for strerror.
|
||||
*
|
||||
* The resulting string may be stored in @buf.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to a static string or @buf.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
bson_strerror_r (int err_code, /* IN */
|
||||
char *buf, /* IN */
|
||||
size_t buflen) /* IN */
|
||||
{
|
||||
static const char *unknown_msg = "Unknown error";
|
||||
char *ret = NULL;
|
||||
|
||||
#if defined(__GNUC__) && defined(_GNU_SOURCE)
|
||||
ret = strerror_r (err_code, buf, buflen);
|
||||
#elif defined(_WIN32)
|
||||
if (strerror_s (buf, buflen, err_code) != 0) {
|
||||
ret = buf;
|
||||
}
|
||||
#else /* XSI strerror_r */
|
||||
if (strerror_r (err_code, buf, buflen) == 0) {
|
||||
ret = buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ret) {
|
||||
bson_strncpy (buf, unknown_msg, buflen);
|
||||
ret = buf;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_ERROR_H
|
||||
#define BSON_ERROR_H
|
||||
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BSON_ERROR_JSON 1
|
||||
#define BSON_ERROR_READER 2
|
||||
|
||||
#define BSON_ERROR_BUFFER_SIZE 64
|
||||
|
||||
|
||||
void bson_set_error (bson_error_t *error,
|
||||
uint32_t domain,
|
||||
uint32_t code,
|
||||
const char *format,
|
||||
...) BSON_GNUC_PRINTF (4, 5);
|
||||
char *bson_strerror_r (int err_code,
|
||||
char *buf,
|
||||
size_t buflen);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_ERROR_H */
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_ISO8601_PRIVATE_H
|
||||
#define BSON_ISO8601_PRIVATE_H
|
||||
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-macros.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
bool
|
||||
_bson_iso8601_date_parse (const char *str,
|
||||
int32_t len,
|
||||
int64_t *out);
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_ISO8601_PRIVATE_H */
|
||||
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-macros.h"
|
||||
#include "bson-error.h"
|
||||
#include "bson-iso8601-private.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include "bson-timegm-private.h"
|
||||
#endif
|
||||
|
||||
|
||||
static bool
|
||||
get_tok (const char *terminals,
|
||||
const char **ptr,
|
||||
int32_t *remaining,
|
||||
const char **out,
|
||||
int32_t *out_len)
|
||||
{
|
||||
const char *terminal;
|
||||
bool found_terminal = false;
|
||||
|
||||
if (!*remaining) {
|
||||
*out = "";
|
||||
*out_len = 0;
|
||||
}
|
||||
|
||||
*out = *ptr;
|
||||
*out_len = -1;
|
||||
|
||||
for (; *remaining && !found_terminal;
|
||||
(*ptr)++, (*remaining)--, (*out_len)++) {
|
||||
for (terminal = terminals; *terminal; terminal++) {
|
||||
if (**ptr == *terminal) {
|
||||
found_terminal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_terminal) {
|
||||
(*out_len)++;
|
||||
}
|
||||
|
||||
return found_terminal;
|
||||
}
|
||||
|
||||
static bool
|
||||
digits_only (const char *str,
|
||||
int32_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!isdigit(str[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_num (const char *str,
|
||||
int32_t len,
|
||||
int32_t digits,
|
||||
int32_t min,
|
||||
int32_t max,
|
||||
int32_t *out)
|
||||
{
|
||||
int i;
|
||||
int magnitude = 1;
|
||||
int32_t value = 0;
|
||||
|
||||
if ((digits >= 0 && len != digits) || !digits_only (str, len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 1; i <= len; i++, magnitude *= 10) {
|
||||
value += (str[len - i] - '0') * magnitude;
|
||||
}
|
||||
|
||||
if (value < min || value > max) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
_bson_iso8601_date_parse (const char *str,
|
||||
int32_t len,
|
||||
int64_t *out)
|
||||
{
|
||||
const char *ptr;
|
||||
int32_t remaining = len;
|
||||
|
||||
const char *year_ptr;
|
||||
const char *month_ptr;
|
||||
const char *day_ptr;
|
||||
const char *hour_ptr;
|
||||
const char *min_ptr;
|
||||
const char *sec_ptr;
|
||||
const char *millis_ptr;
|
||||
const char *tz_ptr;
|
||||
|
||||
int32_t year_len = 0;
|
||||
int32_t month_len = 0;
|
||||
int32_t day_len = 0;
|
||||
int32_t hour_len = 0;
|
||||
int32_t min_len = 0;
|
||||
int32_t sec_len = 0;
|
||||
int32_t millis_len = 0;
|
||||
int32_t tz_len = 0;
|
||||
|
||||
int32_t year;
|
||||
int32_t month;
|
||||
int32_t day;
|
||||
int32_t hour;
|
||||
int32_t min;
|
||||
int32_t sec = 0;
|
||||
int64_t millis = 0;
|
||||
int32_t tz_adjustment = 0;
|
||||
|
||||
#ifdef BSON_OS_WIN32
|
||||
SYSTEMTIME win_sys_time;
|
||||
FILETIME win_file_time;
|
||||
int64_t win_time_offset;
|
||||
int64_t win_epoch_difference;
|
||||
#else
|
||||
struct tm posix_date = { 0 };
|
||||
#endif
|
||||
|
||||
ptr = str;
|
||||
|
||||
/* we have to match at least yyyy-mm-ddThh:mm[:+-Z] */
|
||||
if (!(get_tok ("-", &ptr, &remaining, &year_ptr,
|
||||
&year_len) &&
|
||||
get_tok ("-", &ptr, &remaining, &month_ptr,
|
||||
&month_len) &&
|
||||
get_tok ("T", &ptr, &remaining, &day_ptr,
|
||||
&day_len) &&
|
||||
get_tok (":", &ptr, &remaining, &hour_ptr,
|
||||
&hour_len) &&
|
||||
get_tok (":+-Z", &ptr, &remaining, &min_ptr, &min_len))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* if the minute has a ':' at the end look for seconds */
|
||||
if (min_ptr[min_len] == ':') {
|
||||
if (remaining < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
get_tok (".+-Z", &ptr, &remaining, &sec_ptr, &sec_len);
|
||||
|
||||
if (!sec_len) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we had a second and it is followed by a '.' look for milliseconds */
|
||||
if (sec_len && sec_ptr[sec_len] == '.') {
|
||||
if (remaining < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
get_tok ("+-Z", &ptr, &remaining, &millis_ptr, &millis_len);
|
||||
|
||||
if (!millis_len) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* backtrack by 1 to put ptr on the timezone */
|
||||
ptr--;
|
||||
remaining++;
|
||||
|
||||
get_tok ("", &ptr, &remaining, &tz_ptr, &tz_len);
|
||||
|
||||
/* we want to include the last few hours in 1969 for timezones translate
|
||||
* across 1970 GMT. We'll check in timegm later on to make sure we're post
|
||||
* 1970 */
|
||||
if (!parse_num (year_ptr, year_len, 4, 1969, 9999, &year)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* values are as in struct tm */
|
||||
year -= 1900;
|
||||
|
||||
if (!parse_num (month_ptr, month_len, 2, 1, 12, &month)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* values are as in struct tm */
|
||||
month -= 1;
|
||||
|
||||
if (!parse_num (day_ptr, day_len, 2, 1, 31, &day)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_num (hour_ptr, hour_len, 2, 0, 23, &hour)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_num (min_ptr, min_len, 2, 0, 59, &min)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sec_len && !parse_num (sec_ptr, sec_len, 2, 0, 60, &sec)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tz_len > 0) {
|
||||
if (tz_ptr[0] == 'Z' && tz_len == 1) {
|
||||
/* valid */
|
||||
} else if (tz_ptr[0] == '+' || tz_ptr[0] == '-') {
|
||||
int32_t tz_hour;
|
||||
int32_t tz_min;
|
||||
|
||||
if (tz_len != 5 || !digits_only (tz_ptr + 1, 4)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_num (tz_ptr + 1, 2, -1, -23, 23, &tz_hour)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_num (tz_ptr + 3, 2, -1, 0, 59, &tz_min)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we inflect the meaning of a 'positive' timezone. Those are hours
|
||||
* we have to substract, and vice versa */
|
||||
tz_adjustment =
|
||||
(tz_ptr[0] == '-' ? 1 : -1) * ((tz_min * 60) + (tz_hour * 60 * 60));
|
||||
|
||||
if (!(tz_adjustment > -86400 && tz_adjustment < 86400)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (millis_len > 0) {
|
||||
int i;
|
||||
int magnitude;
|
||||
millis = 0;
|
||||
|
||||
if (millis_len > 3 || !digits_only (millis_ptr, millis_len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 1, magnitude = 1; i <= millis_len; i++, magnitude *= 10) {
|
||||
millis += (millis_ptr[millis_len - i] - '0') * magnitude;
|
||||
}
|
||||
|
||||
if (millis_len == 1) {
|
||||
millis *= 100;
|
||||
} else if (millis_len == 2) {
|
||||
millis *= 10;
|
||||
}
|
||||
|
||||
if (millis < 0 || millis > 1000) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BSON_OS_WIN32
|
||||
win_sys_time.wMilliseconds = millis;
|
||||
win_sys_time.wSecond = sec;
|
||||
win_sys_time.wMinute = min;
|
||||
win_sys_time.wHour = hour;
|
||||
win_sys_time.wDay = day;
|
||||
win_sys_time.wDayOfWeek = -1; /* ignored */
|
||||
win_sys_time.wMonth = month + 1;
|
||||
win_sys_time.wYear = year + 1900;
|
||||
|
||||
/* the wDayOfWeek member of SYSTEMTIME is ignored by this function */
|
||||
if (SystemTimeToFileTime (&win_sys_time, &win_file_time) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The Windows FILETIME structure contains two parts of a 64-bit value representing the
|
||||
* number of 100-nanosecond intervals since January 1, 1601
|
||||
*/
|
||||
win_time_offset =
|
||||
(((uint64_t)win_file_time.dwHighDateTime) << 32) |
|
||||
win_file_time.dwLowDateTime;
|
||||
|
||||
/* There are 11644473600 seconds between the unix epoch and the windows epoch
|
||||
* 100-nanoseconds = milliseconds * 10000
|
||||
*/
|
||||
win_epoch_difference = 11644473600000 * 10000;
|
||||
|
||||
/* removes the diff between 1970 and 1601 */
|
||||
win_time_offset -= win_epoch_difference;
|
||||
|
||||
/* 1 milliseconds = 1000000 nanoseconds = 10000 100-nanosecond intervals */
|
||||
millis = win_time_offset / 10000;
|
||||
#else
|
||||
posix_date.tm_sec = sec;
|
||||
posix_date.tm_min = min;
|
||||
posix_date.tm_hour = hour;
|
||||
posix_date.tm_mday = day;
|
||||
posix_date.tm_mon = month;
|
||||
posix_date.tm_year = year;
|
||||
posix_date.tm_wday = 0;
|
||||
posix_date.tm_yday = 0;
|
||||
|
||||
millis = (1000 * ((uint64_t)_bson_timegm (&posix_date))) + millis;
|
||||
|
||||
#endif
|
||||
|
||||
millis += tz_adjustment * 1000;
|
||||
|
||||
if (millis < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = millis;
|
||||
|
||||
return true;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_ITER_H
|
||||
#define BSON_ITER_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson.h"
|
||||
#include "bson-endian.h"
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BSON_ITER_HOLDS_DOUBLE(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_DOUBLE)
|
||||
|
||||
#define BSON_ITER_HOLDS_UTF8(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_UTF8)
|
||||
|
||||
#define BSON_ITER_HOLDS_DOCUMENT(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_DOCUMENT)
|
||||
|
||||
#define BSON_ITER_HOLDS_ARRAY(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_ARRAY)
|
||||
|
||||
#define BSON_ITER_HOLDS_BINARY(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_BINARY)
|
||||
|
||||
#define BSON_ITER_HOLDS_UNDEFINED(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_UNDEFINED)
|
||||
|
||||
#define BSON_ITER_HOLDS_OID(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_OID)
|
||||
|
||||
#define BSON_ITER_HOLDS_BOOL(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_BOOL)
|
||||
|
||||
#define BSON_ITER_HOLDS_DATE_TIME(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_DATE_TIME)
|
||||
|
||||
#define BSON_ITER_HOLDS_NULL(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_NULL)
|
||||
|
||||
#define BSON_ITER_HOLDS_REGEX(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_REGEX)
|
||||
|
||||
#define BSON_ITER_HOLDS_DBPOINTER(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_DBPOINTER)
|
||||
|
||||
#define BSON_ITER_HOLDS_CODE(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_CODE)
|
||||
|
||||
#define BSON_ITER_HOLDS_SYMBOL(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_SYMBOL)
|
||||
|
||||
#define BSON_ITER_HOLDS_CODEWSCOPE(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_CODEWSCOPE)
|
||||
|
||||
#define BSON_ITER_HOLDS_INT32(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_INT32)
|
||||
|
||||
#define BSON_ITER_HOLDS_TIMESTAMP(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_TIMESTAMP)
|
||||
|
||||
#define BSON_ITER_HOLDS_INT64(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_INT64)
|
||||
|
||||
#define BSON_ITER_HOLDS_MAXKEY(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_MAXKEY)
|
||||
|
||||
#define BSON_ITER_HOLDS_MINKEY(iter) \
|
||||
(bson_iter_type ((iter)) == BSON_TYPE_MINKEY)
|
||||
|
||||
#define BSON_ITER_IS_KEY(iter, key) \
|
||||
(0 == strcmp ((key), bson_iter_key ((iter))))
|
||||
|
||||
|
||||
const bson_value_t *
|
||||
bson_iter_value (bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_utf8_len_unsafe:
|
||||
* @iter: a bson_iter_t.
|
||||
*
|
||||
* Returns the length of a string currently pointed to by @iter. This performs
|
||||
* no validation so the is responsible for knowing the BSON is valid. Calling
|
||||
* bson_validate() is one way to do this ahead of time.
|
||||
*/
|
||||
static BSON_INLINE uint32_t
|
||||
bson_iter_utf8_len_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
int32_t val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, sizeof (val));
|
||||
val = BSON_UINT32_FROM_LE (val);
|
||||
return BSON_MAX (0, val - 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bson_iter_array (const bson_iter_t *iter,
|
||||
uint32_t *array_len,
|
||||
const uint8_t **array);
|
||||
|
||||
|
||||
void
|
||||
bson_iter_binary (const bson_iter_t *iter,
|
||||
bson_subtype_t *subtype,
|
||||
uint32_t *binary_len,
|
||||
const uint8_t **binary);
|
||||
|
||||
|
||||
const char *
|
||||
bson_iter_code (const bson_iter_t *iter,
|
||||
uint32_t *length);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_code_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
* @length: A location for the length of the resulting string.
|
||||
*
|
||||
* Like bson_iter_code() but performs no integrity checks.
|
||||
*
|
||||
* Returns: A string that should not be modified or freed.
|
||||
*/
|
||||
static BSON_INLINE const char *
|
||||
bson_iter_code_unsafe (const bson_iter_t *iter,
|
||||
uint32_t *length)
|
||||
{
|
||||
*length = bson_iter_utf8_len_unsafe (iter);
|
||||
return (const char *)(iter->raw + iter->d2);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
bson_iter_codewscope (const bson_iter_t *iter,
|
||||
uint32_t *length,
|
||||
uint32_t *scope_len,
|
||||
const uint8_t **scope);
|
||||
|
||||
|
||||
void
|
||||
bson_iter_dbpointer (const bson_iter_t *iter,
|
||||
uint32_t *collection_len,
|
||||
const char **collection,
|
||||
const bson_oid_t **oid);
|
||||
|
||||
|
||||
void
|
||||
bson_iter_document (const bson_iter_t *iter,
|
||||
uint32_t *document_len,
|
||||
const uint8_t **document);
|
||||
|
||||
|
||||
double
|
||||
bson_iter_double (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_double_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_double() but does not perform an integrity checking.
|
||||
*
|
||||
* Returns: A double.
|
||||
*/
|
||||
static BSON_INLINE double
|
||||
bson_iter_double_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
double val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, sizeof (val));
|
||||
return BSON_DOUBLE_FROM_LE (val);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_init (bson_iter_t *iter,
|
||||
const bson_t *bson);
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_init_find (bson_iter_t *iter,
|
||||
const bson_t *bson,
|
||||
const char *key);
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_init_find_case (bson_iter_t *iter,
|
||||
const bson_t *bson,
|
||||
const char *key);
|
||||
|
||||
|
||||
int32_t
|
||||
bson_iter_int32 (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_int32_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_int32() but with no integrity checking.
|
||||
*
|
||||
* Returns: A 32-bit signed integer.
|
||||
*/
|
||||
static BSON_INLINE int32_t
|
||||
bson_iter_int32_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
int32_t val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, sizeof (val));
|
||||
return BSON_UINT32_FROM_LE (val);
|
||||
}
|
||||
|
||||
|
||||
int64_t
|
||||
bson_iter_int64 (const bson_iter_t *iter);
|
||||
|
||||
|
||||
int64_t
|
||||
bson_iter_as_int64 (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_int64_unsafe:
|
||||
* @iter: a bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_int64() but without integrity checking.
|
||||
*
|
||||
* Returns: A 64-bit signed integer.
|
||||
*/
|
||||
static BSON_INLINE int64_t
|
||||
bson_iter_int64_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
int64_t val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, sizeof (val));
|
||||
return BSON_UINT64_FROM_LE (val);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_find (bson_iter_t *iter,
|
||||
const char *key);
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_find_case (bson_iter_t *iter,
|
||||
const char *key);
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_find_descendant (bson_iter_t *iter,
|
||||
const char *dotkey,
|
||||
bson_iter_t *descendant);
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_next (bson_iter_t *iter);
|
||||
|
||||
|
||||
const bson_oid_t *
|
||||
bson_iter_oid (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_oid_unsafe:
|
||||
* @iter: A #bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_oid() but performs no integrity checks.
|
||||
*
|
||||
* Returns: A #bson_oid_t that should not be modified or freed.
|
||||
*/
|
||||
static BSON_INLINE const bson_oid_t *
|
||||
bson_iter_oid_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
return (const bson_oid_t *)(iter->raw + iter->d1);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
bson_iter_key (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_key_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_key() but performs no integrity checking.
|
||||
*
|
||||
* Returns: A string that should not be modified or freed.
|
||||
*/
|
||||
static BSON_INLINE const char *
|
||||
bson_iter_key_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
return (const char *)(iter->raw + iter->key);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
bson_iter_utf8 (const bson_iter_t *iter,
|
||||
uint32_t *length);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_utf8_unsafe:
|
||||
*
|
||||
* Similar to bson_iter_utf8() but performs no integrity checking.
|
||||
*
|
||||
* Returns: A string that should not be modified or freed.
|
||||
*/
|
||||
static BSON_INLINE const char *
|
||||
bson_iter_utf8_unsafe (const bson_iter_t *iter,
|
||||
size_t *length)
|
||||
{
|
||||
*length = bson_iter_utf8_len_unsafe (iter);
|
||||
return (const char *)(iter->raw + iter->d2);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
bson_iter_dup_utf8 (const bson_iter_t *iter,
|
||||
uint32_t *length);
|
||||
|
||||
|
||||
int64_t
|
||||
bson_iter_date_time (const bson_iter_t *iter);
|
||||
|
||||
|
||||
time_t
|
||||
bson_iter_time_t (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_time_t_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_time_t() but performs no integrity checking.
|
||||
*
|
||||
* Returns: A time_t containing the number of seconds since UNIX epoch
|
||||
* in UTC.
|
||||
*/
|
||||
static BSON_INLINE time_t
|
||||
bson_iter_time_t_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
return (time_t)(bson_iter_int64_unsafe (iter) / 1000UL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bson_iter_timeval (const bson_iter_t *iter,
|
||||
struct timeval *tv);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_timeval_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
* @tv: A struct timeval.
|
||||
*
|
||||
* Similar to bson_iter_timeval() but performs no integrity checking.
|
||||
*/
|
||||
static BSON_INLINE void
|
||||
bson_iter_timeval_unsafe (const bson_iter_t *iter,
|
||||
struct timeval *tv)
|
||||
{
|
||||
int64_t value = bson_iter_int64_unsafe (iter);
|
||||
#ifdef BSON_OS_WIN32
|
||||
tv->tv_sec = (long) (value / 1000);
|
||||
#else
|
||||
tv->tv_sec = (suseconds_t) (value / 1000);
|
||||
#endif
|
||||
tv->tv_usec = (value % 1000) * 1000;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bson_iter_timestamp (const bson_iter_t *iter,
|
||||
uint32_t *timestamp,
|
||||
uint32_t *increment);
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_bool (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_bool_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_bool() but performs no integrity checking.
|
||||
*
|
||||
* Returns: true or false.
|
||||
*/
|
||||
static BSON_INLINE bool
|
||||
bson_iter_bool_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
char val;
|
||||
|
||||
memcpy (&val, iter->raw + iter->d1, 1);
|
||||
return !!val;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_as_bool (const bson_iter_t *iter);
|
||||
|
||||
|
||||
const char *
|
||||
bson_iter_regex (const bson_iter_t *iter,
|
||||
const char **options);
|
||||
|
||||
|
||||
const char *
|
||||
bson_iter_symbol (const bson_iter_t *iter,
|
||||
uint32_t *length);
|
||||
|
||||
|
||||
bson_type_t
|
||||
bson_iter_type (const bson_iter_t *iter);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_type_unsafe:
|
||||
* @iter: A bson_iter_t.
|
||||
*
|
||||
* Similar to bson_iter_type() but performs no integrity checking.
|
||||
*
|
||||
* Returns: A bson_type_t.
|
||||
*/
|
||||
static BSON_INLINE bson_type_t
|
||||
bson_iter_type_unsafe (const bson_iter_t *iter)
|
||||
{
|
||||
return (bson_type_t) (iter->raw + iter->type) [0];
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_recurse (const bson_iter_t *iter,
|
||||
bson_iter_t *child);
|
||||
|
||||
|
||||
void
|
||||
bson_iter_overwrite_int32 (bson_iter_t *iter,
|
||||
int32_t value);
|
||||
|
||||
|
||||
void
|
||||
bson_iter_overwrite_int64 (bson_iter_t *iter,
|
||||
int64_t value);
|
||||
|
||||
|
||||
void
|
||||
bson_iter_overwrite_double (bson_iter_t *iter,
|
||||
double value);
|
||||
|
||||
|
||||
void
|
||||
bson_iter_overwrite_bool (bson_iter_t *iter,
|
||||
bool value);
|
||||
|
||||
|
||||
bool
|
||||
bson_iter_visit_all (bson_iter_t *iter,
|
||||
const bson_visitor_t *visitor,
|
||||
void *data);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_ITER_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_JSON_H
|
||||
#define BSON_JSON_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef struct _bson_json_reader_t bson_json_reader_t;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BSON_JSON_ERROR_READ_CORRUPT_JS = 1,
|
||||
BSON_JSON_ERROR_READ_INVALID_PARAM,
|
||||
BSON_JSON_ERROR_READ_CB_FAILURE,
|
||||
} bson_json_error_code_t;
|
||||
|
||||
|
||||
typedef ssize_t (*bson_json_reader_cb) (void *handle,
|
||||
uint8_t *buf,
|
||||
size_t count);
|
||||
typedef void (*bson_json_destroy_cb)(void *handle);
|
||||
|
||||
|
||||
bson_json_reader_t *bson_json_reader_new (void *data,
|
||||
bson_json_reader_cb cb,
|
||||
bson_json_destroy_cb dcb,
|
||||
bool allow_multiple,
|
||||
size_t buf_size);
|
||||
bson_json_reader_t *bson_json_reader_new_from_fd (int fd,
|
||||
bool close_on_destroy);
|
||||
bson_json_reader_t *bson_json_reader_new_from_file (const char *filename,
|
||||
bson_error_t *error);
|
||||
void bson_json_reader_destroy (bson_json_reader_t *reader);
|
||||
int bson_json_reader_read (bson_json_reader_t *reader,
|
||||
bson_t *bson,
|
||||
bson_error_t *error);
|
||||
bson_json_reader_t *bson_json_data_reader_new (bool allow_multiple,
|
||||
size_t size);
|
||||
void bson_json_data_reader_ingest (bson_json_reader_t *reader,
|
||||
const uint8_t *data,
|
||||
size_t len);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_JSON_H */
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bson-keys.h"
|
||||
#include "bson-string.h"
|
||||
|
||||
|
||||
static const char * gUint32Strs[] = {
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
|
||||
"13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
|
||||
"24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34",
|
||||
"35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45",
|
||||
"46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56",
|
||||
"57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67",
|
||||
"68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78",
|
||||
"79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
|
||||
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100",
|
||||
"101", "102", "103", "104", "105", "106", "107", "108", "109", "110",
|
||||
"111", "112", "113", "114", "115", "116", "117", "118", "119", "120",
|
||||
"121", "122", "123", "124", "125", "126", "127", "128", "129", "130",
|
||||
"131", "132", "133", "134", "135", "136", "137", "138", "139", "140",
|
||||
"141", "142", "143", "144", "145", "146", "147", "148", "149", "150",
|
||||
"151", "152", "153", "154", "155", "156", "157", "158", "159", "160",
|
||||
"161", "162", "163", "164", "165", "166", "167", "168", "169", "170",
|
||||
"171", "172", "173", "174", "175", "176", "177", "178", "179", "180",
|
||||
"181", "182", "183", "184", "185", "186", "187", "188", "189", "190",
|
||||
"191", "192", "193", "194", "195", "196", "197", "198", "199", "200",
|
||||
"201", "202", "203", "204", "205", "206", "207", "208", "209", "210",
|
||||
"211", "212", "213", "214", "215", "216", "217", "218", "219", "220",
|
||||
"221", "222", "223", "224", "225", "226", "227", "228", "229", "230",
|
||||
"231", "232", "233", "234", "235", "236", "237", "238", "239", "240",
|
||||
"241", "242", "243", "244", "245", "246", "247", "248", "249", "250",
|
||||
"251", "252", "253", "254", "255", "256", "257", "258", "259", "260",
|
||||
"261", "262", "263", "264", "265", "266", "267", "268", "269", "270",
|
||||
"271", "272", "273", "274", "275", "276", "277", "278", "279", "280",
|
||||
"281", "282", "283", "284", "285", "286", "287", "288", "289", "290",
|
||||
"291", "292", "293", "294", "295", "296", "297", "298", "299", "300",
|
||||
"301", "302", "303", "304", "305", "306", "307", "308", "309", "310",
|
||||
"311", "312", "313", "314", "315", "316", "317", "318", "319", "320",
|
||||
"321", "322", "323", "324", "325", "326", "327", "328", "329", "330",
|
||||
"331", "332", "333", "334", "335", "336", "337", "338", "339", "340",
|
||||
"341", "342", "343", "344", "345", "346", "347", "348", "349", "350",
|
||||
"351", "352", "353", "354", "355", "356", "357", "358", "359", "360",
|
||||
"361", "362", "363", "364", "365", "366", "367", "368", "369", "370",
|
||||
"371", "372", "373", "374", "375", "376", "377", "378", "379", "380",
|
||||
"381", "382", "383", "384", "385", "386", "387", "388", "389", "390",
|
||||
"391", "392", "393", "394", "395", "396", "397", "398", "399", "400",
|
||||
"401", "402", "403", "404", "405", "406", "407", "408", "409", "410",
|
||||
"411", "412", "413", "414", "415", "416", "417", "418", "419", "420",
|
||||
"421", "422", "423", "424", "425", "426", "427", "428", "429", "430",
|
||||
"431", "432", "433", "434", "435", "436", "437", "438", "439", "440",
|
||||
"441", "442", "443", "444", "445", "446", "447", "448", "449", "450",
|
||||
"451", "452", "453", "454", "455", "456", "457", "458", "459", "460",
|
||||
"461", "462", "463", "464", "465", "466", "467", "468", "469", "470",
|
||||
"471", "472", "473", "474", "475", "476", "477", "478", "479", "480",
|
||||
"481", "482", "483", "484", "485", "486", "487", "488", "489", "490",
|
||||
"491", "492", "493", "494", "495", "496", "497", "498", "499", "500",
|
||||
"501", "502", "503", "504", "505", "506", "507", "508", "509", "510",
|
||||
"511", "512", "513", "514", "515", "516", "517", "518", "519", "520",
|
||||
"521", "522", "523", "524", "525", "526", "527", "528", "529", "530",
|
||||
"531", "532", "533", "534", "535", "536", "537", "538", "539", "540",
|
||||
"541", "542", "543", "544", "545", "546", "547", "548", "549", "550",
|
||||
"551", "552", "553", "554", "555", "556", "557", "558", "559", "560",
|
||||
"561", "562", "563", "564", "565", "566", "567", "568", "569", "570",
|
||||
"571", "572", "573", "574", "575", "576", "577", "578", "579", "580",
|
||||
"581", "582", "583", "584", "585", "586", "587", "588", "589", "590",
|
||||
"591", "592", "593", "594", "595", "596", "597", "598", "599", "600",
|
||||
"601", "602", "603", "604", "605", "606", "607", "608", "609", "610",
|
||||
"611", "612", "613", "614", "615", "616", "617", "618", "619", "620",
|
||||
"621", "622", "623", "624", "625", "626", "627", "628", "629", "630",
|
||||
"631", "632", "633", "634", "635", "636", "637", "638", "639", "640",
|
||||
"641", "642", "643", "644", "645", "646", "647", "648", "649", "650",
|
||||
"651", "652", "653", "654", "655", "656", "657", "658", "659", "660",
|
||||
"661", "662", "663", "664", "665", "666", "667", "668", "669", "670",
|
||||
"671", "672", "673", "674", "675", "676", "677", "678", "679", "680",
|
||||
"681", "682", "683", "684", "685", "686", "687", "688", "689", "690",
|
||||
"691", "692", "693", "694", "695", "696", "697", "698", "699", "700",
|
||||
"701", "702", "703", "704", "705", "706", "707", "708", "709", "710",
|
||||
"711", "712", "713", "714", "715", "716", "717", "718", "719", "720",
|
||||
"721", "722", "723", "724", "725", "726", "727", "728", "729", "730",
|
||||
"731", "732", "733", "734", "735", "736", "737", "738", "739", "740",
|
||||
"741", "742", "743", "744", "745", "746", "747", "748", "749", "750",
|
||||
"751", "752", "753", "754", "755", "756", "757", "758", "759", "760",
|
||||
"761", "762", "763", "764", "765", "766", "767", "768", "769", "770",
|
||||
"771", "772", "773", "774", "775", "776", "777", "778", "779", "780",
|
||||
"781", "782", "783", "784", "785", "786", "787", "788", "789", "790",
|
||||
"791", "792", "793", "794", "795", "796", "797", "798", "799", "800",
|
||||
"801", "802", "803", "804", "805", "806", "807", "808", "809", "810",
|
||||
"811", "812", "813", "814", "815", "816", "817", "818", "819", "820",
|
||||
"821", "822", "823", "824", "825", "826", "827", "828", "829", "830",
|
||||
"831", "832", "833", "834", "835", "836", "837", "838", "839", "840",
|
||||
"841", "842", "843", "844", "845", "846", "847", "848", "849", "850",
|
||||
"851", "852", "853", "854", "855", "856", "857", "858", "859", "860",
|
||||
"861", "862", "863", "864", "865", "866", "867", "868", "869", "870",
|
||||
"871", "872", "873", "874", "875", "876", "877", "878", "879", "880",
|
||||
"881", "882", "883", "884", "885", "886", "887", "888", "889", "890",
|
||||
"891", "892", "893", "894", "895", "896", "897", "898", "899", "900",
|
||||
"901", "902", "903", "904", "905", "906", "907", "908", "909", "910",
|
||||
"911", "912", "913", "914", "915", "916", "917", "918", "919", "920",
|
||||
"921", "922", "923", "924", "925", "926", "927", "928", "929", "930",
|
||||
"931", "932", "933", "934", "935", "936", "937", "938", "939", "940",
|
||||
"941", "942", "943", "944", "945", "946", "947", "948", "949", "950",
|
||||
"951", "952", "953", "954", "955", "956", "957", "958", "959", "960",
|
||||
"961", "962", "963", "964", "965", "966", "967", "968", "969", "970",
|
||||
"971", "972", "973", "974", "975", "976", "977", "978", "979", "980",
|
||||
"981", "982", "983", "984", "985", "986", "987", "988", "989", "990",
|
||||
"991", "992", "993", "994", "995", "996", "997", "998", "999"
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_uint32_to_string --
|
||||
*
|
||||
* Converts @value to a string.
|
||||
*
|
||||
* If @value is from 0 to 1000, it will use a constant string in the
|
||||
* data section of the library.
|
||||
*
|
||||
* If not, a string will be formatted using @str and snprintf(). This
|
||||
* is much slower, of course and therefore we try to optimize it out.
|
||||
*
|
||||
* @strptr will always be set. It will either point to @str or a
|
||||
* constant string. You will want to use this as your key.
|
||||
*
|
||||
* Parameters:
|
||||
* @value: A #uint32_t to convert to string.
|
||||
* @strptr: (out): A pointer to the resulting string.
|
||||
* @str: (out): Storage for a string made with snprintf.
|
||||
* @size: Size of @str.
|
||||
*
|
||||
* Returns:
|
||||
* The number of bytes in the resulting string.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
size_t
|
||||
bson_uint32_to_string (uint32_t value, /* IN */
|
||||
const char **strptr, /* OUT */
|
||||
char *str, /* OUT */
|
||||
size_t size) /* IN */
|
||||
{
|
||||
if (value < 1000) {
|
||||
*strptr = gUint32Strs[value];
|
||||
|
||||
if (value < 10) {
|
||||
return 1;
|
||||
} else if (value < 100) {
|
||||
return 2;
|
||||
} else {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
*strptr = str;
|
||||
|
||||
return bson_snprintf (str, size, "%u", value);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_KEYS_H
|
||||
#define BSON_KEYS_H
|
||||
|
||||
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
size_t bson_uint32_to_string (uint32_t value,
|
||||
const char **strptr,
|
||||
char *str,
|
||||
size_t size);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_KEYS_H */
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_MACROS_H
|
||||
#define BSON_MACROS_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include <algorithm>
|
||||
#endif
|
||||
|
||||
#include "bson-config.h"
|
||||
|
||||
|
||||
#if BSON_OS == 1
|
||||
# define BSON_OS_UNIX
|
||||
#elif BSON_OS == 2
|
||||
# define BSON_OS_WIN32
|
||||
#else
|
||||
# error "Unknown operating system."
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define BSON_BEGIN_DECLS extern "C" {
|
||||
# define BSON_END_DECLS }
|
||||
#else
|
||||
# define BSON_BEGIN_DECLS
|
||||
# define BSON_END_DECLS
|
||||
#endif
|
||||
|
||||
|
||||
#define BSON_GNUC_CHECK_VERSION(major, minor) \
|
||||
(defined(__GNUC__) && \
|
||||
((__GNUC__ > (major)) || \
|
||||
((__GNUC__ == (major)) && \
|
||||
(__GNUC_MINOR__ >= (minor)))))
|
||||
|
||||
|
||||
#define BSON_GNUC_IS_VERSION(major, minor) \
|
||||
(defined(__GNUC__) && \
|
||||
(__GNUC__ == (major)) && \
|
||||
(__GNUC_MINOR__ == (minor)))
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# ifdef BSON_COMPILATION
|
||||
# define BSON_API __declspec(dllexport)
|
||||
# else
|
||||
# define BSON_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# define BSON_API
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MIN
|
||||
# define BSON_MIN MIN
|
||||
#elif defined(__cplusplus)
|
||||
# define BSON_MIN(a, b) ( (std::min)(a, b) )
|
||||
#elif defined(_MSC_VER)
|
||||
# define BSON_MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#else
|
||||
# define BSON_MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MAX
|
||||
# define BSON_MAX MAX
|
||||
#elif defined(__cplusplus)
|
||||
# define BSON_MAX(a, b) ( (std::max)(a, b) )
|
||||
#elif defined(_MSC_VER)
|
||||
# define BSON_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#else
|
||||
# define BSON_MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ABS
|
||||
# define BSON_ABS ABS
|
||||
#else
|
||||
# define BSON_ABS(a) (((a) < 0) ? ((a) * -1) : (a))
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# ifdef _WIN64
|
||||
# define BSON_ALIGN_OF_PTR 8
|
||||
# else
|
||||
# define BSON_ALIGN_OF_PTR 4
|
||||
# endif
|
||||
#else
|
||||
# define BSON_ALIGN_OF_PTR (sizeof(void *))
|
||||
#endif
|
||||
|
||||
#ifdef BSON_EXTRA_ALIGN
|
||||
# if defined(_MSC_VER)
|
||||
# define BSON_ALIGNED_BEGIN(_N) __declspec (align (_N))
|
||||
# define BSON_ALIGNED_END(_N)
|
||||
# else
|
||||
# define BSON_ALIGNED_BEGIN(_N)
|
||||
# define BSON_ALIGNED_END(_N) __attribute__((aligned (_N)))
|
||||
# endif
|
||||
#else
|
||||
# if defined(_MSC_VER)
|
||||
# define BSON_ALIGNED_BEGIN(_N) __declspec (align ((_N) > BSON_ALIGN_OF_PTR ? BSON_ALIGN_OF_PTR : (_N) ))
|
||||
# define BSON_ALIGNED_END(_N)
|
||||
# else
|
||||
# define BSON_ALIGNED_BEGIN(_N)
|
||||
# define BSON_ALIGNED_END(_N) __attribute__((aligned ((_N) > BSON_ALIGN_OF_PTR ? BSON_ALIGN_OF_PTR : (_N) )))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#define bson_str_empty(s) (!s[0])
|
||||
#define bson_str_empty0(s) (!s || !s[0])
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define BSON_FUNC __FUNCTION__
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ < 199901L
|
||||
# define BSON_FUNC __FUNCTION__
|
||||
#else
|
||||
# define BSON_FUNC __func__
|
||||
#endif
|
||||
|
||||
#define BSON_ASSERT(test) \
|
||||
do { \
|
||||
if (!(BSON_LIKELY(test))) { \
|
||||
fprintf (stderr, "%s:%d %s(): precondition failed: %s\n", \
|
||||
__FILE__, __LINE__, BSON_FUNC, #test); \
|
||||
abort (); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define BSON_STATIC_ASSERT(s) BSON_STATIC_ASSERT_ (s, __LINE__)
|
||||
#define BSON_STATIC_ASSERT_JOIN(a, b) BSON_STATIC_ASSERT_JOIN2 (a, b)
|
||||
#define BSON_STATIC_ASSERT_JOIN2(a, b) a##b
|
||||
#define BSON_STATIC_ASSERT_(s, l) \
|
||||
typedef char BSON_STATIC_ASSERT_JOIN (static_assert_test_, \
|
||||
__LINE__)[(s) ? 1 : -1]
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define BSON_GNUC_CONST __attribute__((const))
|
||||
# define BSON_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
# define BSON_GNUC_CONST
|
||||
# define BSON_GNUC_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
|
||||
#if BSON_GNUC_CHECK_VERSION(4, 0) && !defined(_WIN32)
|
||||
# define BSON_GNUC_NULL_TERMINATED __attribute__((sentinel))
|
||||
# define BSON_GNUC_INTERNAL __attribute__((visibility ("hidden")))
|
||||
#else
|
||||
# define BSON_GNUC_NULL_TERMINATED
|
||||
# define BSON_GNUC_INTERNAL
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define BSON_LIKELY(x) __builtin_expect (!!(x), 1)
|
||||
# define BSON_UNLIKELY(x) __builtin_expect (!!(x), 0)
|
||||
#else
|
||||
# define BSON_LIKELY(v) v
|
||||
# define BSON_UNLIKELY(v) v
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__clang__)
|
||||
# define BSON_GNUC_PRINTF(f, v) __attribute__((format (printf, f, v)))
|
||||
#elif BSON_GNUC_CHECK_VERSION(4, 4)
|
||||
# define BSON_GNUC_PRINTF(f, v) __attribute__((format (gnu_printf, f, v)))
|
||||
#else
|
||||
# define BSON_GNUC_PRINTF(f, v)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__LP64__) || defined(_LP64)
|
||||
# define BSON_WORD_SIZE 64
|
||||
#else
|
||||
# define BSON_WORD_SIZE 32
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define BSON_INLINE __inline
|
||||
#else
|
||||
# define BSON_INLINE __inline__
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define BSON_ENSURE_ARRAY_PARAM_SIZE(_n)
|
||||
# define BSON_TYPEOF decltype
|
||||
#else
|
||||
# define BSON_ENSURE_ARRAY_PARAM_SIZE(_n) static (_n)
|
||||
# define BSON_TYPEOF typeof
|
||||
#endif
|
||||
|
||||
|
||||
#if BSON_GNUC_CHECK_VERSION(3, 1)
|
||||
# define BSON_GNUC_DEPRECATED __attribute__((__deprecated__))
|
||||
#else
|
||||
# define BSON_GNUC_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
#if BSON_GNUC_CHECK_VERSION(4, 5)
|
||||
# define BSON_GNUC_DEPRECATED_FOR(f) __attribute__((deprecated("Use " #f " instead")))
|
||||
#else
|
||||
# define BSON_GNUC_DEPRECATED_FOR(f) BSON_GNUC_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* BSON_MACROS_H */
|
||||
@@ -0,0 +1,404 @@
|
||||
/*
|
||||
Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/* $Id$ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.c is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
|
||||
either statically or dynamically; added missing #include <string.h>
|
||||
in library.
|
||||
2002-03-11 lpd Corrected argument list for main(), and added int return
|
||||
type, in test program and T value program.
|
||||
2002-02-21 lpd Added missing #include <stdio.h> in test program.
|
||||
2000-07-03 lpd Patched to eliminate warnings about "constant is
|
||||
unsigned in ANSI C, signed in traditional"; made test program
|
||||
self-checking.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following MD5 implementation has been modified to use types as
|
||||
* specified in libbson.
|
||||
*/
|
||||
|
||||
#include "bson-compat.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "bson-md5.h"
|
||||
|
||||
|
||||
#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
|
||||
#if BSON_BYTE_ORDER == BSON_BIG_ENDIAN
|
||||
# define BYTE_ORDER 1
|
||||
#else
|
||||
# define BYTE_ORDER -1
|
||||
#endif
|
||||
|
||||
#define T_MASK ((uint32_t)~0)
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 0x242070db
|
||||
#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
|
||||
#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
|
||||
#define T6 0x4787c62a
|
||||
#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
|
||||
#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
|
||||
#define T9 0x698098d8
|
||||
#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
|
||||
#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
|
||||
#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
|
||||
#define T13 0x6b901122
|
||||
#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
|
||||
#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
|
||||
#define T16 0x49b40821
|
||||
#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
|
||||
#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
|
||||
#define T19 0x265e5a51
|
||||
#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
|
||||
#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
|
||||
#define T22 0x02441453
|
||||
#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
|
||||
#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
|
||||
#define T25 0x21e1cde6
|
||||
#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
|
||||
#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
|
||||
#define T28 0x455a14ed
|
||||
#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
|
||||
#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
|
||||
#define T31 0x676f02d9
|
||||
#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
|
||||
#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
|
||||
#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
|
||||
#define T35 0x6d9d6122
|
||||
#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
|
||||
#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
|
||||
#define T38 0x4bdecfa9
|
||||
#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
|
||||
#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
|
||||
#define T41 0x289b7ec6
|
||||
#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
|
||||
#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
|
||||
#define T44 0x04881d05
|
||||
#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
|
||||
#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
|
||||
#define T47 0x1fa27cf8
|
||||
#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
|
||||
#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
|
||||
#define T50 0x432aff97
|
||||
#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
|
||||
#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
|
||||
#define T53 0x655b59c3
|
||||
#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
|
||||
#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
|
||||
#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
|
||||
#define T57 0x6fa87e4f
|
||||
#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
|
||||
#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
|
||||
#define T60 0x4e0811a1
|
||||
#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
|
||||
#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
|
||||
static void
|
||||
bson_md5_process (bson_md5_t *md5,
|
||||
const uint8_t *data)
|
||||
{
|
||||
uint32_t a = md5->abcd[0];
|
||||
uint32_t b = md5->abcd[1];
|
||||
uint32_t c = md5->abcd[2];
|
||||
uint32_t d = md5->abcd[3];
|
||||
uint32_t t;
|
||||
|
||||
#if BYTE_ORDER > 0
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
uint32_t X[16];
|
||||
#else
|
||||
/* Define storage for little-endian or both types of CPUs. */
|
||||
uint32_t xbuf[16];
|
||||
const uint32_t *X;
|
||||
#endif
|
||||
|
||||
{
|
||||
#if BYTE_ORDER == 0
|
||||
/*
|
||||
* Determine dynamically whether this is a big-endian or
|
||||
* little-endian machine, since we can use a more efficient
|
||||
* algorithm on the latter.
|
||||
*/
|
||||
static const int w = 1;
|
||||
|
||||
if (*((const uint8_t *)&w)) /* dynamic little-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER <= 0 /* little-endian */
|
||||
{
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - (const uint8_t *)0) & 3)) {
|
||||
/* data are properly aligned */
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wcast-align"
|
||||
#endif
|
||||
X = (const uint32_t *)data;
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* not aligned */
|
||||
memcpy(xbuf, data, sizeof (xbuf));
|
||||
X = xbuf;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if BYTE_ORDER == 0
|
||||
else /* dynamic big-endian */
|
||||
#endif
|
||||
#if BYTE_ORDER >= 0 /* big-endian */
|
||||
{
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const uint8_t *xp = data;
|
||||
int i;
|
||||
|
||||
# if BYTE_ORDER == 0
|
||||
X = xbuf; /* (dynamic only) */
|
||||
# else
|
||||
# define xbuf X /* (static only) */
|
||||
# endif
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + F(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + G(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + H(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + I(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
md5->abcd[0] += a;
|
||||
md5->abcd[1] += b;
|
||||
md5->abcd[2] += c;
|
||||
md5->abcd[3] += d;
|
||||
}
|
||||
|
||||
void
|
||||
bson_md5_init (bson_md5_t *pms)
|
||||
{
|
||||
pms->count[0] = pms->count[1] = 0;
|
||||
pms->abcd[0] = 0x67452301;
|
||||
pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
pms->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
void
|
||||
bson_md5_append (bson_md5_t *pms,
|
||||
const uint8_t *data,
|
||||
uint32_t nbytes)
|
||||
{
|
||||
const uint8_t *p = data;
|
||||
int left = nbytes;
|
||||
int offset = (pms->count[0] >> 3) & 63;
|
||||
uint32_t nbits = (uint32_t)(nbytes << 3);
|
||||
|
||||
if (nbytes <= 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
pms->count[1] += nbytes >> 29;
|
||||
pms->count[0] += nbits;
|
||||
if (pms->count[0] < nbits)
|
||||
pms->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset) {
|
||||
int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
|
||||
|
||||
memcpy(pms->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
p += copy;
|
||||
left -= copy;
|
||||
bson_md5_process(pms, pms->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
bson_md5_process(pms, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
memcpy(pms->buf, p, left);
|
||||
}
|
||||
|
||||
void
|
||||
bson_md5_finish (bson_md5_t *pms,
|
||||
uint8_t digest[16])
|
||||
{
|
||||
static const uint8_t pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
uint8_t data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
bson_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
bson_md5_append(pms, data, sizeof (data));
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
L. Peter Deutsch
|
||||
ghost@aladdin.com
|
||||
|
||||
*/
|
||||
/* $Id$ */
|
||||
/*
|
||||
Independent implementation of MD5 (RFC 1321).
|
||||
|
||||
This code implements the MD5 Algorithm defined in RFC 1321, whose
|
||||
text is available at
|
||||
http://www.ietf.org/rfc/rfc1321.txt
|
||||
The code is derived from the text of the RFC, including the test suite
|
||||
(section A.5) but excluding the rest of Appendix A. It does not include
|
||||
any code or documentation that is identified in the RFC as being
|
||||
copyrighted.
|
||||
|
||||
The original and principal author of md5.h is L. Peter Deutsch
|
||||
<ghost@aladdin.com>. Other authors are noted in the change history
|
||||
that follows (in reverse chronological order):
|
||||
|
||||
2002-04-13 lpd Removed support for non-ANSI compilers; removed
|
||||
references to Ghostscript; clarified derivation from RFC 1321;
|
||||
now handles byte order either statically or dynamically.
|
||||
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
|
||||
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
|
||||
added conditionalization for C++ compilation from Martin
|
||||
Purschke <purschke@bnl.gov>.
|
||||
1999-05-03 lpd Original version.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* The following MD5 implementation has been modified to use types as
|
||||
* specified in libbson.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_MD5_H
|
||||
#define BSON_MD5_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson-endian.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t count[2]; /* message length in bits, lsw first */
|
||||
uint32_t abcd[4]; /* digest buffer */
|
||||
uint8_t buf[64]; /* accumulate block */
|
||||
} bson_md5_t;
|
||||
|
||||
|
||||
void bson_md5_init (bson_md5_t *pms);
|
||||
void bson_md5_append (bson_md5_t *pms,
|
||||
const uint8_t *data,
|
||||
uint32_t nbytes);
|
||||
void bson_md5_finish (bson_md5_t *pms,
|
||||
uint8_t digest[16]);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_MD5_H */
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bson-atomic.h"
|
||||
#include "bson-config.h"
|
||||
#include "bson-memory.h"
|
||||
|
||||
|
||||
static bson_mem_vtable_t gMemVtable = {
|
||||
malloc,
|
||||
calloc,
|
||||
#ifdef __APPLE__
|
||||
reallocf,
|
||||
#else
|
||||
realloc,
|
||||
#endif
|
||||
free,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_malloc --
|
||||
*
|
||||
* Allocates @num_bytes of memory and returns a pointer to it. If
|
||||
* malloc failed to allocate the memory, abort() is called.
|
||||
*
|
||||
* Libbson does not try to handle OOM conditions as it is beyond the
|
||||
* scope of this library to handle so appropriately.
|
||||
*
|
||||
* Parameters:
|
||||
* @num_bytes: The number of bytes to allocate.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer if successful; otherwise abort() is called and this
|
||||
* function will never return.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void *
|
||||
bson_malloc (size_t num_bytes) /* IN */
|
||||
{
|
||||
void *mem;
|
||||
|
||||
if (!(mem = gMemVtable.malloc (num_bytes))) {
|
||||
abort ();
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_malloc0 --
|
||||
*
|
||||
* Like bson_malloc() except the memory is zeroed first. This is
|
||||
* similar to calloc() except that abort() is called in case of
|
||||
* failure to allocate memory.
|
||||
*
|
||||
* Parameters:
|
||||
* @num_bytes: The number of bytes to allocate.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer if successful; otherwise abort() is called and this
|
||||
* function will never return.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void *
|
||||
bson_malloc0 (size_t num_bytes) /* IN */
|
||||
{
|
||||
void *mem = NULL;
|
||||
|
||||
if (BSON_LIKELY (num_bytes)) {
|
||||
if (BSON_UNLIKELY (!(mem = gMemVtable.calloc (1, num_bytes)))) {
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_realloc --
|
||||
*
|
||||
* This function behaves similar to realloc() except that if there is
|
||||
* a failure abort() is called.
|
||||
*
|
||||
* Parameters:
|
||||
* @mem: The memory to realloc, or NULL.
|
||||
* @num_bytes: The size of the new allocation or 0 to free.
|
||||
*
|
||||
* Returns:
|
||||
* The new allocation if successful; otherwise abort() is called and
|
||||
* this function never returns.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void *
|
||||
bson_realloc (void *mem, /* IN */
|
||||
size_t num_bytes) /* IN */
|
||||
{
|
||||
/*
|
||||
* Not all platforms are guaranteed to free() the memory if a call to
|
||||
* realloc() with a size of zero occurs. Windows, Linux, and FreeBSD do,
|
||||
* however, OS X does not.
|
||||
*/
|
||||
if (BSON_UNLIKELY (num_bytes == 0)) {
|
||||
gMemVtable.free (mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mem = gMemVtable.realloc (mem, num_bytes);
|
||||
|
||||
if (BSON_UNLIKELY (!mem)) {
|
||||
abort ();
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_realloc_ctx --
|
||||
*
|
||||
* This wraps bson_realloc and provides a compatible api for similar
|
||||
* functions with a context
|
||||
*
|
||||
* Parameters:
|
||||
* @mem: The memory to realloc, or NULL.
|
||||
* @num_bytes: The size of the new allocation or 0 to free.
|
||||
* @ctx: Ignored
|
||||
*
|
||||
* Returns:
|
||||
* The new allocation if successful; otherwise abort() is called and
|
||||
* this function never returns.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void *
|
||||
bson_realloc_ctx (void *mem, /* IN */
|
||||
size_t num_bytes, /* IN */
|
||||
void *ctx) /* IN */
|
||||
{
|
||||
return bson_realloc (mem, num_bytes);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_free --
|
||||
*
|
||||
* Frees @mem using the underlying allocator.
|
||||
*
|
||||
* Currently, this only calls free() directly, but that is subject to
|
||||
* change.
|
||||
*
|
||||
* Parameters:
|
||||
* @mem: An allocation to free.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_free (void *mem) /* IN */
|
||||
{
|
||||
gMemVtable.free (mem);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_zero_free --
|
||||
*
|
||||
* Frees @mem using the underlying allocator. @size bytes of @mem will
|
||||
* be zeroed before freeing the memory. This is useful in scenarios
|
||||
* where @mem contains passwords or other sensitive information.
|
||||
*
|
||||
* Parameters:
|
||||
* @mem: An allocation to free.
|
||||
* @size: The number of bytes in @mem.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_zero_free (void *mem, /* IN */
|
||||
size_t size) /* IN */
|
||||
{
|
||||
if (BSON_LIKELY (mem)) {
|
||||
memset (mem, 0, size);
|
||||
gMemVtable.free (mem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_mem_set_vtable --
|
||||
*
|
||||
* This function will change our allocationt vtable.
|
||||
*
|
||||
* It is imperitive that this is called at the beginning of the
|
||||
* process before any memory has been allocated by the default
|
||||
* allocator.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_mem_set_vtable (const bson_mem_vtable_t *vtable)
|
||||
{
|
||||
BSON_ASSERT (vtable);
|
||||
|
||||
if (!vtable->malloc ||
|
||||
!vtable->calloc ||
|
||||
!vtable->realloc ||
|
||||
!vtable->free) {
|
||||
fprintf (stderr, "Failure to install BSON vtable, "
|
||||
"missing functions.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gMemVtable = *vtable;
|
||||
}
|
||||
|
||||
void
|
||||
bson_mem_restore_vtable (void)
|
||||
{
|
||||
bson_mem_vtable_t vtable = {
|
||||
malloc,
|
||||
calloc,
|
||||
#ifdef __APPLE__
|
||||
reallocf,
|
||||
#else
|
||||
realloc,
|
||||
#endif
|
||||
free,
|
||||
};
|
||||
|
||||
bson_mem_set_vtable(&vtable);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_MEMORY_H
|
||||
#define BSON_MEMORY_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef void *(*bson_realloc_func) (void *mem,
|
||||
size_t num_bytes,
|
||||
void *ctx);
|
||||
|
||||
|
||||
typedef struct _bson_mem_vtable_t
|
||||
{
|
||||
void *(*malloc) (size_t num_bytes);
|
||||
void *(*calloc) (size_t n_members,
|
||||
size_t num_bytes);
|
||||
void *(*realloc) (void *mem,
|
||||
size_t num_bytes);
|
||||
void (*free) (void *mem);
|
||||
void *padding [4];
|
||||
} bson_mem_vtable_t;
|
||||
|
||||
|
||||
void bson_mem_set_vtable (const bson_mem_vtable_t *vtable);
|
||||
void bson_mem_restore_vtable (void);
|
||||
void *bson_malloc (size_t num_bytes);
|
||||
void *bson_malloc0 (size_t num_bytes);
|
||||
void *bson_realloc (void *mem,
|
||||
size_t num_bytes);
|
||||
void *bson_realloc_ctx (void *mem,
|
||||
size_t num_bytes,
|
||||
void *ctx);
|
||||
void bson_free (void *mem);
|
||||
void bson_zero_free (void *mem,
|
||||
size_t size);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_MEMORY_H */
|
||||
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson-compat.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bson-context-private.h"
|
||||
#include "bson-md5.h"
|
||||
#include "bson-oid.h"
|
||||
#include "bson-string.h"
|
||||
|
||||
|
||||
/*
|
||||
* This table contains an array of two character pairs for every possible
|
||||
* uint8_t. It is used as a lookup table when encoding a bson_oid_t
|
||||
* to hex formatted ASCII. Performing two characters at a time roughly
|
||||
* reduces the number of operations by one-half.
|
||||
*/
|
||||
static const uint16_t gHexCharPairs[] = {
|
||||
#if BSON_BYTE_ORDER == BSON_BIG_ENDIAN
|
||||
12336, 12337, 12338, 12339, 12340, 12341, 12342, 12343, 12344, 12345,
|
||||
12385, 12386, 12387, 12388, 12389, 12390, 12592, 12593, 12594, 12595,
|
||||
12596, 12597, 12598, 12599, 12600, 12601, 12641, 12642, 12643, 12644,
|
||||
12645, 12646, 12848, 12849, 12850, 12851, 12852, 12853, 12854, 12855,
|
||||
12856, 12857, 12897, 12898, 12899, 12900, 12901, 12902, 13104, 13105,
|
||||
13106, 13107, 13108, 13109, 13110, 13111, 13112, 13113, 13153, 13154,
|
||||
13155, 13156, 13157, 13158, 13360, 13361, 13362, 13363, 13364, 13365,
|
||||
13366, 13367, 13368, 13369, 13409, 13410, 13411, 13412, 13413, 13414,
|
||||
13616, 13617, 13618, 13619, 13620, 13621, 13622, 13623, 13624, 13625,
|
||||
13665, 13666, 13667, 13668, 13669, 13670, 13872, 13873, 13874, 13875,
|
||||
13876, 13877, 13878, 13879, 13880, 13881, 13921, 13922, 13923, 13924,
|
||||
13925, 13926, 14128, 14129, 14130, 14131, 14132, 14133, 14134, 14135,
|
||||
14136, 14137, 14177, 14178, 14179, 14180, 14181, 14182, 14384, 14385,
|
||||
14386, 14387, 14388, 14389, 14390, 14391, 14392, 14393, 14433, 14434,
|
||||
14435, 14436, 14437, 14438, 14640, 14641, 14642, 14643, 14644, 14645,
|
||||
14646, 14647, 14648, 14649, 14689, 14690, 14691, 14692, 14693, 14694,
|
||||
24880, 24881, 24882, 24883, 24884, 24885, 24886, 24887, 24888, 24889,
|
||||
24929, 24930, 24931, 24932, 24933, 24934, 25136, 25137, 25138, 25139,
|
||||
25140, 25141, 25142, 25143, 25144, 25145, 25185, 25186, 25187, 25188,
|
||||
25189, 25190, 25392, 25393, 25394, 25395, 25396, 25397, 25398, 25399,
|
||||
25400, 25401, 25441, 25442, 25443, 25444, 25445, 25446, 25648, 25649,
|
||||
25650, 25651, 25652, 25653, 25654, 25655, 25656, 25657, 25697, 25698,
|
||||
25699, 25700, 25701, 25702, 25904, 25905, 25906, 25907, 25908, 25909,
|
||||
25910, 25911, 25912, 25913, 25953, 25954, 25955, 25956, 25957, 25958,
|
||||
26160, 26161, 26162, 26163, 26164, 26165, 26166, 26167, 26168, 26169,
|
||||
26209, 26210, 26211, 26212, 26213, 26214
|
||||
#else
|
||||
12336, 12592, 12848, 13104, 13360, 13616, 13872, 14128, 14384, 14640,
|
||||
24880, 25136, 25392, 25648, 25904, 26160, 12337, 12593, 12849, 13105,
|
||||
13361, 13617, 13873, 14129, 14385, 14641, 24881, 25137, 25393, 25649,
|
||||
25905, 26161, 12338, 12594, 12850, 13106, 13362, 13618, 13874, 14130,
|
||||
14386, 14642, 24882, 25138, 25394, 25650, 25906, 26162, 12339, 12595,
|
||||
12851, 13107, 13363, 13619, 13875, 14131, 14387, 14643, 24883, 25139,
|
||||
25395, 25651, 25907, 26163, 12340, 12596, 12852, 13108, 13364, 13620,
|
||||
13876, 14132, 14388, 14644, 24884, 25140, 25396, 25652, 25908, 26164,
|
||||
12341, 12597, 12853, 13109, 13365, 13621, 13877, 14133, 14389, 14645,
|
||||
24885, 25141, 25397, 25653, 25909, 26165, 12342, 12598, 12854, 13110,
|
||||
13366, 13622, 13878, 14134, 14390, 14646, 24886, 25142, 25398, 25654,
|
||||
25910, 26166, 12343, 12599, 12855, 13111, 13367, 13623, 13879, 14135,
|
||||
14391, 14647, 24887, 25143, 25399, 25655, 25911, 26167, 12344, 12600,
|
||||
12856, 13112, 13368, 13624, 13880, 14136, 14392, 14648, 24888, 25144,
|
||||
25400, 25656, 25912, 26168, 12345, 12601, 12857, 13113, 13369, 13625,
|
||||
13881, 14137, 14393, 14649, 24889, 25145, 25401, 25657, 25913, 26169,
|
||||
12385, 12641, 12897, 13153, 13409, 13665, 13921, 14177, 14433, 14689,
|
||||
24929, 25185, 25441, 25697, 25953, 26209, 12386, 12642, 12898, 13154,
|
||||
13410, 13666, 13922, 14178, 14434, 14690, 24930, 25186, 25442, 25698,
|
||||
25954, 26210, 12387, 12643, 12899, 13155, 13411, 13667, 13923, 14179,
|
||||
14435, 14691, 24931, 25187, 25443, 25699, 25955, 26211, 12388, 12644,
|
||||
12900, 13156, 13412, 13668, 13924, 14180, 14436, 14692, 24932, 25188,
|
||||
25444, 25700, 25956, 26212, 12389, 12645, 12901, 13157, 13413, 13669,
|
||||
13925, 14181, 14437, 14693, 24933, 25189, 25445, 25701, 25957, 26213,
|
||||
12390, 12646, 12902, 13158, 13414, 13670, 13926, 14182, 14438, 14694,
|
||||
24934, 25190, 25446, 25702, 25958, 26214
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_init_sequence --
|
||||
*
|
||||
* Initializes @oid with the next oid in the sequence. The first 4
|
||||
* bytes contain the current time and the following 8 contain a 64-bit
|
||||
* integer in big-endian format.
|
||||
*
|
||||
* The bson_oid_t generated by this function is not guaranteed to be
|
||||
* globally unique. Only unique within this context. It is however,
|
||||
* guaranteed to be sequential.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is initialized.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_oid_init_sequence (bson_oid_t *oid, /* OUT */
|
||||
bson_context_t *context) /* IN */
|
||||
{
|
||||
uint32_t now = (uint32_t)(time (NULL));
|
||||
|
||||
if (!context) {
|
||||
context = bson_context_get_default ();
|
||||
}
|
||||
|
||||
now = BSON_UINT32_TO_BE (now);
|
||||
|
||||
memcpy (&oid->bytes[0], &now, sizeof (now));
|
||||
context->oid_get_seq64 (context, oid);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_init --
|
||||
*
|
||||
* Generates bytes for a new bson_oid_t and stores them in @oid. The
|
||||
* bytes will be generated according to the specification and includes
|
||||
* the current time, first 3 bytes of MD5(hostname), pid (or tid), and
|
||||
* monotonic counter.
|
||||
*
|
||||
* The bson_oid_t generated by this function is not guaranteed to be
|
||||
* globally unique. Only unique within this context. It is however,
|
||||
* guaranteed to be sequential.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is initialized.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_oid_init (bson_oid_t *oid, /* OUT */
|
||||
bson_context_t *context) /* IN */
|
||||
{
|
||||
uint32_t now = (uint32_t)(time (NULL));
|
||||
|
||||
BSON_ASSERT (oid);
|
||||
|
||||
if (!context) {
|
||||
context = bson_context_get_default ();
|
||||
}
|
||||
|
||||
now = BSON_UINT32_TO_BE (now);
|
||||
memcpy (&oid->bytes[0], &now, sizeof (now));
|
||||
|
||||
context->oid_get_host (context, oid);
|
||||
context->oid_get_pid (context, oid);
|
||||
context->oid_get_seq32 (context, oid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_init_from_data:
|
||||
* @oid: A bson_oid_t to initialize.
|
||||
* @bytes: A 12-byte buffer to copy into @oid.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_init_from_data --
|
||||
*
|
||||
* Initializes an @oid from @data. @data MUST be a buffer of at least
|
||||
* 12 bytes. This method is analagous to memcpy()'ing data into @oid.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is initialized.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_oid_init_from_data (bson_oid_t *oid, /* OUT */
|
||||
const uint8_t *data) /* IN */
|
||||
{
|
||||
BSON_ASSERT (oid);
|
||||
BSON_ASSERT (data);
|
||||
|
||||
memcpy (oid, data, 12);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_init_from_string --
|
||||
*
|
||||
* Parses @str containing hex formatted bytes of an object id and
|
||||
* places the bytes in @oid.
|
||||
*
|
||||
* Parameters:
|
||||
* @oid: A bson_oid_t
|
||||
* @str: A string containing at least 24 characters.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @oid is initialized.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_oid_init_from_string (bson_oid_t *oid, /* OUT */
|
||||
const char *str) /* IN */
|
||||
{
|
||||
BSON_ASSERT (oid);
|
||||
BSON_ASSERT (str);
|
||||
|
||||
bson_oid_init_from_string_unsafe (oid, str);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_get_time_t --
|
||||
*
|
||||
* Fetches the time for which @oid was created.
|
||||
*
|
||||
* Returns:
|
||||
* A time_t.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
time_t
|
||||
bson_oid_get_time_t (const bson_oid_t *oid) /* IN */
|
||||
{
|
||||
BSON_ASSERT (oid);
|
||||
|
||||
return bson_oid_get_time_t_unsafe (oid);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_to_string --
|
||||
*
|
||||
* Formats a bson_oid_t into a string. @str must contain enough bytes
|
||||
* for the resulting string which is 25 bytes with a terminating
|
||||
* NUL-byte.
|
||||
*
|
||||
* Parameters:
|
||||
* @oid: A bson_oid_t.
|
||||
* @str: A location to store the resulting string.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_oid_to_string
|
||||
(const bson_oid_t *oid, /* IN */
|
||||
char str[BSON_ENSURE_ARRAY_PARAM_SIZE(25)]) /* OUT */
|
||||
{
|
||||
#if !defined(__i386__) && !defined(__x86_64__)
|
||||
BSON_ASSERT (oid);
|
||||
BSON_ASSERT (str);
|
||||
|
||||
bson_snprintf (str, 25,
|
||||
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
oid->bytes[0],
|
||||
oid->bytes[1],
|
||||
oid->bytes[2],
|
||||
oid->bytes[3],
|
||||
oid->bytes[4],
|
||||
oid->bytes[5],
|
||||
oid->bytes[6],
|
||||
oid->bytes[7],
|
||||
oid->bytes[8],
|
||||
oid->bytes[9],
|
||||
oid->bytes[10],
|
||||
oid->bytes[11]);
|
||||
#else
|
||||
uint16_t *dst;
|
||||
uint8_t *id = (uint8_t *)oid;
|
||||
|
||||
BSON_ASSERT (oid);
|
||||
BSON_ASSERT (str);
|
||||
|
||||
dst = (uint16_t *)(void *)str;
|
||||
dst[0] = gHexCharPairs[id[0]];
|
||||
dst[1] = gHexCharPairs[id[1]];
|
||||
dst[2] = gHexCharPairs[id[2]];
|
||||
dst[3] = gHexCharPairs[id[3]];
|
||||
dst[4] = gHexCharPairs[id[4]];
|
||||
dst[5] = gHexCharPairs[id[5]];
|
||||
dst[6] = gHexCharPairs[id[6]];
|
||||
dst[7] = gHexCharPairs[id[7]];
|
||||
dst[8] = gHexCharPairs[id[8]];
|
||||
dst[9] = gHexCharPairs[id[9]];
|
||||
dst[10] = gHexCharPairs[id[10]];
|
||||
dst[11] = gHexCharPairs[id[11]];
|
||||
str[24] = '\0';
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_hash --
|
||||
*
|
||||
* Hashes the bytes of the provided bson_oid_t using DJB hash. This
|
||||
* allows bson_oid_t to be used as keys in a hash table.
|
||||
*
|
||||
* Returns:
|
||||
* A hash value corresponding to @oid.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
bson_oid_hash (const bson_oid_t *oid) /* IN */
|
||||
{
|
||||
BSON_ASSERT (oid);
|
||||
|
||||
return bson_oid_hash_unsafe (oid);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_compare --
|
||||
*
|
||||
* A qsort() style compare function that will return less than zero if
|
||||
* @oid1 is less than @oid2, zero if they are the same, and greater
|
||||
* than zero if @oid2 is greater than @oid1.
|
||||
*
|
||||
* Returns:
|
||||
* A qsort() style compare integer.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
bson_oid_compare (const bson_oid_t *oid1, /* IN */
|
||||
const bson_oid_t *oid2) /* IN */
|
||||
{
|
||||
BSON_ASSERT (oid1);
|
||||
BSON_ASSERT (oid2);
|
||||
|
||||
return bson_oid_compare_unsafe (oid1, oid2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_equal --
|
||||
*
|
||||
* Compares for equality of @oid1 and @oid2. If they are equal, then
|
||||
* true is returned, otherwise false.
|
||||
*
|
||||
* Returns:
|
||||
* A boolean indicating the equality of @oid1 and @oid2.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
bson_oid_equal (const bson_oid_t *oid1, /* IN */
|
||||
const bson_oid_t *oid2) /* IN */
|
||||
{
|
||||
BSON_ASSERT (oid1);
|
||||
BSON_ASSERT (oid2);
|
||||
|
||||
return bson_oid_equal_unsafe (oid1, oid2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_copy --
|
||||
*
|
||||
* Copies the contents of @src to @dst.
|
||||
*
|
||||
* Parameters:
|
||||
* @src: A bson_oid_t to copy from.
|
||||
* @dst: A bson_oid_t to copy to.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @dst will contain a copy of the data in @src.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_oid_copy (const bson_oid_t *src, /* IN */
|
||||
bson_oid_t *dst) /* OUT */
|
||||
{
|
||||
BSON_ASSERT (src);
|
||||
BSON_ASSERT (dst);
|
||||
|
||||
bson_oid_copy_unsafe (src, dst);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_oid_is_valid --
|
||||
*
|
||||
* Validates that @str is a valid OID string. @length MUST be 24, but
|
||||
* is provided as a parameter to simplify calling code.
|
||||
*
|
||||
* Parameters:
|
||||
* @str: A string to validate.
|
||||
* @length: The length of @str.
|
||||
*
|
||||
* Returns:
|
||||
* true if @str can be passed to bson_oid_init_from_string().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
bson_oid_is_valid (const char *str, /* IN */
|
||||
size_t length) /* IN */
|
||||
{
|
||||
size_t i;
|
||||
|
||||
BSON_ASSERT (str);
|
||||
|
||||
if ((length == 25) && (str [24] == '\0')) {
|
||||
length = 24;
|
||||
}
|
||||
|
||||
if (length == 24) {
|
||||
for (i = 0; i < length; i++) {
|
||||
switch (str[i]) {
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6':
|
||||
case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd':
|
||||
case 'e': case 'f':
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_OID_H
|
||||
#define BSON_OID_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "bson-context.h"
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
#include "bson-endian.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
int bson_oid_compare (const bson_oid_t *oid1,
|
||||
const bson_oid_t *oid2);
|
||||
void bson_oid_copy (const bson_oid_t *src,
|
||||
bson_oid_t *dst);
|
||||
bool bson_oid_equal (const bson_oid_t *oid1,
|
||||
const bson_oid_t *oid2);
|
||||
bool bson_oid_is_valid (const char *str,
|
||||
size_t length);
|
||||
time_t bson_oid_get_time_t (const bson_oid_t *oid);
|
||||
uint32_t bson_oid_hash (const bson_oid_t *oid);
|
||||
void bson_oid_init (bson_oid_t *oid,
|
||||
bson_context_t *context);
|
||||
void bson_oid_init_from_data (bson_oid_t *oid,
|
||||
const uint8_t *data);
|
||||
void bson_oid_init_from_string (bson_oid_t *oid,
|
||||
const char *str);
|
||||
void bson_oid_init_sequence (bson_oid_t *oid,
|
||||
bson_context_t *context);
|
||||
void bson_oid_to_string (const bson_oid_t *oid,
|
||||
char str[25]);
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_compare_unsafe:
|
||||
* @oid1: A bson_oid_t.
|
||||
* @oid2: A bson_oid_t.
|
||||
*
|
||||
* Performs a qsort() style comparison between @oid1 and @oid2.
|
||||
*
|
||||
* This function is meant to be as fast as possible and therefore performs
|
||||
* no argument validation. That is the callers responsibility.
|
||||
*
|
||||
* Returns: An integer < 0 if @oid1 is less than @oid2. Zero if they are equal.
|
||||
* An integer > 0 if @oid1 is greater than @oid2.
|
||||
*/
|
||||
static BSON_INLINE int
|
||||
bson_oid_compare_unsafe (const bson_oid_t *oid1,
|
||||
const bson_oid_t *oid2)
|
||||
{
|
||||
return memcmp (oid1, oid2, sizeof *oid1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_equal_unsafe:
|
||||
* @oid1: A bson_oid_t.
|
||||
* @oid2: A bson_oid_t.
|
||||
*
|
||||
* Checks the equality of @oid1 and @oid2.
|
||||
*
|
||||
* This function is meant to be as fast as possible and therefore performs
|
||||
* no checks for argument validity. That is the callers responsibility.
|
||||
*
|
||||
* Returns: true if @oid1 and @oid2 are equal; otherwise false.
|
||||
*/
|
||||
static BSON_INLINE bool
|
||||
bson_oid_equal_unsafe (const bson_oid_t *oid1,
|
||||
const bson_oid_t *oid2)
|
||||
{
|
||||
return !memcmp (oid1, oid2, sizeof *oid1);
|
||||
}
|
||||
|
||||
/**
|
||||
* bson_oid_hash_unsafe:
|
||||
* @oid: A bson_oid_t.
|
||||
*
|
||||
* This function performs a DJB style hash upon the bytes contained in @oid.
|
||||
* The result is a hash key suitable for use in a hashtable.
|
||||
*
|
||||
* This function is meant to be as fast as possible and therefore performs no
|
||||
* validation of arguments. The caller is responsible to ensure they are
|
||||
* passing valid arguments.
|
||||
*
|
||||
* Returns: A uint32_t containing a hash code.
|
||||
*/
|
||||
static BSON_INLINE uint32_t
|
||||
bson_oid_hash_unsafe (const bson_oid_t *oid)
|
||||
{
|
||||
uint32_t hash = 5381;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < sizeof oid->bytes; i++) {
|
||||
hash = ((hash << 5) + hash) + oid->bytes[i];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_copy_unsafe:
|
||||
* @src: A bson_oid_t to copy from.
|
||||
* @dst: A bson_oid_t to copy into.
|
||||
*
|
||||
* Copies the contents of @src into @dst. This function is meant to be as
|
||||
* fast as possible and therefore performs no argument checking. It is the
|
||||
* callers responsibility to ensure they are passing valid data into the
|
||||
* function.
|
||||
*/
|
||||
static BSON_INLINE void
|
||||
bson_oid_copy_unsafe (const bson_oid_t *src,
|
||||
bson_oid_t *dst)
|
||||
{
|
||||
memcpy (dst, src, sizeof *src);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_parse_hex_char:
|
||||
* @hex: A character to parse to its integer value.
|
||||
*
|
||||
* This function contains a jump table to return the integer value for a
|
||||
* character containing a hexidecimal value (0-9, a-f, A-F). If the character
|
||||
* is not a hexidecimal character then zero is returned.
|
||||
*
|
||||
* Returns: An integer between 0 and 15.
|
||||
*/
|
||||
static BSON_INLINE uint8_t
|
||||
bson_oid_parse_hex_char (char hex)
|
||||
{
|
||||
switch (hex) {
|
||||
case '0':
|
||||
return 0;
|
||||
case '1':
|
||||
return 1;
|
||||
case '2':
|
||||
return 2;
|
||||
case '3':
|
||||
return 3;
|
||||
case '4':
|
||||
return 4;
|
||||
case '5':
|
||||
return 5;
|
||||
case '6':
|
||||
return 6;
|
||||
case '7':
|
||||
return 7;
|
||||
case '8':
|
||||
return 8;
|
||||
case '9':
|
||||
return 9;
|
||||
case 'a':
|
||||
case 'A':
|
||||
return 0xa;
|
||||
case 'b':
|
||||
case 'B':
|
||||
return 0xb;
|
||||
case 'c':
|
||||
case 'C':
|
||||
return 0xc;
|
||||
case 'd':
|
||||
case 'D':
|
||||
return 0xd;
|
||||
case 'e':
|
||||
case 'E':
|
||||
return 0xe;
|
||||
case 'f':
|
||||
case 'F':
|
||||
return 0xf;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_init_from_string_unsafe:
|
||||
* @oid: A bson_oid_t to store the result.
|
||||
* @str: A 24-character hexidecimal encoded string.
|
||||
*
|
||||
* Parses a string containing 24 hexidecimal encoded bytes into a bson_oid_t.
|
||||
* This function is meant to be as fast as possible and inlined into your
|
||||
* code. For that purpose, the function does not perform any sort of bounds
|
||||
* checking and it is the callers responsibility to ensure they are passing
|
||||
* valid input to the function.
|
||||
*/
|
||||
static BSON_INLINE void
|
||||
bson_oid_init_from_string_unsafe (bson_oid_t *oid,
|
||||
const char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 12; i++) {
|
||||
oid->bytes[i] = ((bson_oid_parse_hex_char (str[2 * i]) << 4) |
|
||||
(bson_oid_parse_hex_char (str[2 * i + 1])));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_get_time_t_unsafe:
|
||||
* @oid: A bson_oid_t.
|
||||
*
|
||||
* Fetches the time @oid was generated.
|
||||
*
|
||||
* Returns: A time_t containing the UNIX timestamp of generation.
|
||||
*/
|
||||
static BSON_INLINE time_t
|
||||
bson_oid_get_time_t_unsafe (const bson_oid_t *oid)
|
||||
{
|
||||
uint32_t t;
|
||||
|
||||
memcpy (&t, oid, sizeof (t));
|
||||
return BSON_UINT32_FROM_BE (t);
|
||||
}
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_OID_H */
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_PRIVATE_H
|
||||
#define BSON_PRIVATE_H
|
||||
|
||||
|
||||
#include "bson-macros.h"
|
||||
#include "bson-memory.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BSON_FLAG_NONE = 0,
|
||||
BSON_FLAG_INLINE = (1 << 0),
|
||||
BSON_FLAG_STATIC = (1 << 1),
|
||||
BSON_FLAG_RDONLY = (1 << 2),
|
||||
BSON_FLAG_CHILD = (1 << 3),
|
||||
BSON_FLAG_IN_CHILD = (1 << 4),
|
||||
BSON_FLAG_NO_FREE = (1 << 5),
|
||||
} bson_flags_t;
|
||||
|
||||
|
||||
BSON_ALIGNED_BEGIN (128)
|
||||
typedef struct
|
||||
{
|
||||
bson_flags_t flags;
|
||||
uint32_t len;
|
||||
uint8_t data [120];
|
||||
} bson_impl_inline_t
|
||||
BSON_ALIGNED_END (128);
|
||||
|
||||
|
||||
BSON_STATIC_ASSERT (sizeof (bson_impl_inline_t) == 128);
|
||||
|
||||
|
||||
BSON_ALIGNED_BEGIN (128)
|
||||
typedef struct
|
||||
{
|
||||
bson_flags_t flags; /* flags describing the bson_t */
|
||||
uint32_t len; /* length of bson document in bytes */
|
||||
bson_t *parent; /* parent bson if a child */
|
||||
uint32_t depth; /* Subdocument depth. */
|
||||
uint8_t **buf; /* pointer to buffer pointer */
|
||||
size_t *buflen; /* pointer to buffer length */
|
||||
size_t offset; /* our offset inside *buf */
|
||||
uint8_t *alloc; /* buffer that we own. */
|
||||
size_t alloclen; /* length of buffer that we own. */
|
||||
bson_realloc_func realloc; /* our realloc implementation */
|
||||
void *realloc_func_ctx; /* context for our realloc func */
|
||||
} bson_impl_alloc_t
|
||||
BSON_ALIGNED_END (128);
|
||||
|
||||
|
||||
BSON_STATIC_ASSERT (sizeof (bson_impl_alloc_t) <= 128);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_PRIVATE_H */
|
||||
@@ -0,0 +1,814 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bson.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef BSON_OS_WIN32
|
||||
# include <io.h>
|
||||
# include <share.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "bson-reader.h"
|
||||
#include "bson-memory.h"
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BSON_READER_HANDLE = 1,
|
||||
BSON_READER_DATA = 2,
|
||||
} bson_reader_type_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bson_reader_type_t type;
|
||||
void *handle;
|
||||
bool done : 1;
|
||||
bool failed : 1;
|
||||
size_t end;
|
||||
size_t len;
|
||||
size_t offset;
|
||||
size_t bytes_read;
|
||||
bson_t inline_bson;
|
||||
uint8_t *data;
|
||||
bson_reader_read_func_t read_func;
|
||||
bson_reader_destroy_func_t destroy_func;
|
||||
} bson_reader_handle_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fd;
|
||||
bool do_close;
|
||||
} bson_reader_handle_fd_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bson_reader_type_t type;
|
||||
const uint8_t *data;
|
||||
size_t length;
|
||||
size_t offset;
|
||||
bson_t inline_bson;
|
||||
} bson_reader_data_t;
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_reader_handle_fill_buffer --
|
||||
*
|
||||
* Attempt to read as much as possible until the underlying buffer
|
||||
* in @reader is filled or we have reached end-of-stream or
|
||||
* read failure.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_reader_handle_fill_buffer (bson_reader_handle_t *reader) /* IN */
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
/*
|
||||
* Handle first read specially.
|
||||
*/
|
||||
if ((!reader->done) && (!reader->offset) && (!reader->end)) {
|
||||
ret = reader->read_func (reader->handle, &reader->data[0], reader->len);
|
||||
|
||||
if (ret <= 0) {
|
||||
reader->done = true;
|
||||
return;
|
||||
}
|
||||
reader->bytes_read += ret;
|
||||
|
||||
reader->end = ret;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move valid data to head.
|
||||
*/
|
||||
memmove (&reader->data[0],
|
||||
&reader->data[reader->offset],
|
||||
reader->end - reader->offset);
|
||||
reader->end = reader->end - reader->offset;
|
||||
reader->offset = 0;
|
||||
|
||||
/*
|
||||
* Read in data to fill the buffer.
|
||||
*/
|
||||
ret = reader->read_func (reader->handle,
|
||||
&reader->data[reader->end],
|
||||
reader->len - reader->end);
|
||||
|
||||
if (ret <= 0) {
|
||||
reader->done = true;
|
||||
reader->failed = (ret < 0);
|
||||
} else {
|
||||
reader->bytes_read += ret;
|
||||
reader->end += ret;
|
||||
}
|
||||
|
||||
BSON_ASSERT (reader->offset == 0);
|
||||
BSON_ASSERT (reader->end <= reader->len);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_new_from_handle --
|
||||
*
|
||||
* Allocates and initializes a new bson_reader_t using the opaque
|
||||
* handle provided.
|
||||
*
|
||||
* Parameters:
|
||||
* @handle: an opaque handle to use to read data.
|
||||
* @rf: a function to perform reads on @handle.
|
||||
* @df: a function to release @handle, or NULL.
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated bson_reader_t if successful, otherwise NULL.
|
||||
* Free the successful result with bson_reader_destroy().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bson_reader_t *
|
||||
bson_reader_new_from_handle (void *handle,
|
||||
bson_reader_read_func_t rf,
|
||||
bson_reader_destroy_func_t df)
|
||||
{
|
||||
bson_reader_handle_t *real;
|
||||
|
||||
BSON_ASSERT (handle);
|
||||
BSON_ASSERT (rf);
|
||||
|
||||
real = bson_malloc0 (sizeof *real);
|
||||
real->type = BSON_READER_HANDLE;
|
||||
real->data = bson_malloc0 (1024);
|
||||
real->handle = handle;
|
||||
real->len = 1024;
|
||||
real->offset = 0;
|
||||
|
||||
bson_reader_set_read_func ((bson_reader_t *)real, rf);
|
||||
|
||||
if (df) {
|
||||
bson_reader_set_destroy_func ((bson_reader_t *)real, df);
|
||||
}
|
||||
|
||||
_bson_reader_handle_fill_buffer (real);
|
||||
|
||||
return (bson_reader_t *)real;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_reader_handle_fd_destroy --
|
||||
*
|
||||
* Cleanup allocations associated with state created in
|
||||
* bson_reader_new_from_fd().
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_reader_handle_fd_destroy (void *handle) /* IN */
|
||||
{
|
||||
bson_reader_handle_fd_t *fd = handle;
|
||||
|
||||
if (fd) {
|
||||
if ((fd->fd != -1) && fd->do_close) {
|
||||
#ifdef _WIN32
|
||||
_close (fd->fd);
|
||||
#else
|
||||
close (fd->fd);
|
||||
#endif
|
||||
}
|
||||
bson_free (fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_reader_handle_fd_read --
|
||||
*
|
||||
* Perform read on opaque handle created in
|
||||
* bson_reader_new_from_fd().
|
||||
*
|
||||
* The underlying file descriptor is read from the current position
|
||||
* using the bson_reader_handle_fd_t allocated.
|
||||
*
|
||||
* Returns:
|
||||
* -1 on failure.
|
||||
* 0 on end of stream.
|
||||
* Greater than zero on success.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static ssize_t
|
||||
_bson_reader_handle_fd_read (void *handle, /* IN */
|
||||
void *buf, /* IN */
|
||||
size_t len) /* IN */
|
||||
{
|
||||
bson_reader_handle_fd_t *fd = handle;
|
||||
ssize_t ret = -1;
|
||||
|
||||
if (fd && (fd->fd != -1)) {
|
||||
again:
|
||||
#ifdef BSON_OS_WIN32
|
||||
ret = _read (fd->fd, buf, (unsigned int)len);
|
||||
#else
|
||||
ret = read (fd->fd, buf, len);
|
||||
#endif
|
||||
if ((ret == -1) && (errno == EAGAIN)) {
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_new_from_fd --
|
||||
*
|
||||
* Create a new bson_reader_t using the file-descriptor provided.
|
||||
*
|
||||
* Parameters:
|
||||
* @fd: a libc style file-descriptor.
|
||||
* @close_on_destroy: if close() should be called on @fd when
|
||||
* bson_reader_destroy() is called.
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated bson_reader_t on success; otherwise NULL.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bson_reader_t *
|
||||
bson_reader_new_from_fd (int fd, /* IN */
|
||||
bool close_on_destroy) /* IN */
|
||||
{
|
||||
bson_reader_handle_fd_t *handle;
|
||||
|
||||
BSON_ASSERT (fd != -1);
|
||||
|
||||
handle = bson_malloc0 (sizeof *handle);
|
||||
handle->fd = fd;
|
||||
handle->do_close = close_on_destroy;
|
||||
|
||||
return bson_reader_new_from_handle (handle,
|
||||
_bson_reader_handle_fd_read,
|
||||
_bson_reader_handle_fd_destroy);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_reader_set_read_func:
|
||||
* @reader: A bson_reader_t.
|
||||
*
|
||||
* Note that @reader must be initialized by bson_reader_init_from_handle(), or data
|
||||
* will be destroyed.
|
||||
*/
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_set_read_func --
|
||||
*
|
||||
* Set the read func to be provided for @reader.
|
||||
*
|
||||
* You probably want to use bson_reader_new_from_handle() or
|
||||
* bson_reader_new_from_fd() instead.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_reader_set_read_func (bson_reader_t *reader, /* IN */
|
||||
bson_reader_read_func_t func) /* IN */
|
||||
{
|
||||
bson_reader_handle_t *real = (bson_reader_handle_t *)reader;
|
||||
|
||||
BSON_ASSERT (reader->type == BSON_READER_HANDLE);
|
||||
|
||||
real->read_func = func;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_set_destroy_func --
|
||||
*
|
||||
* Set the function to cleanup state when @reader is destroyed.
|
||||
*
|
||||
* You probably want bson_reader_new_from_fd() or
|
||||
* bson_reader_new_from_handle() instead.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_reader_set_destroy_func (bson_reader_t *reader, /* IN */
|
||||
bson_reader_destroy_func_t func) /* IN */
|
||||
{
|
||||
bson_reader_handle_t *real = (bson_reader_handle_t *)reader;
|
||||
|
||||
BSON_ASSERT (reader->type == BSON_READER_HANDLE);
|
||||
|
||||
real->destroy_func = func;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_reader_handle_grow_buffer --
|
||||
*
|
||||
* Grow the buffer to the next power of two.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
_bson_reader_handle_grow_buffer (bson_reader_handle_t *reader) /* IN */
|
||||
{
|
||||
size_t size;
|
||||
|
||||
size = reader->len * 2;
|
||||
reader->data = bson_realloc (reader->data, size);
|
||||
reader->len = size;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_reader_handle_tell --
|
||||
*
|
||||
* Tell the current position within the underlying file-descriptor.
|
||||
*
|
||||
* Returns:
|
||||
* An off_t containing the current offset.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static off_t
|
||||
_bson_reader_handle_tell (bson_reader_handle_t *reader) /* IN */
|
||||
{
|
||||
off_t off;
|
||||
|
||||
off = (off_t)reader->bytes_read;
|
||||
off -= (off_t)reader->end;
|
||||
off += (off_t)reader->offset;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_reader_handle_read --
|
||||
*
|
||||
* Read the next chunk of data from the underlying file descriptor
|
||||
* and return a bson_t which should not be modified.
|
||||
*
|
||||
* There was a failure if NULL is returned and @reached_eof is
|
||||
* not set to true.
|
||||
*
|
||||
* Returns:
|
||||
* NULL on failure or end of stream.
|
||||
*
|
||||
* Side effects:
|
||||
* @reached_eof is set if non-NULL.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static const bson_t *
|
||||
_bson_reader_handle_read (bson_reader_handle_t *reader, /* IN */
|
||||
bool *reached_eof) /* IN */
|
||||
{
|
||||
int32_t blen;
|
||||
|
||||
if (reached_eof) {
|
||||
*reached_eof = false;
|
||||
}
|
||||
|
||||
while (!reader->done) {
|
||||
if ((reader->end - reader->offset) < 4) {
|
||||
_bson_reader_handle_fill_buffer (reader);
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy (&blen, &reader->data[reader->offset], sizeof blen);
|
||||
blen = BSON_UINT32_FROM_LE (blen);
|
||||
|
||||
if (blen < 5) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (blen > (int32_t)(reader->end - reader->offset)) {
|
||||
if (blen > (int32_t)reader->len) {
|
||||
_bson_reader_handle_grow_buffer (reader);
|
||||
}
|
||||
|
||||
_bson_reader_handle_fill_buffer (reader);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!bson_init_static (&reader->inline_bson,
|
||||
&reader->data[reader->offset],
|
||||
(uint32_t)blen)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reader->offset += blen;
|
||||
|
||||
return &reader->inline_bson;
|
||||
}
|
||||
|
||||
if (reached_eof) {
|
||||
*reached_eof = reader->done && !reader->failed;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_new_from_data --
|
||||
*
|
||||
* Allocates and initializes a new bson_reader_t that will the memory
|
||||
* provided as a stream of BSON documents.
|
||||
*
|
||||
* Parameters:
|
||||
* @data: A buffer to read BSON documents from.
|
||||
* @length: The length of @data.
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated bson_reader_t that should be freed with
|
||||
* bson_reader_destroy().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bson_reader_t *
|
||||
bson_reader_new_from_data (const uint8_t *data, /* IN */
|
||||
size_t length) /* IN */
|
||||
{
|
||||
bson_reader_data_t *real;
|
||||
|
||||
BSON_ASSERT (data);
|
||||
|
||||
real = (bson_reader_data_t*)bson_malloc0 (sizeof *real);
|
||||
real->type = BSON_READER_DATA;
|
||||
real->data = data;
|
||||
real->length = length;
|
||||
real->offset = 0;
|
||||
|
||||
return (bson_reader_t *)real;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_reader_data_read --
|
||||
*
|
||||
* Read the next document from the underlying buffer.
|
||||
*
|
||||
* Returns:
|
||||
* NULL on failure or end of stream.
|
||||
* a bson_t which should not be modified.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static const bson_t *
|
||||
_bson_reader_data_read (bson_reader_data_t *reader, /* IN */
|
||||
bool *reached_eof) /* IN */
|
||||
{
|
||||
int32_t blen;
|
||||
|
||||
if (reached_eof) {
|
||||
*reached_eof = false;
|
||||
}
|
||||
|
||||
if ((reader->offset + 4) < reader->length) {
|
||||
memcpy (&blen, &reader->data[reader->offset], sizeof blen);
|
||||
blen = BSON_UINT32_FROM_LE (blen);
|
||||
|
||||
if (blen < 5) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (blen > (int32_t)(reader->length - reader->offset)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!bson_init_static (&reader->inline_bson,
|
||||
&reader->data[reader->offset], (uint32_t)blen)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reader->offset += blen;
|
||||
|
||||
return &reader->inline_bson;
|
||||
}
|
||||
|
||||
if (reached_eof) {
|
||||
*reached_eof = (reader->offset == reader->length);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_reader_data_tell --
|
||||
*
|
||||
* Tell the current position in the underlying buffer.
|
||||
*
|
||||
* Returns:
|
||||
* An off_t of the current offset.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static off_t
|
||||
_bson_reader_data_tell (bson_reader_data_t *reader) /* IN */
|
||||
{
|
||||
return (off_t)reader->offset;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_destroy --
|
||||
*
|
||||
* Release a bson_reader_t created with bson_reader_new_from_data(),
|
||||
* bson_reader_new_from_fd(), or bson_reader_new_from_handle().
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_reader_destroy (bson_reader_t *reader) /* IN */
|
||||
{
|
||||
BSON_ASSERT (reader);
|
||||
|
||||
switch (reader->type) {
|
||||
case 0:
|
||||
break;
|
||||
case BSON_READER_HANDLE:
|
||||
{
|
||||
bson_reader_handle_t *handle = (bson_reader_handle_t *)reader;
|
||||
|
||||
if (handle->destroy_func) {
|
||||
|
||||
handle->destroy_func(handle->handle);
|
||||
}
|
||||
|
||||
bson_free (handle->data);
|
||||
}
|
||||
break;
|
||||
case BSON_READER_DATA:
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "No such reader type: %02x\n", reader->type);
|
||||
break;
|
||||
}
|
||||
|
||||
reader->type = 0;
|
||||
|
||||
bson_free (reader);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_read --
|
||||
*
|
||||
* Reads the next bson_t in the underlying memory or storage. The
|
||||
* resulting bson_t should not be modified or freed. You may copy it
|
||||
* and iterate over it. Functions that take a const bson_t* are safe
|
||||
* to use.
|
||||
*
|
||||
* This structure does not survive calls to bson_reader_read() or
|
||||
* bson_reader_destroy() as it uses memory allocated by the reader or
|
||||
* underlying storage/memory.
|
||||
*
|
||||
* If NULL is returned then @reached_eof will be set to true if the
|
||||
* end of the file or buffer was reached. This indicates if there was
|
||||
* an error parsing the document stream.
|
||||
*
|
||||
* Returns:
|
||||
* A const bson_t that should not be modified or freed.
|
||||
* NULL on failure or end of stream.
|
||||
*
|
||||
* Side effects:
|
||||
* @reached_eof is set if non-NULL.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const bson_t *
|
||||
bson_reader_read (bson_reader_t *reader, /* IN */
|
||||
bool *reached_eof) /* OUT */
|
||||
{
|
||||
BSON_ASSERT (reader);
|
||||
|
||||
switch (reader->type) {
|
||||
case BSON_READER_HANDLE:
|
||||
return _bson_reader_handle_read ((bson_reader_handle_t *)reader, reached_eof);
|
||||
|
||||
case BSON_READER_DATA:
|
||||
return _bson_reader_data_read ((bson_reader_data_t *)reader, reached_eof);
|
||||
|
||||
default:
|
||||
fprintf (stderr, "No such reader type: %02x\n", reader->type);
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_tell --
|
||||
*
|
||||
* Return the current position in the underlying reader. This will
|
||||
* always be at the beginning of a bson document or end of file.
|
||||
*
|
||||
* Returns:
|
||||
* An off_t containing the current offset.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
off_t
|
||||
bson_reader_tell (bson_reader_t *reader) /* IN */
|
||||
{
|
||||
BSON_ASSERT (reader);
|
||||
|
||||
switch (reader->type) {
|
||||
case BSON_READER_HANDLE:
|
||||
return _bson_reader_handle_tell ((bson_reader_handle_t *)reader);
|
||||
|
||||
case BSON_READER_DATA:
|
||||
return _bson_reader_data_tell ((bson_reader_data_t *)reader);
|
||||
|
||||
default:
|
||||
fprintf (stderr, "No such reader type: %02x\n", reader->type);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_new_from_file --
|
||||
*
|
||||
* A convenience function to open a file containing sequential
|
||||
* bson documents and read them using bson_reader_t.
|
||||
*
|
||||
* Returns:
|
||||
* A new bson_reader_t if successful, otherwise NULL and
|
||||
* @error is set. Free the non-NULL result with
|
||||
* bson_reader_destroy().
|
||||
*
|
||||
* Side effects:
|
||||
* @error may be set.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bson_reader_t *
|
||||
bson_reader_new_from_file (const char *path, /* IN */
|
||||
bson_error_t *error) /* OUT */
|
||||
{
|
||||
char errmsg_buf[BSON_ERROR_BUFFER_SIZE];
|
||||
char *errmsg;
|
||||
int fd;
|
||||
|
||||
BSON_ASSERT (path);
|
||||
|
||||
#ifdef BSON_OS_WIN32
|
||||
if (_sopen_s (&fd, path, (_O_RDONLY | _O_BINARY), _SH_DENYNO, 0) != 0) {
|
||||
fd = -1;
|
||||
}
|
||||
#else
|
||||
fd = open (path, O_RDONLY);
|
||||
#endif
|
||||
|
||||
if (fd == -1) {
|
||||
errmsg = bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf);
|
||||
bson_set_error (error,
|
||||
BSON_ERROR_READER,
|
||||
BSON_ERROR_READER_BADFD,
|
||||
"%s", errmsg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bson_reader_new_from_fd (fd, true);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_READER_H
|
||||
#define BSON_READER_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-oid.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#define BSON_ERROR_READER_BADFD 1
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_read_func_t --
|
||||
*
|
||||
* This function is a callback used by bson_reader_t to read the
|
||||
* next chunk of data from the underlying opaque file descriptor.
|
||||
*
|
||||
* This function is meant to operate similar to the read() function
|
||||
* as part of libc on UNIX-like systems.
|
||||
*
|
||||
* Parameters:
|
||||
* @handle: The handle to read from.
|
||||
* @buf: The buffer to read into.
|
||||
* @count: The number of bytes to read.
|
||||
*
|
||||
* Returns:
|
||||
* 0 for end of stream.
|
||||
* -1 for read failure.
|
||||
* Greater than zero for number of bytes read into @buf.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef ssize_t (*bson_reader_read_func_t) (void *handle, /* IN */
|
||||
void *buf, /* IN */
|
||||
size_t count); /* IN */
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_reader_destroy_func_t --
|
||||
*
|
||||
* Destroy callback to release any resources associated with the
|
||||
* opaque handle.
|
||||
*
|
||||
* Parameters:
|
||||
* @handle: the handle provided to bson_reader_new_from_handle().
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef void (*bson_reader_destroy_func_t) (void *handle); /* IN */
|
||||
|
||||
|
||||
bson_reader_t *bson_reader_new_from_handle (void *handle,
|
||||
bson_reader_read_func_t rf,
|
||||
bson_reader_destroy_func_t df);
|
||||
bson_reader_t *bson_reader_new_from_fd (int fd,
|
||||
bool close_on_destroy);
|
||||
bson_reader_t *bson_reader_new_from_file (const char *path,
|
||||
bson_error_t *error);
|
||||
bson_reader_t *bson_reader_new_from_data (const uint8_t *data,
|
||||
size_t length);
|
||||
void bson_reader_destroy (bson_reader_t *reader);
|
||||
void bson_reader_set_read_func (bson_reader_t *reader,
|
||||
bson_reader_read_func_t func);
|
||||
void bson_reader_set_destroy_func (bson_reader_t *reader,
|
||||
bson_reader_destroy_func_t func);
|
||||
const bson_t *bson_reader_read (bson_reader_t *reader,
|
||||
bool *reached_eof);
|
||||
off_t bson_reader_tell (bson_reader_t *reader);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_READER_H */
|
||||
@@ -0,0 +1,259 @@
|
||||
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
//
|
||||
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||
//
|
||||
// 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 product 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 AUTHOR ``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 AUTHOR 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.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _MSC_VER // [
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif // _MSC_VER ]
|
||||
|
||||
#ifndef _MSC_STDINT_H_ // [
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if _MSC_VER >= 1600 // [
|
||||
#include <stdint.h>
|
||||
#else // ] _MSC_VER >= 1600 [
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// 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++" {}'
|
||||
// or compiler give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
// 7.18.1 Integer types
|
||||
|
||||
// 7.18.1.1 Exact-width integer types
|
||||
|
||||
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
// realize that, e.g. char has the same size as __int8
|
||||
// so we give up on __intX for them.
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
|
||||
// 7.18.1.2 Minimum-width integer types
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
// 7.18.1.3 Fastest minimum-width integer types
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
// 7.18.1.4 Integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else // _WIN64 ][
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.1.5 Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
|
||||
// 7.18.2 Limits of specified-width integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||
|
||||
// 7.18.2.1 Limits of exact-width integer types
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
// 7.18.2.2 Limits of minimum-width integer types
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||
#ifdef _WIN64 // [
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
// 7.18.2.5 Limits of greatest-width integer types
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
// 7.18.3 Limits of other integer types
|
||||
|
||||
#ifdef _WIN64 // [
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else // _WIN64 ][
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif // _WIN64 ]
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX // [
|
||||
# ifdef _WIN64 // [
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else // _WIN64 ][
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif // _WIN64 ]
|
||||
#endif // SIZE_MAX ]
|
||||
|
||||
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||
#ifndef WCHAR_MIN // [
|
||||
# define WCHAR_MIN 0
|
||||
#endif // WCHAR_MIN ]
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif // WCHAR_MAX ]
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif // __STDC_LIMIT_MACROS ]
|
||||
|
||||
|
||||
// 7.18.4 Limits of other integer types
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||
|
||||
// 7.18.4.1 Macros for minimum-width integer constants
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
// 7.18.4.2 Macros for greatest-width integer constants
|
||||
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||
// Check out Issue 9 for the details.
|
||||
#ifndef INTMAX_C // [
|
||||
# define INTMAX_C INT64_C
|
||||
#endif // INTMAX_C ]
|
||||
#ifndef UINTMAX_C // [
|
||||
# define UINTMAX_C UINT64_C
|
||||
#endif // UINTMAX_C ]
|
||||
|
||||
#endif // __STDC_CONSTANT_MACROS ]
|
||||
|
||||
#endif // _MSC_VER >= 1600 ]
|
||||
|
||||
#endif // _MSC_STDINT_H_ ]
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef _SRC_BSON_BSON_STDINT_H
|
||||
#define _SRC_BSON_BSON_STDINT_H 1
|
||||
#ifndef _GENERATED_STDINT_H
|
||||
#define _GENERATED_STDINT_H " "
|
||||
/* generated using a gnu compiler version gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 Copyright (C) 2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* system headers have good uint64_t */
|
||||
#ifndef _HAVE_UINT64_T
|
||||
#define _HAVE_UINT64_T
|
||||
#endif
|
||||
|
||||
/* once */
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,771 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-config.h"
|
||||
#include "bson-string.h"
|
||||
#include "bson-memory.h"
|
||||
#include "bson-utf8.h"
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_string_new --
|
||||
*
|
||||
* Create a new bson_string_t.
|
||||
*
|
||||
* bson_string_t is a power-of-2 allocation growing string. Every
|
||||
* time data is appended the next power of two size is chosen for
|
||||
* the allocation. Pretty standard stuff.
|
||||
*
|
||||
* It is UTF-8 aware through the use of bson_string_append_unichar().
|
||||
* The proper UTF-8 character sequence will be used.
|
||||
*
|
||||
* Parameters:
|
||||
* @str: a string to copy or NULL.
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated bson_string_t that should be freed with
|
||||
* bson_string_free().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bson_string_t *
|
||||
bson_string_new (const char *str) /* IN */
|
||||
{
|
||||
bson_string_t *ret;
|
||||
|
||||
ret = bson_malloc0 (sizeof *ret);
|
||||
ret->len = str ? (int)strlen (str) : 0;
|
||||
ret->alloc = ret->len + 1;
|
||||
|
||||
if (!bson_is_power_of_two (ret->alloc)) {
|
||||
ret->alloc = (uint32_t)bson_next_power_of_two ((size_t)ret->alloc);
|
||||
}
|
||||
|
||||
BSON_ASSERT (ret->alloc >= 1);
|
||||
|
||||
ret->str = bson_malloc (ret->alloc);
|
||||
|
||||
if (str) {
|
||||
memcpy (ret->str, str, ret->len);
|
||||
}
|
||||
ret->str [ret->len] = '\0';
|
||||
|
||||
ret->str [ret->len] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_string_free --
|
||||
*
|
||||
* Free the bson_string_t @string and related allocations.
|
||||
*
|
||||
* If @free_segment is false, then the strings buffer will be
|
||||
* returned and is not freed. Otherwise, NULL is returned.
|
||||
*
|
||||
* Returns:
|
||||
* The string->str if free_segment is false.
|
||||
* Otherwise NULL.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
bson_string_free (bson_string_t *string, /* IN */
|
||||
bool free_segment) /* IN */
|
||||
{
|
||||
char *ret = NULL;
|
||||
|
||||
BSON_ASSERT (string);
|
||||
|
||||
if (!free_segment) {
|
||||
ret = string->str;
|
||||
} else {
|
||||
bson_free (string->str);
|
||||
}
|
||||
|
||||
bson_free (string);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_string_append --
|
||||
*
|
||||
* Append the UTF-8 string @str to @string.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_string_append (bson_string_t *string, /* IN */
|
||||
const char *str) /* IN */
|
||||
{
|
||||
uint32_t len;
|
||||
|
||||
BSON_ASSERT (string);
|
||||
BSON_ASSERT (str);
|
||||
|
||||
len = (uint32_t)strlen (str);
|
||||
|
||||
if ((string->alloc - string->len - 1) < len) {
|
||||
string->alloc += len;
|
||||
if (!bson_is_power_of_two (string->alloc)) {
|
||||
string->alloc = (uint32_t)bson_next_power_of_two ((size_t)string->alloc);
|
||||
}
|
||||
string->str = bson_realloc (string->str, string->alloc);
|
||||
}
|
||||
|
||||
memcpy (string->str + string->len, str, len);
|
||||
string->len += len;
|
||||
string->str [string->len] = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_string_append_c --
|
||||
*
|
||||
* Append the ASCII character @c to @string.
|
||||
*
|
||||
* Do not use this if you are working with UTF-8 sequences,
|
||||
* use bson_string_append_unichar().
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_string_append_c (bson_string_t *string, /* IN */
|
||||
char c) /* IN */
|
||||
{
|
||||
char cc[2];
|
||||
|
||||
BSON_ASSERT (string);
|
||||
|
||||
if (BSON_UNLIKELY (string->alloc == (string->len + 1))) {
|
||||
cc [0] = c;
|
||||
cc [1] = '\0';
|
||||
bson_string_append (string, cc);
|
||||
return;
|
||||
}
|
||||
|
||||
string->str [string->len++] = c;
|
||||
string->str [string->len] = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_string_append_unichar --
|
||||
*
|
||||
* Append the bson_unichar_t @unichar to the string @string.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_string_append_unichar (bson_string_t *string, /* IN */
|
||||
bson_unichar_t unichar) /* IN */
|
||||
{
|
||||
uint32_t len;
|
||||
char str [8];
|
||||
|
||||
BSON_ASSERT (string);
|
||||
BSON_ASSERT (unichar);
|
||||
|
||||
bson_utf8_from_unichar (unichar, str, &len);
|
||||
|
||||
if (len <= 6) {
|
||||
str [len] = '\0';
|
||||
bson_string_append (string, str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_string_append_printf --
|
||||
*
|
||||
* Format a string according to @format and append it to @string.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_string_append_printf (bson_string_t *string,
|
||||
const char *format,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
char *ret;
|
||||
|
||||
BSON_ASSERT (string);
|
||||
BSON_ASSERT (format);
|
||||
|
||||
va_start (args, format);
|
||||
ret = bson_strdupv_printf (format, args);
|
||||
va_end (args);
|
||||
bson_string_append (string, ret);
|
||||
bson_free (ret);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_string_truncate --
|
||||
*
|
||||
* Truncate the string @string to @len bytes.
|
||||
*
|
||||
* The underlying memory will be released via realloc() down to
|
||||
* the minimum required size specified by @len.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_string_truncate (bson_string_t *string, /* IN */
|
||||
uint32_t len) /* IN */
|
||||
{
|
||||
uint32_t alloc;
|
||||
|
||||
BSON_ASSERT (string);
|
||||
BSON_ASSERT (len < INT_MAX);
|
||||
|
||||
alloc = len + 1;
|
||||
|
||||
if (alloc < 16) {
|
||||
alloc = 16;
|
||||
}
|
||||
|
||||
if (!bson_is_power_of_two (alloc)) {
|
||||
alloc = (uint32_t)bson_next_power_of_two ((size_t)alloc);
|
||||
}
|
||||
|
||||
string->str = bson_realloc (string->str, alloc);
|
||||
string->alloc = alloc;
|
||||
string->len = len;
|
||||
|
||||
string->str [string->len] = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_strdup --
|
||||
*
|
||||
* Portable strdup().
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated string that should be freed with bson_free().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
bson_strdup (const char *str) /* IN */
|
||||
{
|
||||
long len;
|
||||
char *out;
|
||||
|
||||
if (!str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = (long)strlen (str);
|
||||
out = bson_malloc (len + 1);
|
||||
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy (out, str, len + 1);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_strdupv_printf --
|
||||
*
|
||||
* Like bson_strdup_printf() but takes a va_list.
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated string that should be freed with bson_free().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
bson_strdupv_printf (const char *format, /* IN */
|
||||
va_list args) /* IN */
|
||||
{
|
||||
va_list my_args;
|
||||
char *buf;
|
||||
int len = 32;
|
||||
int n;
|
||||
|
||||
BSON_ASSERT (format);
|
||||
|
||||
buf = bson_malloc0 (len);
|
||||
|
||||
while (true) {
|
||||
va_copy (my_args, args);
|
||||
n = bson_vsnprintf (buf, len, format, my_args);
|
||||
va_end (my_args);
|
||||
|
||||
if (n > -1 && n < len) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (n > -1) {
|
||||
len = n + 1;
|
||||
} else {
|
||||
len *= 2;
|
||||
}
|
||||
|
||||
buf = bson_realloc (buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_strdup_printf --
|
||||
*
|
||||
* Convenience function that formats a string according to @format
|
||||
* and returns a copy of it.
|
||||
*
|
||||
* Returns:
|
||||
* A newly created string that should be freed with bson_free().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
bson_strdup_printf (const char *format, /* IN */
|
||||
...) /* IN */
|
||||
{
|
||||
va_list args;
|
||||
char *ret;
|
||||
|
||||
BSON_ASSERT (format);
|
||||
|
||||
va_start (args, format);
|
||||
ret = bson_strdupv_printf (format, args);
|
||||
va_end (args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_strndup --
|
||||
*
|
||||
* A portable strndup().
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated string that should be freed with bson_free().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
bson_strndup (const char *str, /* IN */
|
||||
size_t n_bytes) /* IN */
|
||||
{
|
||||
char *ret;
|
||||
|
||||
BSON_ASSERT (str);
|
||||
|
||||
ret = bson_malloc (n_bytes + 1);
|
||||
memcpy (ret, str, n_bytes);
|
||||
ret[n_bytes] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_strfreev --
|
||||
*
|
||||
* Frees each string in a NULL terminated array of strings.
|
||||
* This also frees the underlying array.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_strfreev (char **str) /* IN */
|
||||
{
|
||||
int i;
|
||||
|
||||
if (str) {
|
||||
for (i = 0; str [i]; i++)
|
||||
bson_free (str [i]);
|
||||
bson_free (str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_strnlen --
|
||||
*
|
||||
* A portable strnlen().
|
||||
*
|
||||
* Returns:
|
||||
* The length of @s up to @maxlen.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
size_t
|
||||
bson_strnlen (const char *s, /* IN */
|
||||
size_t maxlen) /* IN */
|
||||
{
|
||||
#ifdef BSON_HAVE_STRNLEN
|
||||
return strnlen (s, maxlen);
|
||||
#else
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < maxlen; i++) {
|
||||
if (s [i] == '\0') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return maxlen;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_strncpy --
|
||||
*
|
||||
* A portable strncpy.
|
||||
*
|
||||
* Copies @src into @dst, which must be @size bytes or larger.
|
||||
* The result is guaranteed to be \0 terminated.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_strncpy (char *dst, /* IN */
|
||||
const char *src, /* IN */
|
||||
size_t size) /* IN */
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
strncpy_s (dst, size, src, _TRUNCATE);
|
||||
#else
|
||||
strncpy (dst, src, size);
|
||||
dst[size - 1] = '\0';
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_vsnprintf --
|
||||
*
|
||||
* A portable vsnprintf.
|
||||
*
|
||||
* If more than @size bytes are required (exluding the null byte),
|
||||
* then @size bytes will be written to @string and the return value
|
||||
* is the number of bytes required.
|
||||
*
|
||||
* This function will always return a NULL terminated string.
|
||||
*
|
||||
* Returns:
|
||||
* The number of bytes required for @format excluding the null byte.
|
||||
*
|
||||
* Side effects:
|
||||
* @str is initialized with the formatted string.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
bson_vsnprintf (char *str, /* IN */
|
||||
size_t size, /* IN */
|
||||
const char *format, /* IN */
|
||||
va_list ap) /* IN */
|
||||
{
|
||||
#ifdef BSON_OS_WIN32
|
||||
int r = -1;
|
||||
|
||||
BSON_ASSERT (str);
|
||||
|
||||
if (size != 0) {
|
||||
r = _vsnprintf_s (str, size, _TRUNCATE, format, ap);
|
||||
}
|
||||
|
||||
if (r == -1) {
|
||||
r = _vscprintf (format, ap);
|
||||
}
|
||||
|
||||
str [size - 1] = '\0';
|
||||
|
||||
return r;
|
||||
#else
|
||||
int r;
|
||||
|
||||
r = vsnprintf (str, size, format, ap);
|
||||
str [size - 1] = '\0';
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_snprintf --
|
||||
*
|
||||
* A portable snprintf.
|
||||
*
|
||||
* If @format requires more than @size bytes, then @size bytes are
|
||||
* written and the result is the number of bytes required (excluding
|
||||
* the null byte).
|
||||
*
|
||||
* This function will always return a NULL terminated string.
|
||||
*
|
||||
* Returns:
|
||||
* The number of bytes required for @format.
|
||||
*
|
||||
* Side effects:
|
||||
* @str is initialized.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
bson_snprintf (char *str, /* IN */
|
||||
size_t size, /* IN */
|
||||
const char *format, /* IN */
|
||||
...)
|
||||
{
|
||||
int r;
|
||||
va_list ap;
|
||||
|
||||
BSON_ASSERT (str);
|
||||
|
||||
va_start (ap, format);
|
||||
r = bson_vsnprintf (str, size, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int64_t
|
||||
bson_ascii_strtoll (const char *s,
|
||||
char **e,
|
||||
int base)
|
||||
{
|
||||
char *tok = (char *)s;
|
||||
char c;
|
||||
int64_t number = 0;
|
||||
int64_t sign = 1;
|
||||
|
||||
if (!s) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
c = *tok;
|
||||
|
||||
while (isspace (c)) {
|
||||
c = *++tok;
|
||||
}
|
||||
|
||||
if (!isdigit (c) && (c != '+') && (c != '-')) {
|
||||
*e = tok - 1;
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c == '-') {
|
||||
sign = -1;
|
||||
c = *++tok;
|
||||
}
|
||||
|
||||
if (c == '+') {
|
||||
c = *++tok;
|
||||
}
|
||||
|
||||
if (c == '0' && tok[1] != '\0') {
|
||||
/* Hex, octal or binary -- maybe. */
|
||||
|
||||
c = *++tok;
|
||||
|
||||
if (c == 'x' || c == 'X') { /* Hex */
|
||||
if (base != 16) {
|
||||
*e = (char *)(s);
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
c = *++tok;
|
||||
if (!isxdigit (c)) {
|
||||
*e = tok;
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
number = (number << 4) + (c - '0');
|
||||
c = *(++tok);
|
||||
} while (isxdigit (c));
|
||||
}
|
||||
else { /* Octal */
|
||||
if (base != 8) {
|
||||
*e = (char *)(s);
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c < '0' || c >= '8') {
|
||||
*e = tok;
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
number = (number << 3) + (c - '0');
|
||||
c = *(++tok);
|
||||
} while (('0' <= c) && (c < '8'));
|
||||
}
|
||||
|
||||
while (c == 'l' || c == 'L' || c == 'u' || c == 'U') {
|
||||
c = *++tok;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Decimal */
|
||||
if (base != 10) {
|
||||
*e = (char *)(s);
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
number = (number * 10) + (c - '0');
|
||||
c = *(++tok);
|
||||
} while (isdigit (c));
|
||||
|
||||
while (c == 'l' || c == 'L' || c == 'u' || c == 'U') {
|
||||
c = *(++tok);
|
||||
}
|
||||
}
|
||||
|
||||
*e = tok;
|
||||
errno = 0;
|
||||
return (sign * number);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_STRING_H
|
||||
#define BSON_STRING_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *str;
|
||||
uint32_t len;
|
||||
uint32_t alloc;
|
||||
} bson_string_t;
|
||||
|
||||
|
||||
bson_string_t *bson_string_new (const char *str);
|
||||
char *bson_string_free (bson_string_t *string,
|
||||
bool free_segment);
|
||||
void bson_string_append (bson_string_t *string,
|
||||
const char *str);
|
||||
void bson_string_append_c (bson_string_t *string,
|
||||
char str);
|
||||
void bson_string_append_unichar (bson_string_t *string,
|
||||
bson_unichar_t unichar);
|
||||
void bson_string_append_printf (bson_string_t *string,
|
||||
const char *format,
|
||||
...) BSON_GNUC_PRINTF (2, 3);
|
||||
void bson_string_truncate (bson_string_t *string,
|
||||
uint32_t len);
|
||||
char *bson_strdup (const char *str);
|
||||
char *bson_strdup_printf (const char *format,
|
||||
...) BSON_GNUC_PRINTF (1, 2);
|
||||
char *bson_strdupv_printf (const char *format,
|
||||
va_list args) BSON_GNUC_PRINTF (1, 0);
|
||||
char *bson_strndup (const char *str,
|
||||
size_t n_bytes);
|
||||
void bson_strncpy (char *dst,
|
||||
const char *src,
|
||||
size_t size);
|
||||
int bson_vsnprintf (char *str,
|
||||
size_t size,
|
||||
const char *format,
|
||||
va_list ap) BSON_GNUC_PRINTF (3, 0);
|
||||
int bson_snprintf (char *str,
|
||||
size_t size,
|
||||
const char *format,
|
||||
...) BSON_GNUC_PRINTF (3, 4);
|
||||
void bson_strfreev (char **strv);
|
||||
size_t bson_strnlen (const char *s,
|
||||
size_t maxlen);
|
||||
int64_t bson_ascii_strtoll (const char *str,
|
||||
char **endptr,
|
||||
int base);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_STRING_H */
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_THREAD_PRIVATE_H
|
||||
#define BSON_THREAD_PRIVATE_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-config.h"
|
||||
#include "bson-macros.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
#if defined(BSON_OS_UNIX)
|
||||
# include <pthread.h>
|
||||
# define bson_mutex_t pthread_mutex_t
|
||||
# define bson_mutex_init(_n) pthread_mutex_init((_n), NULL)
|
||||
# define bson_mutex_lock pthread_mutex_lock
|
||||
# define bson_mutex_unlock pthread_mutex_unlock
|
||||
# define bson_mutex_destroy pthread_mutex_destroy
|
||||
# define bson_thread_t pthread_t
|
||||
# define bson_thread_create(_t,_f,_d) pthread_create((_t), NULL, (_f), (_d))
|
||||
# define bson_thread_join(_n) pthread_join((_n), NULL)
|
||||
# define bson_once_t pthread_once_t
|
||||
# define bson_once pthread_once
|
||||
# define BSON_ONCE_FUN(n) void n(void)
|
||||
# define BSON_ONCE_RETURN return
|
||||
# ifdef BSON_PTHREAD_ONCE_INIT_NEEDS_BRACES
|
||||
# define BSON_ONCE_INIT {PTHREAD_ONCE_INIT}
|
||||
# else
|
||||
# define BSON_ONCE_INIT PTHREAD_ONCE_INIT
|
||||
# endif
|
||||
#else
|
||||
# define bson_mutex_t CRITICAL_SECTION
|
||||
# define bson_mutex_init InitializeCriticalSection
|
||||
# define bson_mutex_lock EnterCriticalSection
|
||||
# define bson_mutex_unlock LeaveCriticalSection
|
||||
# define bson_mutex_destroy DeleteCriticalSection
|
||||
# define bson_thread_t HANDLE
|
||||
# define bson_thread_create(_t,_f,_d) (!(*(_t) = CreateThread(NULL,0,(void*)_f,_d,0,NULL)))
|
||||
# define bson_thread_join(_n) WaitForSingleObject((_n), INFINITE)
|
||||
# define bson_once_t INIT_ONCE
|
||||
# define BSON_ONCE_INIT INIT_ONCE_STATIC_INIT
|
||||
# define bson_once(o, c) InitOnceExecuteOnce(o, c, NULL, NULL)
|
||||
# define BSON_ONCE_FUN(n) BOOL CALLBACK n(PINIT_ONCE _ignored_a, PVOID _ignored_b, PVOID *_ignored_c)
|
||||
# define BSON_ONCE_RETURN return true
|
||||
#endif
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_THREAD_PRIVATE_H */
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_TIMEGM_PRIVATE_H
|
||||
#define BSON_TIMEGM_PRIVATE_H
|
||||
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-macros.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
time_t
|
||||
_bson_timegm (struct tm *const tmp);
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_TIMEGM_PRIVATE_H */
|
||||
@@ -0,0 +1,813 @@
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 1996-06-05 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
/*
|
||||
** Leap second handling from Bradley White.
|
||||
** POSIX-style TZ environment variable handling from Guy Harris.
|
||||
*/
|
||||
|
||||
#include "bson-compat.h"
|
||||
#include "bson-macros.h"
|
||||
#include "bson-timegm-private.h"
|
||||
|
||||
#ifndef BSON_OS_WIN32
|
||||
|
||||
#include "errno.h"
|
||||
#include "string.h"
|
||||
#include "limits.h" /* for CHAR_BIT et al. */
|
||||
#include "time.h"
|
||||
|
||||
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
|
||||
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
|
||||
|
||||
#ifndef CHAR_BIT
|
||||
#define CHAR_BIT 8
|
||||
#endif
|
||||
|
||||
#if 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
|
||||
# define ATTRIBUTE_CONST __attribute__ ((const))
|
||||
# define ATTRIBUTE_PURE __attribute__ ((__pure__))
|
||||
# define ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
|
||||
#else
|
||||
# define ATTRIBUTE_CONST /* empty */
|
||||
# define ATTRIBUTE_PURE /* empty */
|
||||
# define ATTRIBUTE_FORMAT(spec) /* empty */
|
||||
#endif
|
||||
|
||||
#if !defined _Noreturn && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112)
|
||||
# if 2 < __GNUC__ + (8 <= __GNUC_MINOR__)
|
||||
# define _Noreturn __attribute__ ((__noreturn__))
|
||||
# else
|
||||
# define _Noreturn
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901) && !defined restrict
|
||||
# define restrict /* empty */
|
||||
#endif
|
||||
|
||||
#ifndef TYPE_BIT
|
||||
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
|
||||
#endif /* !defined TYPE_BIT */
|
||||
|
||||
#ifndef TYPE_SIGNED
|
||||
#define TYPE_SIGNED(type) (((type) -1) < 0)
|
||||
#endif /* !defined TYPE_SIGNED */
|
||||
|
||||
/* The minimum and maximum finite time values. */
|
||||
static time_t const time_t_min =
|
||||
(TYPE_SIGNED(time_t)
|
||||
? (time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1)
|
||||
: 0);
|
||||
static time_t const time_t_max =
|
||||
(TYPE_SIGNED(time_t)
|
||||
? - (~ 0 < 0) - ((time_t) -1 << (CHAR_BIT * sizeof (time_t) - 1))
|
||||
: -1);
|
||||
|
||||
|
||||
#ifndef TZ_MAX_TIMES
|
||||
#define TZ_MAX_TIMES 2000
|
||||
#endif /* !defined TZ_MAX_TIMES */
|
||||
|
||||
#ifndef TZ_MAX_TYPES
|
||||
/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */
|
||||
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
|
||||
#endif /* !defined TZ_MAX_TYPES */
|
||||
|
||||
#ifndef TZ_MAX_CHARS
|
||||
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
|
||||
/* (limited by what unsigned chars can hold) */
|
||||
#endif /* !defined TZ_MAX_CHARS */
|
||||
|
||||
#ifndef TZ_MAX_LEAPS
|
||||
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
|
||||
#endif /* !defined TZ_MAX_LEAPS */
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY)
|
||||
#define MONSPERYEAR 12
|
||||
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_JANUARY 0
|
||||
#define TM_FEBRUARY 1
|
||||
#define TM_MARCH 2
|
||||
#define TM_APRIL 3
|
||||
#define TM_MAY 4
|
||||
#define TM_JUNE 5
|
||||
#define TM_JULY 6
|
||||
#define TM_AUGUST 7
|
||||
#define TM_SEPTEMBER 8
|
||||
#define TM_OCTOBER 9
|
||||
#define TM_NOVEMBER 10
|
||||
#define TM_DECEMBER 11
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||
|
||||
/*
|
||||
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
|
||||
** isleap(y) == isleap(y % 400)
|
||||
** and so
|
||||
** isleap(a + b) == isleap((a + b) % 400)
|
||||
** or
|
||||
** isleap(a + b) == isleap(a % 400 + b % 400)
|
||||
** This is true even if % means modulo rather than Fortran remainder
|
||||
** (which is allowed by C89 but not C99).
|
||||
** We use this to avoid addition overflow problems.
|
||||
*/
|
||||
|
||||
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
|
||||
|
||||
#ifndef TZ_ABBR_MAX_LEN
|
||||
#define TZ_ABBR_MAX_LEN 16
|
||||
#endif /* !defined TZ_ABBR_MAX_LEN */
|
||||
|
||||
#ifndef TZ_ABBR_CHAR_SET
|
||||
#define TZ_ABBR_CHAR_SET \
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._"
|
||||
#endif /* !defined TZ_ABBR_CHAR_SET */
|
||||
|
||||
#ifndef TZ_ABBR_ERR_CHAR
|
||||
#define TZ_ABBR_ERR_CHAR '_'
|
||||
#endif /* !defined TZ_ABBR_ERR_CHAR */
|
||||
|
||||
#ifndef WILDABBR
|
||||
/*
|
||||
** Someone might make incorrect use of a time zone abbreviation:
|
||||
** 1. They might reference tzname[0] before calling tzset (explicitly
|
||||
** or implicitly).
|
||||
** 2. They might reference tzname[1] before calling tzset (explicitly
|
||||
** or implicitly).
|
||||
** 3. They might reference tzname[1] after setting to a time zone
|
||||
** in which Daylight Saving Time is never observed.
|
||||
** 4. They might reference tzname[0] after setting to a time zone
|
||||
** in which Standard Time is never observed.
|
||||
** 5. They might reference tm.TM_ZONE after calling offtime.
|
||||
** What's best to do in the above cases is open to debate;
|
||||
** for now, we just set things up so that in any of the five cases
|
||||
** WILDABBR is used. Another possibility: initialize tzname[0] to the
|
||||
** string "tzname[0] used before set", and similarly for the other cases.
|
||||
** And another: initialize tzname[0] to "ERA", with an explanation in the
|
||||
** manual page of what this "time zone abbreviation" means (doing this so
|
||||
** that tzname[0] has the "normal" length of three characters).
|
||||
*/
|
||||
#define WILDABBR " "
|
||||
#endif /* !defined WILDABBR */
|
||||
|
||||
#ifdef TM_ZONE
|
||||
static const char wildabbr[] = WILDABBR;
|
||||
#endif
|
||||
|
||||
static const char gmt[] = "GMT";
|
||||
|
||||
struct ttinfo { /* time type information */
|
||||
int_fast32_t tt_gmtoff; /* UT offset in seconds */
|
||||
int tt_isdst; /* used to set tm_isdst */
|
||||
int tt_abbrind; /* abbreviation list index */
|
||||
int tt_ttisstd; /* true if transition is std time */
|
||||
int tt_ttisgmt; /* true if transition is UT */
|
||||
};
|
||||
|
||||
struct lsinfo { /* leap second information */
|
||||
time_t ls_trans; /* transition time */
|
||||
int_fast64_t ls_corr; /* correction to apply */
|
||||
};
|
||||
|
||||
#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#ifdef TZNAME_MAX
|
||||
#define MY_TZNAME_MAX TZNAME_MAX
|
||||
#endif /* defined TZNAME_MAX */
|
||||
#ifndef TZNAME_MAX
|
||||
#define MY_TZNAME_MAX 255
|
||||
#endif /* !defined TZNAME_MAX */
|
||||
|
||||
struct state {
|
||||
int leapcnt;
|
||||
int timecnt;
|
||||
int typecnt;
|
||||
int charcnt;
|
||||
int goback;
|
||||
int goahead;
|
||||
time_t ats[TZ_MAX_TIMES];
|
||||
unsigned char types[TZ_MAX_TIMES];
|
||||
struct ttinfo ttis[TZ_MAX_TYPES];
|
||||
char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
|
||||
(2 * (MY_TZNAME_MAX + 1)))];
|
||||
struct lsinfo lsis[TZ_MAX_LEAPS];
|
||||
int defaulttype; /* for early times or if no transitions */
|
||||
};
|
||||
|
||||
struct rule {
|
||||
int r_type; /* type of rule--see below */
|
||||
int r_day; /* day number of rule */
|
||||
int r_week; /* week number of rule */
|
||||
int r_mon; /* month number of rule */
|
||||
int_fast32_t r_time; /* transition time of rule */
|
||||
};
|
||||
|
||||
#define JULIAN_DAY 0 /* Jn - Julian day */
|
||||
#define DAY_OF_YEAR 1 /* n - day of year */
|
||||
#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */
|
||||
|
||||
/*
|
||||
** Prototypes for static functions.
|
||||
*/
|
||||
|
||||
static void gmtload(struct state * sp);
|
||||
static struct tm * gmtsub(const time_t * timep, int_fast32_t offset,
|
||||
struct tm * tmp);
|
||||
static int increment_overflow(int * number, int delta);
|
||||
static int leaps_thru_end_of(int y) ATTRIBUTE_PURE;
|
||||
static int increment_overflow32(int_fast32_t * number, int delta);
|
||||
static int normalize_overflow32(int_fast32_t * tensptr,
|
||||
int * unitsptr, int base);
|
||||
static int normalize_overflow(int * tensptr, int * unitsptr,
|
||||
int base);
|
||||
static time_t time1(struct tm * tmp,
|
||||
struct tm * (*funcp)(const time_t *,
|
||||
int_fast32_t, struct tm *),
|
||||
int_fast32_t offset);
|
||||
static time_t time2(struct tm *tmp,
|
||||
struct tm * (*funcp)(const time_t *,
|
||||
int_fast32_t, struct tm*),
|
||||
int_fast32_t offset, int * okayp);
|
||||
static time_t time2sub(struct tm *tmp,
|
||||
struct tm * (*funcp)(const time_t *,
|
||||
int_fast32_t, struct tm*),
|
||||
int_fast32_t offset, int * okayp, int do_norm_secs);
|
||||
static struct tm * timesub(const time_t * timep, int_fast32_t offset,
|
||||
const struct state * sp, struct tm * tmp);
|
||||
static int tmcomp(const struct tm * atmp,
|
||||
const struct tm * btmp);
|
||||
|
||||
static struct state gmtmem;
|
||||
#define gmtptr (&gmtmem)
|
||||
|
||||
static int gmt_is_set;
|
||||
|
||||
static const int mon_lengths[2][MONSPERYEAR] = {
|
||||
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
||||
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
};
|
||||
|
||||
static const int year_lengths[2] = {
|
||||
DAYSPERNYEAR, DAYSPERLYEAR
|
||||
};
|
||||
|
||||
static void
|
||||
gmtload(struct state *const sp)
|
||||
{
|
||||
memset(sp, 0, sizeof(struct state));
|
||||
sp->typecnt = 1;
|
||||
sp->charcnt = 4;
|
||||
sp->chars[0] = 'G';
|
||||
sp->chars[1] = 'M';
|
||||
sp->chars[2] = 'T';
|
||||
}
|
||||
|
||||
/*
|
||||
** gmtsub is to gmtime as localsub is to localtime.
|
||||
*/
|
||||
|
||||
static struct tm *
|
||||
gmtsub(const time_t *const timep, const int_fast32_t offset,
|
||||
struct tm *const tmp)
|
||||
{
|
||||
register struct tm * result;
|
||||
|
||||
if (!gmt_is_set) {
|
||||
gmt_is_set = true;
|
||||
// if (gmtptr != NULL)
|
||||
gmtload(gmtptr);
|
||||
}
|
||||
result = timesub(timep, offset, gmtptr, tmp);
|
||||
#ifdef TM_ZONE
|
||||
/*
|
||||
** Could get fancy here and deliver something such as
|
||||
** "UT+xxxx" or "UT-xxxx" if offset is non-zero,
|
||||
** but this is no time for a treasure hunt.
|
||||
*/
|
||||
tmp->TM_ZONE = offset ? wildabbr : gmtptr ? gmtptr->chars : gmt;
|
||||
#endif /* defined TM_ZONE */
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of leap years through the end of the given year
|
||||
** where, to make the math easy, the answer for year zero is defined as zero.
|
||||
*/
|
||||
|
||||
static int
|
||||
leaps_thru_end_of(register const int y)
|
||||
{
|
||||
return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
|
||||
-(leaps_thru_end_of(-(y + 1)) + 1);
|
||||
}
|
||||
|
||||
static struct tm *
|
||||
timesub(const time_t *const timep, const int_fast32_t offset,
|
||||
register const struct state *const sp,
|
||||
register struct tm *const tmp)
|
||||
{
|
||||
register const struct lsinfo * lp;
|
||||
register time_t tdays;
|
||||
register int idays; /* unsigned would be so 2003 */
|
||||
register int_fast64_t rem;
|
||||
int y;
|
||||
register const int * ip;
|
||||
register int_fast64_t corr;
|
||||
register int hit;
|
||||
register int i;
|
||||
|
||||
corr = 0;
|
||||
hit = 0;
|
||||
i = (sp == NULL) ? 0 : sp->leapcnt;
|
||||
while (--i >= 0) {
|
||||
lp = &sp->lsis[i];
|
||||
if (*timep >= lp->ls_trans) {
|
||||
if (*timep == lp->ls_trans) {
|
||||
hit = ((i == 0 && lp->ls_corr > 0) ||
|
||||
lp->ls_corr > sp->lsis[i - 1].ls_corr);
|
||||
if (hit)
|
||||
while (i > 0 &&
|
||||
sp->lsis[i].ls_trans ==
|
||||
sp->lsis[i - 1].ls_trans + 1 &&
|
||||
sp->lsis[i].ls_corr ==
|
||||
sp->lsis[i - 1].ls_corr + 1) {
|
||||
++hit;
|
||||
--i;
|
||||
}
|
||||
}
|
||||
corr = lp->ls_corr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
y = EPOCH_YEAR;
|
||||
tdays = *timep / SECSPERDAY;
|
||||
rem = *timep - tdays * SECSPERDAY;
|
||||
while (tdays < 0 || tdays >= year_lengths[isleap(y)]) {
|
||||
int newy;
|
||||
register time_t tdelta;
|
||||
register int idelta;
|
||||
register int leapdays;
|
||||
|
||||
tdelta = tdays / DAYSPERLYEAR;
|
||||
if (! ((! TYPE_SIGNED(time_t) || INT_MIN <= tdelta)
|
||||
&& tdelta <= INT_MAX))
|
||||
return NULL;
|
||||
idelta = (int) tdelta;
|
||||
if (idelta == 0)
|
||||
idelta = (tdays < 0) ? -1 : 1;
|
||||
newy = y;
|
||||
if (increment_overflow(&newy, idelta))
|
||||
return NULL;
|
||||
leapdays = leaps_thru_end_of(newy - 1) -
|
||||
leaps_thru_end_of(y - 1);
|
||||
tdays -= ((time_t) newy - y) * DAYSPERNYEAR;
|
||||
tdays -= leapdays;
|
||||
y = newy;
|
||||
}
|
||||
{
|
||||
register int_fast32_t seconds;
|
||||
|
||||
seconds = (int_fast32_t) (tdays * SECSPERDAY);
|
||||
tdays = seconds / SECSPERDAY;
|
||||
rem += seconds - tdays * SECSPERDAY;
|
||||
}
|
||||
/*
|
||||
** Given the range, we can now fearlessly cast...
|
||||
*/
|
||||
idays = (int) tdays;
|
||||
rem += offset - corr;
|
||||
while (rem < 0) {
|
||||
rem += SECSPERDAY;
|
||||
--idays;
|
||||
}
|
||||
while (rem >= SECSPERDAY) {
|
||||
rem -= SECSPERDAY;
|
||||
++idays;
|
||||
}
|
||||
while (idays < 0) {
|
||||
if (increment_overflow(&y, -1))
|
||||
return NULL;
|
||||
idays += year_lengths[isleap(y)];
|
||||
}
|
||||
while (idays >= year_lengths[isleap(y)]) {
|
||||
idays -= year_lengths[isleap(y)];
|
||||
if (increment_overflow(&y, 1))
|
||||
return NULL;
|
||||
}
|
||||
tmp->tm_year = y;
|
||||
if (increment_overflow(&tmp->tm_year, -TM_YEAR_BASE))
|
||||
return NULL;
|
||||
tmp->tm_yday = idays;
|
||||
/*
|
||||
** The "extra" mods below avoid overflow problems.
|
||||
*/
|
||||
tmp->tm_wday = EPOCH_WDAY +
|
||||
((y - EPOCH_YEAR) % DAYSPERWEEK) *
|
||||
(DAYSPERNYEAR % DAYSPERWEEK) +
|
||||
leaps_thru_end_of(y - 1) -
|
||||
leaps_thru_end_of(EPOCH_YEAR - 1) +
|
||||
idays;
|
||||
tmp->tm_wday %= DAYSPERWEEK;
|
||||
if (tmp->tm_wday < 0)
|
||||
tmp->tm_wday += DAYSPERWEEK;
|
||||
tmp->tm_hour = (int) (rem / SECSPERHOUR);
|
||||
rem %= SECSPERHOUR;
|
||||
tmp->tm_min = (int) (rem / SECSPERMIN);
|
||||
/*
|
||||
** A positive leap second requires a special
|
||||
** representation. This uses "... ??:59:60" et seq.
|
||||
*/
|
||||
tmp->tm_sec = (int) (rem % SECSPERMIN) + hit;
|
||||
ip = mon_lengths[isleap(y)];
|
||||
for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon))
|
||||
idays -= ip[tmp->tm_mon];
|
||||
tmp->tm_mday = (int) (idays + 1);
|
||||
tmp->tm_isdst = 0;
|
||||
#ifdef TM_GMTOFF
|
||||
tmp->TM_GMTOFF = offset;
|
||||
#endif /* defined TM_GMTOFF */
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
** Adapted from code provided by Robert Elz, who writes:
|
||||
** The "best" way to do mktime I think is based on an idea of Bob
|
||||
** Kridle's (so its said...) from a long time ago.
|
||||
** It does a binary search of the time_t space. Since time_t's are
|
||||
** just 32 bits, its a max of 32 iterations (even at 64 bits it
|
||||
** would still be very reasonable).
|
||||
*/
|
||||
|
||||
#ifndef WRONG
|
||||
#define WRONG (-1)
|
||||
#endif /* !defined WRONG */
|
||||
|
||||
/*
|
||||
** Normalize logic courtesy Paul Eggert.
|
||||
*/
|
||||
|
||||
static int
|
||||
increment_overflow(int *const ip, int j)
|
||||
{
|
||||
register int const i = *ip;
|
||||
|
||||
/*
|
||||
** If i >= 0 there can only be overflow if i + j > INT_MAX
|
||||
** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
|
||||
** If i < 0 there can only be overflow if i + j < INT_MIN
|
||||
** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
|
||||
*/
|
||||
if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i))
|
||||
return true;
|
||||
*ip += j;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
increment_overflow32(int_fast32_t *const lp, int const m)
|
||||
{
|
||||
register int_fast32_t const l = *lp;
|
||||
|
||||
if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
|
||||
return true;
|
||||
*lp += m;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
normalize_overflow(int *const tensptr, int *const unitsptr, const int base)
|
||||
{
|
||||
register int tensdelta;
|
||||
|
||||
tensdelta = (*unitsptr >= 0) ?
|
||||
(*unitsptr / base) :
|
||||
(-1 - (-1 - *unitsptr) / base);
|
||||
*unitsptr -= tensdelta * base;
|
||||
return increment_overflow(tensptr, tensdelta);
|
||||
}
|
||||
|
||||
static int
|
||||
normalize_overflow32(int_fast32_t *const tensptr, int *const unitsptr,
|
||||
const int base)
|
||||
{
|
||||
register int tensdelta;
|
||||
|
||||
tensdelta = (*unitsptr >= 0) ?
|
||||
(*unitsptr / base) :
|
||||
(-1 - (-1 - *unitsptr) / base);
|
||||
*unitsptr -= tensdelta * base;
|
||||
return increment_overflow32(tensptr, tensdelta);
|
||||
}
|
||||
|
||||
static int
|
||||
tmcomp(register const struct tm *const atmp,
|
||||
register const struct tm *const btmp)
|
||||
{
|
||||
register int result;
|
||||
|
||||
if (atmp->tm_year != btmp->tm_year)
|
||||
return atmp->tm_year < btmp->tm_year ? -1 : 1;
|
||||
if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
|
||||
(result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
|
||||
(result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
|
||||
(result = (atmp->tm_min - btmp->tm_min)) == 0)
|
||||
result = atmp->tm_sec - btmp->tm_sec;
|
||||
return result;
|
||||
}
|
||||
|
||||
static time_t
|
||||
time2sub(struct tm *const tmp,
|
||||
struct tm *(*const funcp)(const time_t *, int_fast32_t, struct tm *),
|
||||
const int_fast32_t offset,
|
||||
int *const okayp,
|
||||
const int do_norm_secs)
|
||||
{
|
||||
register const struct state * sp;
|
||||
register int dir;
|
||||
register int i, j;
|
||||
register int saved_seconds;
|
||||
register int_fast32_t li;
|
||||
register time_t lo;
|
||||
register time_t hi;
|
||||
int_fast32_t y;
|
||||
time_t newt;
|
||||
time_t t;
|
||||
struct tm yourtm, mytm;
|
||||
|
||||
*okayp = false;
|
||||
yourtm = *tmp;
|
||||
if (do_norm_secs) {
|
||||
if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec,
|
||||
SECSPERMIN))
|
||||
return WRONG;
|
||||
}
|
||||
if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
|
||||
return WRONG;
|
||||
if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
|
||||
return WRONG;
|
||||
y = yourtm.tm_year;
|
||||
if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR))
|
||||
return WRONG;
|
||||
/*
|
||||
** Turn y into an actual year number for now.
|
||||
** It is converted back to an offset from TM_YEAR_BASE later.
|
||||
*/
|
||||
if (increment_overflow32(&y, TM_YEAR_BASE))
|
||||
return WRONG;
|
||||
while (yourtm.tm_mday <= 0) {
|
||||
if (increment_overflow32(&y, -1))
|
||||
return WRONG;
|
||||
li = y + (1 < yourtm.tm_mon);
|
||||
yourtm.tm_mday += year_lengths[isleap(li)];
|
||||
}
|
||||
while (yourtm.tm_mday > DAYSPERLYEAR) {
|
||||
li = y + (1 < yourtm.tm_mon);
|
||||
yourtm.tm_mday -= year_lengths[isleap(li)];
|
||||
if (increment_overflow32(&y, 1))
|
||||
return WRONG;
|
||||
}
|
||||
for ( ; ; ) {
|
||||
i = mon_lengths[isleap(y)][yourtm.tm_mon];
|
||||
if (yourtm.tm_mday <= i)
|
||||
break;
|
||||
yourtm.tm_mday -= i;
|
||||
if (++yourtm.tm_mon >= MONSPERYEAR) {
|
||||
yourtm.tm_mon = 0;
|
||||
if (increment_overflow32(&y, 1))
|
||||
return WRONG;
|
||||
}
|
||||
}
|
||||
if (increment_overflow32(&y, -TM_YEAR_BASE))
|
||||
return WRONG;
|
||||
yourtm.tm_year = y;
|
||||
if (yourtm.tm_year != y)
|
||||
return WRONG;
|
||||
if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN)
|
||||
saved_seconds = 0;
|
||||
else if (y + TM_YEAR_BASE < EPOCH_YEAR) {
|
||||
/*
|
||||
** We can't set tm_sec to 0, because that might push the
|
||||
** time below the minimum representable time.
|
||||
** Set tm_sec to 59 instead.
|
||||
** This assumes that the minimum representable time is
|
||||
** not in the same minute that a leap second was deleted from,
|
||||
** which is a safer assumption than using 58 would be.
|
||||
*/
|
||||
if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
|
||||
return WRONG;
|
||||
saved_seconds = yourtm.tm_sec;
|
||||
yourtm.tm_sec = SECSPERMIN - 1;
|
||||
} else {
|
||||
saved_seconds = yourtm.tm_sec;
|
||||
yourtm.tm_sec = 0;
|
||||
}
|
||||
/*
|
||||
** Do a binary search (this works whatever time_t's type is).
|
||||
*/
|
||||
if (!TYPE_SIGNED(time_t)) {
|
||||
lo = 0;
|
||||
hi = lo - 1;
|
||||
} else {
|
||||
lo = 1;
|
||||
for (i = 0; i < (int) TYPE_BIT(time_t) - 1; ++i)
|
||||
lo *= 2;
|
||||
hi = -(lo + 1);
|
||||
}
|
||||
for ( ; ; ) {
|
||||
t = lo / 2 + hi / 2;
|
||||
if (t < lo)
|
||||
t = lo;
|
||||
else if (t > hi)
|
||||
t = hi;
|
||||
if ((*funcp)(&t, offset, &mytm) == NULL) {
|
||||
/*
|
||||
** Assume that t is too extreme to be represented in
|
||||
** a struct tm; arrange things so that it is less
|
||||
** extreme on the next pass.
|
||||
*/
|
||||
dir = (t > 0) ? 1 : -1;
|
||||
} else dir = tmcomp(&mytm, &yourtm);
|
||||
if (dir != 0) {
|
||||
if (t == lo) {
|
||||
if (t == time_t_max)
|
||||
return WRONG;
|
||||
++t;
|
||||
++lo;
|
||||
} else if (t == hi) {
|
||||
if (t == time_t_min)
|
||||
return WRONG;
|
||||
--t;
|
||||
--hi;
|
||||
}
|
||||
if (lo > hi)
|
||||
return WRONG;
|
||||
if (dir > 0)
|
||||
hi = t;
|
||||
else lo = t;
|
||||
continue;
|
||||
}
|
||||
if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
|
||||
break;
|
||||
/*
|
||||
** Right time, wrong type.
|
||||
** Hunt for right time, right type.
|
||||
** It's okay to guess wrong since the guess
|
||||
** gets checked.
|
||||
*/
|
||||
sp = (const struct state *) gmtptr;
|
||||
if (sp == NULL)
|
||||
return WRONG;
|
||||
for (i = sp->typecnt - 1; i >= 0; --i) {
|
||||
if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
|
||||
continue;
|
||||
for (j = sp->typecnt - 1; j >= 0; --j) {
|
||||
if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
|
||||
continue;
|
||||
newt = t + sp->ttis[j].tt_gmtoff -
|
||||
sp->ttis[i].tt_gmtoff;
|
||||
if ((*funcp)(&newt, offset, &mytm) == NULL)
|
||||
continue;
|
||||
if (tmcomp(&mytm, &yourtm) != 0)
|
||||
continue;
|
||||
if (mytm.tm_isdst != yourtm.tm_isdst)
|
||||
continue;
|
||||
/*
|
||||
** We have a match.
|
||||
*/
|
||||
t = newt;
|
||||
goto label;
|
||||
}
|
||||
}
|
||||
return WRONG;
|
||||
}
|
||||
label:
|
||||
newt = t + saved_seconds;
|
||||
if ((newt < t) != (saved_seconds < 0))
|
||||
return WRONG;
|
||||
t = newt;
|
||||
if ((*funcp)(&t, offset, tmp))
|
||||
*okayp = true;
|
||||
return t;
|
||||
}
|
||||
|
||||
static time_t
|
||||
time2(struct tm * const tmp,
|
||||
struct tm * (*const funcp)(const time_t *, int_fast32_t, struct tm *),
|
||||
const int_fast32_t offset,
|
||||
int *const okayp)
|
||||
{
|
||||
time_t t;
|
||||
|
||||
/*
|
||||
** First try without normalization of seconds
|
||||
** (in case tm_sec contains a value associated with a leap second).
|
||||
** If that fails, try with normalization of seconds.
|
||||
*/
|
||||
t = time2sub(tmp, funcp, offset, okayp, false);
|
||||
return *okayp ? t : time2sub(tmp, funcp, offset, okayp, true);
|
||||
}
|
||||
|
||||
static time_t
|
||||
time1(struct tm *const tmp,
|
||||
struct tm *(*const funcp) (const time_t *, int_fast32_t, struct tm *),
|
||||
const int_fast32_t offset)
|
||||
{
|
||||
register time_t t;
|
||||
register const struct state * sp;
|
||||
register int samei, otheri;
|
||||
register int sameind, otherind;
|
||||
register int i;
|
||||
register int nseen;
|
||||
int seen[TZ_MAX_TYPES];
|
||||
int types[TZ_MAX_TYPES];
|
||||
int okay;
|
||||
|
||||
if (tmp == NULL) {
|
||||
errno = EINVAL;
|
||||
return WRONG;
|
||||
}
|
||||
if (tmp->tm_isdst > 1)
|
||||
tmp->tm_isdst = 1;
|
||||
t = time2(tmp, funcp, offset, &okay);
|
||||
if (okay)
|
||||
return t;
|
||||
if (tmp->tm_isdst < 0)
|
||||
#ifdef PCTS
|
||||
/*
|
||||
** POSIX Conformance Test Suite code courtesy Grant Sullivan.
|
||||
*/
|
||||
tmp->tm_isdst = 0; /* reset to std and try again */
|
||||
#else
|
||||
return t;
|
||||
#endif /* !defined PCTS */
|
||||
/*
|
||||
** We're supposed to assume that somebody took a time of one type
|
||||
** and did some math on it that yielded a "struct tm" that's bad.
|
||||
** We try to divine the type they started from and adjust to the
|
||||
** type they need.
|
||||
*/
|
||||
sp = (const struct state *) gmtptr;
|
||||
if (sp == NULL)
|
||||
return WRONG;
|
||||
for (i = 0; i < sp->typecnt; ++i)
|
||||
seen[i] = false;
|
||||
nseen = 0;
|
||||
for (i = sp->timecnt - 1; i >= 0; --i)
|
||||
if (!seen[sp->types[i]]) {
|
||||
seen[sp->types[i]] = true;
|
||||
types[nseen++] = sp->types[i];
|
||||
}
|
||||
for (sameind = 0; sameind < nseen; ++sameind) {
|
||||
samei = types[sameind];
|
||||
if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
|
||||
continue;
|
||||
for (otherind = 0; otherind < nseen; ++otherind) {
|
||||
otheri = types[otherind];
|
||||
if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
|
||||
continue;
|
||||
tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
|
||||
sp->ttis[samei].tt_gmtoff;
|
||||
tmp->tm_isdst = !tmp->tm_isdst;
|
||||
t = time2(tmp, funcp, offset, &okay);
|
||||
if (okay)
|
||||
return t;
|
||||
tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
|
||||
sp->ttis[samei].tt_gmtoff;
|
||||
tmp->tm_isdst = !tmp->tm_isdst;
|
||||
}
|
||||
}
|
||||
return WRONG;
|
||||
}
|
||||
|
||||
time_t
|
||||
_bson_timegm(struct tm *const tmp)
|
||||
{
|
||||
if (tmp != NULL)
|
||||
tmp->tm_isdst = 0;
|
||||
return time1(tmp, gmtsub, 0L);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_TYPES_H
|
||||
#define BSON_TYPES_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
#error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "bson-macros.h"
|
||||
#include "bson-compat.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_unichar_t --
|
||||
*
|
||||
* bson_unichar_t provides an unsigned 32-bit type for containing
|
||||
* unicode characters. When iterating UTF-8 sequences, this should
|
||||
* be used to avoid losing the high-bits of non-ascii characters.
|
||||
*
|
||||
* See also:
|
||||
* bson_string_append_unichar()
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef uint32_t bson_unichar_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_context_flags_t:
|
||||
*
|
||||
* This enumeration is used to configure a bson_context_t.
|
||||
*
|
||||
* %BSON_CONTEXT_NONE: Use default options.
|
||||
* %BSON_CONTEXT_THREAD_SAFE: Context will be called from multiple threads.
|
||||
* %BSON_CONTEXT_DISABLE_PID_CACHE: Call getpid() instead of caching the
|
||||
* result of getpid() when initializing the context.
|
||||
* %BSON_CONTEXT_DISABLE_HOST_CACHE: Call gethostname() instead of caching the
|
||||
* result of gethostname() when initializing the context.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BSON_CONTEXT_NONE = 0,
|
||||
BSON_CONTEXT_THREAD_SAFE = (1 << 0),
|
||||
BSON_CONTEXT_DISABLE_HOST_CACHE = (1 << 1),
|
||||
BSON_CONTEXT_DISABLE_PID_CACHE = (1 << 2),
|
||||
#if defined(__linux__)
|
||||
BSON_CONTEXT_USE_TASK_ID = (1 << 3),
|
||||
#endif
|
||||
} bson_context_flags_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_context_t:
|
||||
*
|
||||
* This structure manages context for the bson library. It handles
|
||||
* configuration for thread-safety and other performance related requirements.
|
||||
* Consumers will create a context and may use multiple under a variety of
|
||||
* situations.
|
||||
*
|
||||
* If your program calls fork(), you should initialize a new bson_context_t
|
||||
* using bson_context_init().
|
||||
*
|
||||
* If you are using threading, it is suggested that you use a bson_context_t
|
||||
* per thread for best performance. Alternatively, you can initialize the
|
||||
* bson_context_t with BSON_CONTEXT_THREAD_SAFE, although a performance penalty
|
||||
* will be incurred.
|
||||
*
|
||||
* Many functions will require that you provide a bson_context_t such as OID
|
||||
* generation.
|
||||
*
|
||||
* This structure is oqaque in that you cannot see the contents of the
|
||||
* structure. However, it is stack allocatable in that enough padding is
|
||||
* provided in _bson_context_t to hold the structure.
|
||||
*/
|
||||
typedef struct _bson_context_t bson_context_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_t:
|
||||
*
|
||||
* This structure manages a buffer whose contents are a properly formatted
|
||||
* BSON document. You may perform various transforms on the BSON documents.
|
||||
* Additionally, it can be iterated over using bson_iter_t.
|
||||
*
|
||||
* See bson_iter_init() for iterating the contents of a bson_t.
|
||||
*
|
||||
* When building a bson_t structure using the various append functions,
|
||||
* memory allocations may occur. That is performed using power of two
|
||||
* allocations and realloc().
|
||||
*
|
||||
* See http://bsonspec.org for the BSON document spec.
|
||||
*
|
||||
* This structure is meant to fit in two sequential 64-byte cachelines.
|
||||
*/
|
||||
BSON_ALIGNED_BEGIN (128)
|
||||
typedef struct _bson_t
|
||||
{
|
||||
uint32_t flags; /* Internal flags for the bson_t. */
|
||||
uint32_t len; /* Length of BSON data. */
|
||||
uint8_t padding[120]; /* Padding for stack allocation. */
|
||||
} bson_t
|
||||
BSON_ALIGNED_END (128);
|
||||
|
||||
|
||||
/**
|
||||
* BSON_INITIALIZER:
|
||||
*
|
||||
* This macro can be used to initialize a #bson_t structure on the stack
|
||||
* without calling bson_init().
|
||||
*
|
||||
* |[
|
||||
* bson_t b = BSON_INITIALIZER;
|
||||
* ]|
|
||||
*/
|
||||
#define BSON_INITIALIZER { 3, 5, { 5 } }
|
||||
|
||||
|
||||
BSON_STATIC_ASSERT (sizeof (bson_t) == 128);
|
||||
|
||||
|
||||
/**
|
||||
* bson_oid_t:
|
||||
*
|
||||
* This structure contains the binary form of a BSON Object Id as specified
|
||||
* on http://bsonspec.org. If you would like the bson_oid_t in string form
|
||||
* see bson_oid_to_string() or bson_oid_to_string_r().
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bytes[12];
|
||||
} bson_oid_t;
|
||||
|
||||
|
||||
BSON_STATIC_ASSERT (sizeof (bson_oid_t) == 12);
|
||||
|
||||
|
||||
/**
|
||||
* bson_validate_flags_t:
|
||||
*
|
||||
* This enumeration is used for validation of BSON documents. It allows
|
||||
* selective control on what you wish to validate.
|
||||
*
|
||||
* %BSON_VALIDATE_NONE: No additional validation occurs.
|
||||
* %BSON_VALIDATE_UTF8: Check that strings are valid UTF-8.
|
||||
* %BSON_VALIDATE_DOLLAR_KEYS: Check that keys do not start with $.
|
||||
* %BSON_VALIDATE_DOT_KEYS: Check that keys do not contain a period.
|
||||
* %BSON_VALIDATE_UTF8_ALLOW_NULL: Allow NUL bytes in UTF-8 text.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BSON_VALIDATE_NONE = 0,
|
||||
BSON_VALIDATE_UTF8 = (1 << 0),
|
||||
BSON_VALIDATE_DOLLAR_KEYS = (1 << 1),
|
||||
BSON_VALIDATE_DOT_KEYS = (1 << 2),
|
||||
BSON_VALIDATE_UTF8_ALLOW_NULL = (1 << 3),
|
||||
} bson_validate_flags_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_type_t:
|
||||
*
|
||||
* This enumeration contains all of the possible types within a BSON document.
|
||||
* Use bson_iter_type() to fetch the type of a field while iterating over it.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BSON_TYPE_EOD = 0x00,
|
||||
BSON_TYPE_DOUBLE = 0x01,
|
||||
BSON_TYPE_UTF8 = 0x02,
|
||||
BSON_TYPE_DOCUMENT = 0x03,
|
||||
BSON_TYPE_ARRAY = 0x04,
|
||||
BSON_TYPE_BINARY = 0x05,
|
||||
BSON_TYPE_UNDEFINED = 0x06,
|
||||
BSON_TYPE_OID = 0x07,
|
||||
BSON_TYPE_BOOL = 0x08,
|
||||
BSON_TYPE_DATE_TIME = 0x09,
|
||||
BSON_TYPE_NULL = 0x0A,
|
||||
BSON_TYPE_REGEX = 0x0B,
|
||||
BSON_TYPE_DBPOINTER = 0x0C,
|
||||
BSON_TYPE_CODE = 0x0D,
|
||||
BSON_TYPE_SYMBOL = 0x0E,
|
||||
BSON_TYPE_CODEWSCOPE = 0x0F,
|
||||
BSON_TYPE_INT32 = 0x10,
|
||||
BSON_TYPE_TIMESTAMP = 0x11,
|
||||
BSON_TYPE_INT64 = 0x12,
|
||||
BSON_TYPE_MAXKEY = 0x7F,
|
||||
BSON_TYPE_MINKEY = 0xFF,
|
||||
} bson_type_t;
|
||||
|
||||
|
||||
/**
|
||||
* bson_subtype_t:
|
||||
*
|
||||
* This enumeration contains the various subtypes that may be used in a binary
|
||||
* field. See http://bsonspec.org for more information.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
BSON_SUBTYPE_BINARY = 0x00,
|
||||
BSON_SUBTYPE_FUNCTION = 0x01,
|
||||
BSON_SUBTYPE_BINARY_DEPRECATED = 0x02,
|
||||
BSON_SUBTYPE_UUID_DEPRECATED = 0x03,
|
||||
BSON_SUBTYPE_UUID = 0x04,
|
||||
BSON_SUBTYPE_MD5 = 0x05,
|
||||
BSON_SUBTYPE_USER = 0x80,
|
||||
} bson_subtype_t;
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_value_t --
|
||||
*
|
||||
* A boxed type to contain various bson_type_t types.
|
||||
*
|
||||
* See also:
|
||||
* bson_value_copy()
|
||||
* bson_value_destroy()
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
BSON_ALIGNED_BEGIN (8)
|
||||
typedef struct _bson_value_t
|
||||
{
|
||||
bson_type_t value_type;
|
||||
int32_t padding;
|
||||
union {
|
||||
bson_oid_t v_oid;
|
||||
int64_t v_int64;
|
||||
int32_t v_int32;
|
||||
int8_t v_int8;
|
||||
double v_double;
|
||||
bool v_bool;
|
||||
int64_t v_datetime;
|
||||
struct {
|
||||
uint32_t timestamp;
|
||||
uint32_t increment;
|
||||
} v_timestamp;
|
||||
struct {
|
||||
char *str;
|
||||
uint32_t len;
|
||||
} v_utf8;
|
||||
struct {
|
||||
uint8_t *data;
|
||||
uint32_t data_len;
|
||||
} v_doc;
|
||||
struct {
|
||||
uint8_t *data;
|
||||
uint32_t data_len;
|
||||
bson_subtype_t subtype;
|
||||
} v_binary;
|
||||
struct {
|
||||
char *regex;
|
||||
char *options;
|
||||
} v_regex;
|
||||
struct {
|
||||
char *collection;
|
||||
uint32_t collection_len;
|
||||
bson_oid_t oid;
|
||||
} v_dbpointer;
|
||||
struct {
|
||||
char *code;
|
||||
uint32_t code_len;
|
||||
} v_code;
|
||||
struct {
|
||||
char *code;
|
||||
uint8_t *scope_data;
|
||||
uint32_t code_len;
|
||||
uint32_t scope_len;
|
||||
} v_codewscope;
|
||||
struct {
|
||||
char *symbol;
|
||||
uint32_t len;
|
||||
} v_symbol;
|
||||
} value;
|
||||
} bson_value_t
|
||||
BSON_ALIGNED_END (8);
|
||||
|
||||
|
||||
/**
|
||||
* bson_iter_t:
|
||||
*
|
||||
* This structure manages iteration over a bson_t structure. It keeps track
|
||||
* of the location of the current key and value within the buffer. Using the
|
||||
* various functions to get the value of the iter will read from these
|
||||
* locations.
|
||||
*
|
||||
* This structure is safe to discard on the stack. No cleanup is necessary
|
||||
* after using it.
|
||||
*/
|
||||
BSON_ALIGNED_BEGIN (128)
|
||||
typedef struct
|
||||
{
|
||||
const uint8_t *raw; /* The raw buffer being iterated. */
|
||||
uint32_t len; /* The length of raw. */
|
||||
uint32_t off; /* The offset within the buffer. */
|
||||
uint32_t type; /* The offset of the type byte. */
|
||||
uint32_t key; /* The offset of the key byte. */
|
||||
uint32_t d1; /* The offset of the first data byte. */
|
||||
uint32_t d2; /* The offset of the second data byte. */
|
||||
uint32_t d3; /* The offset of the third data byte. */
|
||||
uint32_t d4; /* The offset of the fourth data byte. */
|
||||
uint32_t next_off; /* The offset of the next field. */
|
||||
uint32_t err_off; /* The offset of the error. */
|
||||
bson_value_t value; /* Internal value for various state. */
|
||||
} bson_iter_t
|
||||
BSON_ALIGNED_END (128);
|
||||
|
||||
|
||||
/**
|
||||
* bson_reader_t:
|
||||
*
|
||||
* This structure is used to iterate over a sequence of BSON documents. It
|
||||
* allows for them to be iterated with the possibility of no additional
|
||||
* memory allocations under certain circumstances such as reading from an
|
||||
* incoming mongo packet.
|
||||
*/
|
||||
|
||||
BSON_ALIGNED_BEGIN (BSON_ALIGN_OF_PTR)
|
||||
typedef struct
|
||||
{
|
||||
uint32_t type;
|
||||
/*< private >*/
|
||||
} bson_reader_t
|
||||
BSON_ALIGNED_END (BSON_ALIGN_OF_PTR);
|
||||
|
||||
|
||||
/**
|
||||
* bson_visitor_t:
|
||||
*
|
||||
* This structure contains a series of pointers that can be executed for
|
||||
* each field of a BSON document based on the field type.
|
||||
*
|
||||
* For example, if an int32 field is found, visit_int32 will be called.
|
||||
*
|
||||
* When visiting each field using bson_iter_visit_all(), you may provide a
|
||||
* data pointer that will be provided with each callback. This might be useful
|
||||
* if you are marshaling to another language.
|
||||
*
|
||||
* You may pre-maturely stop the visitation of fields by returning true in your
|
||||
* visitor. Returning false will continue visitation to further fields.
|
||||
*/
|
||||
BSON_ALIGNED_BEGIN (8)
|
||||
typedef struct
|
||||
{
|
||||
bool (*visit_before) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
void *data);
|
||||
bool (*visit_after) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
void *data);
|
||||
void (*visit_corrupt) (const bson_iter_t *iter,
|
||||
void *data);
|
||||
bool (*visit_double) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
double v_double,
|
||||
void *data);
|
||||
bool (*visit_utf8) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_utf8_len,
|
||||
const char *v_utf8,
|
||||
void *data);
|
||||
bool (*visit_document) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
const bson_t *v_document,
|
||||
void *data);
|
||||
bool (*visit_array) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
const bson_t *v_array,
|
||||
void *data);
|
||||
bool (*visit_binary) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
bson_subtype_t v_subtype,
|
||||
size_t v_binary_len,
|
||||
const uint8_t *v_binary,
|
||||
void *data);
|
||||
bool (*visit_undefined) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
void *data);
|
||||
bool (*visit_oid) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
const bson_oid_t *v_oid,
|
||||
void *data);
|
||||
bool (*visit_bool) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
bool v_bool,
|
||||
void *data);
|
||||
bool (*visit_date_time) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
int64_t msec_since_epoch,
|
||||
void *data);
|
||||
bool (*visit_null) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
void *data);
|
||||
bool (*visit_regex) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
const char *v_regex,
|
||||
const char *v_options,
|
||||
void *data);
|
||||
bool (*visit_dbpointer) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_collection_len,
|
||||
const char *v_collection,
|
||||
const bson_oid_t *v_oid,
|
||||
void *data);
|
||||
bool (*visit_code) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_code_len,
|
||||
const char *v_code,
|
||||
void *data);
|
||||
bool (*visit_symbol) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_symbol_len,
|
||||
const char *v_symbol,
|
||||
void *data);
|
||||
bool (*visit_codewscope) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
size_t v_code_len,
|
||||
const char *v_code,
|
||||
const bson_t *v_scope,
|
||||
void *data);
|
||||
bool (*visit_int32) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
int32_t v_int32,
|
||||
void *data);
|
||||
bool (*visit_timestamp) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
uint32_t v_timestamp,
|
||||
uint32_t v_increment,
|
||||
void *data);
|
||||
bool (*visit_int64) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
int64_t v_int64,
|
||||
void *data);
|
||||
bool (*visit_maxkey) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
void *data);
|
||||
bool (*visit_minkey) (const bson_iter_t *iter,
|
||||
const char *key,
|
||||
void *data);
|
||||
|
||||
void *padding[9];
|
||||
} bson_visitor_t
|
||||
BSON_ALIGNED_END (8);
|
||||
|
||||
|
||||
BSON_ALIGNED_BEGIN (8)
|
||||
typedef struct _bson_error_t
|
||||
{
|
||||
uint32_t domain;
|
||||
uint32_t code;
|
||||
char message[504];
|
||||
} bson_error_t
|
||||
BSON_ALIGNED_END (8);
|
||||
|
||||
|
||||
BSON_STATIC_ASSERT (sizeof (bson_error_t) == 512);
|
||||
|
||||
|
||||
/**
|
||||
* bson_next_power_of_two:
|
||||
* @v: A 32-bit unsigned integer of required bytes.
|
||||
*
|
||||
* Determines the next larger power of two for the value of @v
|
||||
* in a constant number of operations.
|
||||
*
|
||||
* It is up to the caller to guarantee this will not overflow.
|
||||
*
|
||||
* Returns: The next power of 2 from @v.
|
||||
*/
|
||||
static BSON_INLINE size_t
|
||||
bson_next_power_of_two (size_t v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
#if BSON_WORD_SIZE == 64
|
||||
v |= v >> 32;
|
||||
#endif
|
||||
v++;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
static BSON_INLINE bool
|
||||
bson_is_power_of_two (uint32_t v)
|
||||
{
|
||||
return ((v != 0) && ((v & (v - 1)) == 0));
|
||||
}
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_TYPES_H */
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "bson-memory.h"
|
||||
#include "bson-string.h"
|
||||
#include "bson-utf8.h"
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* _bson_utf8_get_sequence --
|
||||
*
|
||||
* Determine the sequence length of the first UTF-8 character in
|
||||
* @utf8. The sequence length is stored in @seq_length and the mask
|
||||
* for the first character is stored in @first_mask.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @seq_length is set.
|
||||
* @first_mask is set.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static BSON_INLINE void
|
||||
_bson_utf8_get_sequence (const char *utf8, /* IN */
|
||||
uint8_t *seq_length, /* OUT */
|
||||
uint8_t *first_mask) /* OUT */
|
||||
{
|
||||
unsigned char c = *(const unsigned char *)utf8;
|
||||
uint8_t m;
|
||||
uint8_t n;
|
||||
|
||||
/*
|
||||
* See the following[1] for a description of what the given multi-byte
|
||||
* sequences will be based on the bits set of the first byte. We also need
|
||||
* to mask the first byte based on that. All subsequent bytes are masked
|
||||
* against 0x3F.
|
||||
*
|
||||
* [1] http://www.joelonsoftware.com/articles/Unicode.html
|
||||
*/
|
||||
|
||||
if ((c & 0x80) == 0) {
|
||||
n = 1;
|
||||
m = 0x7F;
|
||||
} else if ((c & 0xE0) == 0xC0) {
|
||||
n = 2;
|
||||
m = 0x1F;
|
||||
} else if ((c & 0xF0) == 0xE0) {
|
||||
n = 3;
|
||||
m = 0x0F;
|
||||
} else if ((c & 0xF8) == 0xF0) {
|
||||
n = 4;
|
||||
m = 0x07;
|
||||
} else if ((c & 0xFC) == 0xF8) {
|
||||
n = 5;
|
||||
m = 0x03;
|
||||
} else if ((c & 0xFE) == 0xFC) {
|
||||
n = 6;
|
||||
m = 0x01;
|
||||
} else {
|
||||
n = 0;
|
||||
m = 0;
|
||||
}
|
||||
|
||||
*seq_length = n;
|
||||
*first_mask = m;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_utf8_validate --
|
||||
*
|
||||
* Validates that @utf8 is a valid UTF-8 string.
|
||||
*
|
||||
* If @allow_null is true, then \0 is allowed within @utf8_len bytes
|
||||
* of @utf8. Generally, this is bad practice since the main point of
|
||||
* UTF-8 strings is that they can be used with strlen() and friends.
|
||||
* However, some languages such as Python can send UTF-8 encoded
|
||||
* strings with NUL's in them.
|
||||
*
|
||||
* Parameters:
|
||||
* @utf8: A UTF-8 encoded string.
|
||||
* @utf8_len: The length of @utf8 in bytes.
|
||||
* @allow_null: If \0 is allowed within @utf8, exclusing trailing \0.
|
||||
*
|
||||
* Returns:
|
||||
* true if @utf8 is valid UTF-8. otherwise false.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
bson_utf8_validate (const char *utf8, /* IN */
|
||||
size_t utf8_len, /* IN */
|
||||
bool allow_null) /* IN */
|
||||
{
|
||||
bson_unichar_t c;
|
||||
uint8_t first_mask;
|
||||
uint8_t seq_length;
|
||||
unsigned i;
|
||||
unsigned j;
|
||||
|
||||
BSON_ASSERT (utf8);
|
||||
|
||||
for (i = 0; i < utf8_len; i += seq_length) {
|
||||
_bson_utf8_get_sequence (&utf8[i], &seq_length, &first_mask);
|
||||
|
||||
/*
|
||||
* Ensure we have a valid multi-byte sequence length.
|
||||
*/
|
||||
if (!seq_length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure we have enough bytes left.
|
||||
*/
|
||||
if ((utf8_len - i) < seq_length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Also calculate the next char as a unichar so we can
|
||||
* check code ranges for non-shortest form.
|
||||
*/
|
||||
c = utf8 [i] & first_mask;
|
||||
|
||||
/*
|
||||
* Check the high-bits for each additional sequence byte.
|
||||
*/
|
||||
for (j = i + 1; j < (i + seq_length); j++) {
|
||||
c = (c << 6) | (utf8 [j] & 0x3F);
|
||||
if ((utf8[j] & 0xC0) != 0x80) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for NULL bytes afterwards.
|
||||
*
|
||||
* Hint: if you want to optimize this function, starting here to do
|
||||
* this in the same pass as the data above would probably be a good
|
||||
* idea. You would add a branch into the inner loop, but save possibly
|
||||
* on cache-line bouncing on larger strings. Just a thought.
|
||||
*/
|
||||
if (!allow_null) {
|
||||
for (j = 0; j < seq_length; j++) {
|
||||
if (((i + j) > utf8_len) || !utf8[i + j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Code point wont fit in utf-16, not allowed.
|
||||
*/
|
||||
if (c > 0x0010FFFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Byte is in reserved range for UTF-16 high-marks
|
||||
* for surrogate pairs.
|
||||
*/
|
||||
if ((c & 0xFFFFF800) == 0xD800) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check non-shortest form unicode.
|
||||
*/
|
||||
switch (seq_length) {
|
||||
case 1:
|
||||
if (c <= 0x007F) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
|
||||
case 2:
|
||||
if ((c >= 0x0080) && (c <= 0x07FF)) {
|
||||
continue;
|
||||
} else if (c == 0) {
|
||||
/* Two-byte representation for NULL. */
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
|
||||
case 3:
|
||||
if (((c >= 0x0800) && (c <= 0x0FFF)) ||
|
||||
((c >= 0x1000) && (c <= 0xFFFF))) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
|
||||
case 4:
|
||||
if (((c >= 0x10000) && (c <= 0x3FFFF)) ||
|
||||
((c >= 0x40000) && (c <= 0xFFFFF)) ||
|
||||
((c >= 0x100000) && (c <= 0x10FFFF))) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_utf8_escape_for_json --
|
||||
*
|
||||
* Allocates a new string matching @utf8 except that special
|
||||
* characters in JSON will be escaped. The resulting string is also
|
||||
* UTF-8 encoded.
|
||||
*
|
||||
* Both " and \ characters will be escaped. Additionally, if a NUL
|
||||
* byte is found before @utf8_len bytes, it will be converted to the
|
||||
* two byte UTF-8 sequence.
|
||||
*
|
||||
* Parameters:
|
||||
* @utf8: A UTF-8 encoded string.
|
||||
* @utf8_len: The length of @utf8 in bytes or -1 if NUL terminated.
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated string that should be freed with bson_free().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
bson_utf8_escape_for_json (const char *utf8, /* IN */
|
||||
ssize_t utf8_len) /* IN */
|
||||
{
|
||||
bson_unichar_t c;
|
||||
bson_string_t *str;
|
||||
bool length_provided = true;
|
||||
const char *end;
|
||||
|
||||
BSON_ASSERT (utf8);
|
||||
|
||||
str = bson_string_new (NULL);
|
||||
|
||||
if (utf8_len < 0) {
|
||||
length_provided = false;
|
||||
utf8_len = strlen (utf8);
|
||||
}
|
||||
|
||||
end = utf8 + utf8_len;
|
||||
|
||||
while (utf8 < end) {
|
||||
c = bson_utf8_get_char (utf8);
|
||||
|
||||
switch (c) {
|
||||
case '\\':
|
||||
case '"':
|
||||
case '/':
|
||||
bson_string_append_c (str, '\\');
|
||||
bson_string_append_unichar (str, c);
|
||||
break;
|
||||
case '\b':
|
||||
bson_string_append (str, "\\b");
|
||||
break;
|
||||
case '\f':
|
||||
bson_string_append (str, "\\f");
|
||||
break;
|
||||
case '\n':
|
||||
bson_string_append (str, "\\n");
|
||||
break;
|
||||
case '\r':
|
||||
bson_string_append (str, "\\r");
|
||||
break;
|
||||
case '\t':
|
||||
bson_string_append (str, "\\t");
|
||||
break;
|
||||
default:
|
||||
if (c < ' ') {
|
||||
bson_string_append_printf (str, "\\u%04u", (unsigned)c);
|
||||
} else {
|
||||
bson_string_append_unichar (str, c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (c) {
|
||||
utf8 = bson_utf8_next_char (utf8);
|
||||
} else {
|
||||
if (length_provided && !*utf8) {
|
||||
/* we escaped nil as '\u0000', now advance past it */
|
||||
utf8++;
|
||||
} else {
|
||||
/* invalid UTF-8 */
|
||||
bson_string_free (str, true);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bson_string_free (str, false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_utf8_get_char --
|
||||
*
|
||||
* Fetches the next UTF-8 character from the UTF-8 sequence.
|
||||
*
|
||||
* Parameters:
|
||||
* @utf8: A string containing validated UTF-8.
|
||||
*
|
||||
* Returns:
|
||||
* A 32-bit bson_unichar_t reprsenting the multi-byte sequence.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bson_unichar_t
|
||||
bson_utf8_get_char (const char *utf8) /* IN */
|
||||
{
|
||||
bson_unichar_t c;
|
||||
uint8_t mask;
|
||||
uint8_t num;
|
||||
int i;
|
||||
|
||||
BSON_ASSERT (utf8);
|
||||
|
||||
_bson_utf8_get_sequence (utf8, &num, &mask);
|
||||
c = (*utf8) & mask;
|
||||
|
||||
for (i = 1; i < num; i++) {
|
||||
c = (c << 6) | (utf8[i] & 0x3F);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_utf8_next_char --
|
||||
*
|
||||
* Returns an incremented pointer to the beginning of the next
|
||||
* multi-byte sequence in @utf8.
|
||||
*
|
||||
* Parameters:
|
||||
* @utf8: A string containing validated UTF-8.
|
||||
*
|
||||
* Returns:
|
||||
* An incremented pointer in @utf8.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
const char *
|
||||
bson_utf8_next_char (const char *utf8) /* IN */
|
||||
{
|
||||
uint8_t mask;
|
||||
uint8_t num;
|
||||
|
||||
BSON_ASSERT (utf8);
|
||||
|
||||
_bson_utf8_get_sequence (utf8, &num, &mask);
|
||||
|
||||
return utf8 + num;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_utf8_from_unichar --
|
||||
*
|
||||
* Converts the unichar to a sequence of utf8 bytes and stores those
|
||||
* in @utf8. The number of bytes in the sequence are stored in @len.
|
||||
*
|
||||
* Parameters:
|
||||
* @unichar: A bson_unichar_t.
|
||||
* @utf8: A location for the multi-byte sequence.
|
||||
* @len: A location for number of bytes stored in @utf8.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* @utf8 is set.
|
||||
* @len is set.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_utf8_from_unichar (
|
||||
bson_unichar_t unichar, /* IN */
|
||||
char utf8[BSON_ENSURE_ARRAY_PARAM_SIZE(6)], /* OUT */
|
||||
uint32_t *len) /* OUT */
|
||||
{
|
||||
BSON_ASSERT (utf8);
|
||||
BSON_ASSERT (len);
|
||||
|
||||
if (unichar <= 0x7F) {
|
||||
utf8[0] = unichar;
|
||||
*len = 1;
|
||||
} else if (unichar <= 0x7FF) {
|
||||
*len = 2;
|
||||
utf8[0] = 0xC0 | ((unichar >> 6) & 0x3F);
|
||||
utf8[1] = 0x80 | ((unichar) & 0x3F);
|
||||
} else if (unichar <= 0xFFFF) {
|
||||
*len = 3;
|
||||
utf8[0] = 0xE0 | ((unichar >> 12) & 0xF);
|
||||
utf8[1] = 0x80 | ((unichar >> 6) & 0x3F);
|
||||
utf8[2] = 0x80 | ((unichar) & 0x3F);
|
||||
} else if (unichar <= 0x1FFFFF) {
|
||||
*len = 4;
|
||||
utf8[0] = 0xF0 | ((unichar >> 18) & 0x7);
|
||||
utf8[1] = 0x80 | ((unichar >> 12) & 0x3F);
|
||||
utf8[2] = 0x80 | ((unichar >> 6) & 0x3F);
|
||||
utf8[3] = 0x80 | ((unichar) & 0x3F);
|
||||
} else if (unichar <= 0x3FFFFFF) {
|
||||
*len = 5;
|
||||
utf8[0] = 0xF8 | ((unichar >> 24) & 0x3);
|
||||
utf8[1] = 0x80 | ((unichar >> 18) & 0x3F);
|
||||
utf8[2] = 0x80 | ((unichar >> 12) & 0x3F);
|
||||
utf8[3] = 0x80 | ((unichar >> 6) & 0x3F);
|
||||
utf8[4] = 0x80 | ((unichar) & 0x3F);
|
||||
} else if (unichar <= 0x7FFFFFFF) {
|
||||
*len = 6;
|
||||
utf8[0] = 0xFC | ((unichar >> 31) & 0x1);
|
||||
utf8[1] = 0x80 | ((unichar >> 25) & 0x3F);
|
||||
utf8[2] = 0x80 | ((unichar >> 19) & 0x3F);
|
||||
utf8[3] = 0x80 | ((unichar >> 13) & 0x3F);
|
||||
utf8[4] = 0x80 | ((unichar >> 7) & 0x3F);
|
||||
utf8[5] = 0x80 | ((unichar) & 0x1);
|
||||
} else {
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_UTF8_H
|
||||
#define BSON_UTF8_H
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
# error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
bool bson_utf8_validate (const char *utf8,
|
||||
size_t utf8_len,
|
||||
bool allow_null);
|
||||
char *bson_utf8_escape_for_json (const char *utf8,
|
||||
ssize_t utf8_len);
|
||||
bson_unichar_t bson_utf8_get_char (const char *utf8);
|
||||
const char *bson_utf8_next_char (const char *utf8);
|
||||
void bson_utf8_from_unichar (bson_unichar_t unichar,
|
||||
char utf8[6],
|
||||
uint32_t *len);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_UTF8_H */
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "bson-memory.h"
|
||||
#include "bson-string.h"
|
||||
#include "bson-value.h"
|
||||
#include "bson-oid.h"
|
||||
|
||||
|
||||
void
|
||||
bson_value_copy (const bson_value_t *src, /* IN */
|
||||
bson_value_t *dst) /* OUT */
|
||||
{
|
||||
BSON_ASSERT (src);
|
||||
BSON_ASSERT (dst);
|
||||
|
||||
dst->value_type = src->value_type;
|
||||
|
||||
switch (src->value_type) {
|
||||
case BSON_TYPE_DOUBLE:
|
||||
dst->value.v_double = src->value.v_double;
|
||||
break;
|
||||
case BSON_TYPE_UTF8:
|
||||
dst->value.v_utf8.len = src->value.v_utf8.len;
|
||||
dst->value.v_utf8.str = bson_malloc (src->value.v_utf8.len + 1);
|
||||
memcpy (dst->value.v_utf8.str,
|
||||
src->value.v_utf8.str,
|
||||
dst->value.v_utf8.len);
|
||||
dst->value.v_utf8.str [dst->value.v_utf8.len] = '\0';
|
||||
break;
|
||||
case BSON_TYPE_DOCUMENT:
|
||||
case BSON_TYPE_ARRAY:
|
||||
dst->value.v_doc.data_len = src->value.v_doc.data_len;
|
||||
dst->value.v_doc.data = bson_malloc (src->value.v_doc.data_len);
|
||||
memcpy (dst->value.v_doc.data,
|
||||
src->value.v_doc.data,
|
||||
dst->value.v_doc.data_len);
|
||||
break;
|
||||
case BSON_TYPE_BINARY:
|
||||
dst->value.v_binary.subtype = src->value.v_binary.subtype;
|
||||
dst->value.v_binary.data_len = src->value.v_binary.data_len;
|
||||
dst->value.v_binary.data = bson_malloc (src->value.v_binary.data_len);
|
||||
memcpy (dst->value.v_binary.data,
|
||||
src->value.v_binary.data,
|
||||
dst->value.v_binary.data_len);
|
||||
break;
|
||||
case BSON_TYPE_OID:
|
||||
bson_oid_copy (&src->value.v_oid, &dst->value.v_oid);
|
||||
break;
|
||||
case BSON_TYPE_BOOL:
|
||||
dst->value.v_bool = src->value.v_bool;
|
||||
break;
|
||||
case BSON_TYPE_DATE_TIME:
|
||||
dst->value.v_datetime = src->value.v_datetime;
|
||||
break;
|
||||
case BSON_TYPE_REGEX:
|
||||
dst->value.v_regex.regex = bson_strdup (src->value.v_regex.regex);
|
||||
dst->value.v_regex.options = bson_strdup (src->value.v_regex.options);
|
||||
break;
|
||||
case BSON_TYPE_DBPOINTER:
|
||||
dst->value.v_dbpointer.collection_len = src->value.v_dbpointer.collection_len;
|
||||
dst->value.v_dbpointer.collection = bson_malloc (src->value.v_dbpointer.collection_len + 1);
|
||||
memcpy (dst->value.v_dbpointer.collection,
|
||||
src->value.v_dbpointer.collection,
|
||||
dst->value.v_dbpointer.collection_len);
|
||||
dst->value.v_dbpointer.collection [dst->value.v_dbpointer.collection_len] = '\0';
|
||||
bson_oid_copy (&src->value.v_dbpointer.oid, &dst->value.v_dbpointer.oid);
|
||||
break;
|
||||
case BSON_TYPE_CODE:
|
||||
dst->value.v_code.code_len = src->value.v_code.code_len;
|
||||
dst->value.v_code.code = bson_malloc (src->value.v_code.code_len + 1);
|
||||
memcpy (dst->value.v_code.code,
|
||||
src->value.v_code.code,
|
||||
dst->value.v_code.code_len);
|
||||
dst->value.v_code.code [dst->value.v_code.code_len] = '\0';
|
||||
break;
|
||||
case BSON_TYPE_SYMBOL:
|
||||
dst->value.v_symbol.len = src->value.v_symbol.len;
|
||||
dst->value.v_symbol.symbol = bson_malloc (src->value.v_symbol.len + 1);
|
||||
memcpy (dst->value.v_symbol.symbol,
|
||||
src->value.v_symbol.symbol,
|
||||
dst->value.v_symbol.len);
|
||||
dst->value.v_symbol.symbol [dst->value.v_symbol.len] = '\0';
|
||||
break;
|
||||
case BSON_TYPE_CODEWSCOPE:
|
||||
dst->value.v_codewscope.code_len = src->value.v_codewscope.code_len;
|
||||
dst->value.v_codewscope.code = bson_malloc (src->value.v_codewscope.code_len + 1);
|
||||
memcpy (dst->value.v_codewscope.code,
|
||||
src->value.v_codewscope.code,
|
||||
dst->value.v_codewscope.code_len);
|
||||
dst->value.v_codewscope.code [dst->value.v_codewscope.code_len] = '\0';
|
||||
dst->value.v_codewscope.scope_len = src->value.v_codewscope.scope_len;
|
||||
dst->value.v_codewscope.scope_data = bson_malloc (src->value.v_codewscope.scope_len);
|
||||
memcpy (dst->value.v_codewscope.scope_data,
|
||||
src->value.v_codewscope.scope_data,
|
||||
dst->value.v_codewscope.scope_len);
|
||||
break;
|
||||
case BSON_TYPE_INT32:
|
||||
dst->value.v_int32 = src->value.v_int32;
|
||||
break;
|
||||
case BSON_TYPE_TIMESTAMP:
|
||||
dst->value.v_timestamp.timestamp = src->value.v_timestamp.timestamp;
|
||||
dst->value.v_timestamp.increment = src->value.v_timestamp.increment;
|
||||
break;
|
||||
case BSON_TYPE_INT64:
|
||||
dst->value.v_int64 = src->value.v_int64;
|
||||
break;
|
||||
case BSON_TYPE_UNDEFINED:
|
||||
case BSON_TYPE_NULL:
|
||||
case BSON_TYPE_MAXKEY:
|
||||
case BSON_TYPE_MINKEY:
|
||||
break;
|
||||
case BSON_TYPE_EOD:
|
||||
default:
|
||||
BSON_ASSERT (false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bson_value_destroy (bson_value_t *value) /* IN */
|
||||
{
|
||||
switch (value->value_type) {
|
||||
case BSON_TYPE_UTF8:
|
||||
bson_free (value->value.v_utf8.str);
|
||||
break;
|
||||
case BSON_TYPE_DOCUMENT:
|
||||
case BSON_TYPE_ARRAY:
|
||||
bson_free (value->value.v_doc.data);
|
||||
break;
|
||||
case BSON_TYPE_BINARY:
|
||||
bson_free (value->value.v_binary.data);
|
||||
break;
|
||||
case BSON_TYPE_REGEX:
|
||||
bson_free (value->value.v_regex.regex);
|
||||
bson_free (value->value.v_regex.options);
|
||||
break;
|
||||
case BSON_TYPE_DBPOINTER:
|
||||
bson_free (value->value.v_dbpointer.collection);
|
||||
break;
|
||||
case BSON_TYPE_CODE:
|
||||
bson_free (value->value.v_code.code);
|
||||
break;
|
||||
case BSON_TYPE_SYMBOL:
|
||||
bson_free (value->value.v_symbol.symbol);
|
||||
break;
|
||||
case BSON_TYPE_CODEWSCOPE:
|
||||
bson_free (value->value.v_codewscope.code);
|
||||
bson_free (value->value.v_codewscope.scope_data);
|
||||
break;
|
||||
case BSON_TYPE_DOUBLE:
|
||||
case BSON_TYPE_UNDEFINED:
|
||||
case BSON_TYPE_OID:
|
||||
case BSON_TYPE_BOOL:
|
||||
case BSON_TYPE_DATE_TIME:
|
||||
case BSON_TYPE_NULL:
|
||||
case BSON_TYPE_INT32:
|
||||
case BSON_TYPE_TIMESTAMP:
|
||||
case BSON_TYPE_INT64:
|
||||
case BSON_TYPE_MAXKEY:
|
||||
case BSON_TYPE_MINKEY:
|
||||
case BSON_TYPE_EOD:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2014 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_VALUE_H
|
||||
#define BSON_VALUE_H
|
||||
|
||||
|
||||
#include "bson-macros.h"
|
||||
#include "bson-types.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
void bson_value_copy (const bson_value_t *src,
|
||||
bson_value_t *dst);
|
||||
void bson_value_destroy (bson_value_t *value);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_VALUE_H */
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2015 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "bson-version.h"
|
||||
#include "bson-version-functions.h"
|
||||
|
||||
|
||||
/**
|
||||
* bson_get_major_version:
|
||||
*
|
||||
* Helper function to return the runtime major version of the library.
|
||||
*/
|
||||
int
|
||||
bson_get_major_version (void)
|
||||
{
|
||||
return BSON_MAJOR_VERSION;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bson_get_minor_version:
|
||||
*
|
||||
* Helper function to return the runtime minor version of the library.
|
||||
*/
|
||||
int
|
||||
bson_get_minor_version (void)
|
||||
{
|
||||
return BSON_MINOR_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* bson_get_micro_version:
|
||||
*
|
||||
* Helper function to return the runtime micro version of the library.
|
||||
*/
|
||||
int
|
||||
bson_get_micro_version (void)
|
||||
{
|
||||
return BSON_MICRO_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* bson_get_version:
|
||||
*
|
||||
* Helper function to return the runtime string version of the library.
|
||||
*/
|
||||
const char *
|
||||
bson_get_version (void)
|
||||
{
|
||||
return BSON_VERSION_S;
|
||||
}
|
||||
|
||||
/**
|
||||
* bson_check_version:
|
||||
*
|
||||
* True if libmongoc's version is greater than or equal to the required
|
||||
* version.
|
||||
*/
|
||||
bool
|
||||
bson_check_version (int required_major,
|
||||
int required_minor,
|
||||
int required_micro)
|
||||
{
|
||||
return BSON_CHECK_VERSION(required_major, required_minor, required_micro);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2015 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
#error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_VERSION_FUNCTIONS_H
|
||||
#define BSON_VERSION_FUNCTIONS_H
|
||||
|
||||
#include "bson-types.h"
|
||||
|
||||
int bson_get_major_version (void);
|
||||
int bson_get_minor_version (void);
|
||||
int bson_get_micro_version (void);
|
||||
const char *bson_get_version (void);
|
||||
bool bson_check_version (int required_major,
|
||||
int required_minor,
|
||||
int required_micro);
|
||||
|
||||
|
||||
#endif /* BSON_VERSION_FUNCTIONS_H */
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
#error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_VERSION_H
|
||||
#define BSON_VERSION_H
|
||||
|
||||
|
||||
/**
|
||||
* BSON_MAJOR_VERSION:
|
||||
*
|
||||
* BSON major version component (e.g. 1 if %BSON_VERSION is 1.2.3)
|
||||
*/
|
||||
#define BSON_MAJOR_VERSION (1)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_MINOR_VERSION:
|
||||
*
|
||||
* BSON minor version component (e.g. 2 if %BSON_VERSION is 1.2.3)
|
||||
*/
|
||||
#define BSON_MINOR_VERSION (3)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_MICRO_VERSION:
|
||||
*
|
||||
* BSON micro version component (e.g. 3 if %BSON_VERSION is 1.2.3)
|
||||
*/
|
||||
#define BSON_MICRO_VERSION (5)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_PRERELEASE_VERSION:
|
||||
*
|
||||
* BSON prerelease version component (e.g. rc0 if %BSON_VERSION is 1.2.3-rc0)
|
||||
*/
|
||||
#define BSON_PRERELEASE_VERSION ()
|
||||
|
||||
/**
|
||||
* BSON_VERSION:
|
||||
*
|
||||
* BSON version.
|
||||
*/
|
||||
#define BSON_VERSION (1.3.5)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_VERSION_S:
|
||||
*
|
||||
* BSON version, encoded as a string, useful for printing and
|
||||
* concatenation.
|
||||
*/
|
||||
#define BSON_VERSION_S "1.3.5"
|
||||
|
||||
|
||||
/**
|
||||
* BSON_VERSION_HEX:
|
||||
*
|
||||
* BSON version, encoded as an hexadecimal number, useful for
|
||||
* integer comparisons.
|
||||
*/
|
||||
#define BSON_VERSION_HEX (BSON_MAJOR_VERSION << 24 | \
|
||||
BSON_MINOR_VERSION << 16 | \
|
||||
BSON_MICRO_VERSION << 8)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_CHECK_VERSION:
|
||||
* @major: required major version
|
||||
* @minor: required minor version
|
||||
* @micro: required micro version
|
||||
*
|
||||
* Compile-time version checking. Evaluates to %TRUE if the version
|
||||
* of BSON is greater than the required one.
|
||||
*/
|
||||
#define BSON_CHECK_VERSION(major,minor,micro) \
|
||||
(BSON_MAJOR_VERSION > (major) || \
|
||||
(BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION > (minor)) || \
|
||||
(BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION == (minor) && \
|
||||
BSON_MICRO_VERSION >= (micro)))
|
||||
|
||||
#endif /* BSON_VERSION_H */
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#if !defined (BSON_INSIDE) && !defined (BSON_COMPILATION)
|
||||
#error "Only <bson.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BSON_VERSION_H
|
||||
#define BSON_VERSION_H
|
||||
|
||||
|
||||
/**
|
||||
* BSON_MAJOR_VERSION:
|
||||
*
|
||||
* BSON major version component (e.g. 1 if %BSON_VERSION is 1.2.3)
|
||||
*/
|
||||
#define BSON_MAJOR_VERSION (@BSON_MAJOR_VERSION@)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_MINOR_VERSION:
|
||||
*
|
||||
* BSON minor version component (e.g. 2 if %BSON_VERSION is 1.2.3)
|
||||
*/
|
||||
#define BSON_MINOR_VERSION (@BSON_MINOR_VERSION@)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_MICRO_VERSION:
|
||||
*
|
||||
* BSON micro version component (e.g. 3 if %BSON_VERSION is 1.2.3)
|
||||
*/
|
||||
#define BSON_MICRO_VERSION (@BSON_MICRO_VERSION@)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_PRERELEASE_VERSION:
|
||||
*
|
||||
* BSON prerelease version component (e.g. rc0 if %BSON_VERSION is 1.2.3-rc0)
|
||||
*/
|
||||
#define BSON_PRERELEASE_VERSION (@BSON_PRERELEASE_VERSION@)
|
||||
|
||||
/**
|
||||
* BSON_VERSION:
|
||||
*
|
||||
* BSON version.
|
||||
*/
|
||||
#define BSON_VERSION (@BSON_VERSION@)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_VERSION_S:
|
||||
*
|
||||
* BSON version, encoded as a string, useful for printing and
|
||||
* concatenation.
|
||||
*/
|
||||
#define BSON_VERSION_S "@BSON_VERSION@"
|
||||
|
||||
|
||||
/**
|
||||
* BSON_VERSION_HEX:
|
||||
*
|
||||
* BSON version, encoded as an hexadecimal number, useful for
|
||||
* integer comparisons.
|
||||
*/
|
||||
#define BSON_VERSION_HEX (BSON_MAJOR_VERSION << 24 | \
|
||||
BSON_MINOR_VERSION << 16 | \
|
||||
BSON_MICRO_VERSION << 8)
|
||||
|
||||
|
||||
/**
|
||||
* BSON_CHECK_VERSION:
|
||||
* @major: required major version
|
||||
* @minor: required minor version
|
||||
* @micro: required micro version
|
||||
*
|
||||
* Compile-time version checking. Evaluates to %TRUE if the version
|
||||
* of BSON is greater than the required one.
|
||||
*/
|
||||
#define BSON_CHECK_VERSION(major,minor,micro) \
|
||||
(BSON_MAJOR_VERSION > (major) || \
|
||||
(BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION > (minor)) || \
|
||||
(BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION == (minor) && \
|
||||
BSON_MICRO_VERSION >= (micro)))
|
||||
|
||||
#endif /* BSON_VERSION_H */
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "bson-private.h"
|
||||
#include "bson-writer.h"
|
||||
|
||||
|
||||
struct _bson_writer_t
|
||||
{
|
||||
bool ready;
|
||||
uint8_t **buf;
|
||||
size_t *buflen;
|
||||
size_t offset;
|
||||
bson_realloc_func realloc_func;
|
||||
void *realloc_func_ctx;
|
||||
bson_t b;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_writer_new --
|
||||
*
|
||||
* Creates a new instance of bson_writer_t using the buffer, length,
|
||||
* offset, and realloc() function supplied.
|
||||
*
|
||||
* The caller is expected to clean up the structure when finished
|
||||
* using bson_writer_destroy().
|
||||
*
|
||||
* Parameters:
|
||||
* @buf: (inout): A pointer to a target buffer.
|
||||
* @buflen: (inout): A pointer to the buffer length.
|
||||
* @offset: The offset in the target buffer to start from.
|
||||
* @realloc_func: A realloc() style function or NULL.
|
||||
*
|
||||
* Returns:
|
||||
* A newly allocated bson_writer_t that should be freed with
|
||||
* bson_writer_destroy().
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bson_writer_t *
|
||||
bson_writer_new (uint8_t **buf, /* IN */
|
||||
size_t *buflen, /* IN */
|
||||
size_t offset, /* IN */
|
||||
bson_realloc_func realloc_func, /* IN */
|
||||
void *realloc_func_ctx) /* IN */
|
||||
{
|
||||
bson_writer_t *writer;
|
||||
|
||||
writer = bson_malloc0 (sizeof *writer);
|
||||
writer->buf = buf;
|
||||
writer->buflen = buflen;
|
||||
writer->offset = offset;
|
||||
writer->realloc_func = realloc_func;
|
||||
writer->realloc_func_ctx = realloc_func_ctx;
|
||||
writer->ready = true;
|
||||
|
||||
return writer;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_writer_destroy --
|
||||
*
|
||||
* Cleanup after @writer and release any allocated memory. Note that
|
||||
* the buffer supplied to bson_writer_new() is NOT freed from this
|
||||
* method. The caller is responsible for that.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_writer_destroy (bson_writer_t *writer) /* IN */
|
||||
{
|
||||
bson_free (writer);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_writer_get_length --
|
||||
*
|
||||
* Fetches the current length of the content written by the buffer
|
||||
* (including the initial offset). This includes a partly written
|
||||
* document currently being written.
|
||||
*
|
||||
* This is useful if you want to check to see if you've passed a given
|
||||
* memory boundry that cannot be sent in a packet. See
|
||||
* bson_writer_rollback() to abort the current document being written.
|
||||
*
|
||||
* Returns:
|
||||
* The number of bytes written plus initial offset.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
size_t
|
||||
bson_writer_get_length (bson_writer_t *writer) /* IN */
|
||||
{
|
||||
return writer->offset + writer->b.len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_writer_begin --
|
||||
*
|
||||
* Begins writing a new document. The caller may use the bson
|
||||
* structure to write out a new BSON document. When completed, the
|
||||
* caller must call either bson_writer_end() or
|
||||
* bson_writer_rollback().
|
||||
*
|
||||
* Parameters:
|
||||
* @writer: A bson_writer_t.
|
||||
* @bson: (out): A location for a bson_t*.
|
||||
*
|
||||
* Returns:
|
||||
* true if the underlying realloc was successful; otherwise false.
|
||||
*
|
||||
* Side effects:
|
||||
* @bson is initialized if true is returned.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
bool
|
||||
bson_writer_begin (bson_writer_t *writer, /* IN */
|
||||
bson_t **bson) /* OUT */
|
||||
{
|
||||
bson_impl_alloc_t *b;
|
||||
bool grown = false;
|
||||
|
||||
BSON_ASSERT (writer);
|
||||
BSON_ASSERT (writer->ready);
|
||||
BSON_ASSERT (bson);
|
||||
|
||||
writer->ready = false;
|
||||
|
||||
memset (&writer->b, 0, sizeof (bson_t));
|
||||
|
||||
b = (bson_impl_alloc_t *)&writer->b;
|
||||
b->flags = BSON_FLAG_STATIC | BSON_FLAG_NO_FREE;
|
||||
b->len = 5;
|
||||
b->parent = NULL;
|
||||
b->buf = writer->buf;
|
||||
b->buflen = writer->buflen;
|
||||
b->offset = writer->offset;
|
||||
b->alloc = NULL;
|
||||
b->alloclen = 0;
|
||||
b->realloc = writer->realloc_func;
|
||||
b->realloc_func_ctx = writer->realloc_func_ctx;
|
||||
|
||||
while ((writer->offset + writer->b.len) > *writer->buflen) {
|
||||
if (!writer->realloc_func) {
|
||||
memset (&writer->b, 0, sizeof (bson_t));
|
||||
writer->ready = true;
|
||||
return false;
|
||||
}
|
||||
grown = true;
|
||||
|
||||
if (!*writer->buflen) {
|
||||
*writer->buflen = 64;
|
||||
} else {
|
||||
(*writer->buflen) *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (grown) {
|
||||
*writer->buf = writer->realloc_func (*writer->buf, *writer->buflen, writer->realloc_func_ctx);
|
||||
}
|
||||
|
||||
memset ((*writer->buf) + writer->offset + 1, 0, 5);
|
||||
(*writer->buf)[writer->offset] = 5;
|
||||
|
||||
*bson = &writer->b;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_writer_end --
|
||||
*
|
||||
* Complete writing of a bson_writer_t to the buffer supplied.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_writer_end (bson_writer_t *writer) /* IN */
|
||||
{
|
||||
BSON_ASSERT (writer);
|
||||
BSON_ASSERT (!writer->ready);
|
||||
|
||||
writer->offset += writer->b.len;
|
||||
memset (&writer->b, 0, sizeof (bson_t));
|
||||
writer->ready = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*--------------------------------------------------------------------------
|
||||
*
|
||||
* bson_writer_rollback --
|
||||
*
|
||||
* Abort the appending of the current bson_t to the memory region
|
||||
* managed by @writer. This is useful if you detected that you went
|
||||
* past a particular memory limit. For example, MongoDB has 48MB
|
||||
* message limits.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
bson_writer_rollback (bson_writer_t *writer) /* IN */
|
||||
{
|
||||
BSON_ASSERT (writer);
|
||||
|
||||
if (writer->b.len) {
|
||||
memset (&writer->b, 0, sizeof (bson_t));
|
||||
}
|
||||
|
||||
writer->ready = true;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2013 MongoDB, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BSON_WRITER_H
|
||||
#define BSON_WRITER_H
|
||||
|
||||
|
||||
#include "bson.h"
|
||||
|
||||
|
||||
BSON_BEGIN_DECLS
|
||||
|
||||
|
||||
/**
|
||||
* bson_writer_t:
|
||||
*
|
||||
* The bson_writer_t structure is a helper for writing a series of BSON
|
||||
* documents to a single malloc() buffer. You can provide a realloc() style
|
||||
* function to grow the buffer as you go.
|
||||
*
|
||||
* This is useful if you want to build a series of BSON documents right into
|
||||
* the target buffer for an outgoing packet. The offset parameter allows you to
|
||||
* start at an offset of the target buffer.
|
||||
*/
|
||||
typedef struct _bson_writer_t bson_writer_t;
|
||||
|
||||
|
||||
bson_writer_t *bson_writer_new (uint8_t **buf,
|
||||
size_t *buflen,
|
||||
size_t offset,
|
||||
bson_realloc_func realloc_func,
|
||||
void *realloc_func_ctx);
|
||||
void bson_writer_destroy (bson_writer_t *writer);
|
||||
size_t bson_writer_get_length (bson_writer_t *writer);
|
||||
bool bson_writer_begin (bson_writer_t *writer,
|
||||
bson_t **bson);
|
||||
void bson_writer_end (bson_writer_t *writer);
|
||||
void bson_writer_rollback (bson_writer_t *writer);
|
||||
|
||||
|
||||
BSON_END_DECLS
|
||||
|
||||
|
||||
#endif /* BSON_WRITER_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=${prefix}
|
||||
libdir=@libdir@
|
||||
includedir=${exec_prefix}/include
|
||||
|
||||
Name: libbson
|
||||
Description: The libbson BSON serialization library.
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lbson-@BSON_API_VERSION@
|
||||
Cflags: -I${includedir}/libbson-@BSON_API_VERSION@
|
||||
@@ -0,0 +1,184 @@
|
||||
bcon_append
|
||||
bcon_append_ctx
|
||||
bcon_append_ctx_init
|
||||
bcon_append_ctx_va
|
||||
bcon_new
|
||||
bcon_extract
|
||||
bcon_extract_ctx
|
||||
bcon_extract_ctx_init
|
||||
bcon_extract_ctx_va
|
||||
bson_append_array
|
||||
bson_append_array_begin
|
||||
bson_append_array_end
|
||||
bson_append_binary
|
||||
bson_append_bool
|
||||
bson_append_code
|
||||
bson_append_code_with_scope
|
||||
bson_append_date_time
|
||||
bson_append_dbpointer
|
||||
bson_append_document
|
||||
bson_append_document_begin
|
||||
bson_append_document_end
|
||||
bson_append_double
|
||||
bson_append_int32
|
||||
bson_append_int64
|
||||
bson_append_iter
|
||||
bson_append_maxkey
|
||||
bson_append_minkey
|
||||
bson_append_now_utc
|
||||
bson_append_null
|
||||
bson_append_oid
|
||||
bson_append_regex
|
||||
bson_append_symbol
|
||||
bson_append_timestamp
|
||||
bson_append_time_t
|
||||
bson_append_timeval
|
||||
bson_append_undefined
|
||||
bson_append_utf8
|
||||
bson_append_value
|
||||
bson_array_as_json
|
||||
bson_as_json
|
||||
bson_ascii_strtoll
|
||||
bson_atomic_int_add
|
||||
bson_atomic_int64_add
|
||||
bson_bcon_magic
|
||||
bson_bcone_magic
|
||||
bson_compare
|
||||
bson_concat
|
||||
bson_context_destroy
|
||||
bson_context_new
|
||||
bson_context_get_default
|
||||
bson_copy
|
||||
bson_copy_to
|
||||
bson_copy_to_excluding
|
||||
bson_copy_to_excluding_noinit
|
||||
bson_count_keys
|
||||
bson_destroy
|
||||
bson_destroy_with_steal
|
||||
bson_equal
|
||||
bson_free
|
||||
bson_get_data
|
||||
bson_get_major_version
|
||||
bson_get_micro_version
|
||||
bson_get_minor_version
|
||||
bson_get_monotonic_time
|
||||
bson_gettimeofday
|
||||
bson_has_field
|
||||
bson_init
|
||||
bson_init_from_json
|
||||
bson_init_static
|
||||
bson_iter_array
|
||||
bson_iter_as_bool
|
||||
bson_iter_as_int64
|
||||
bson_iter_binary
|
||||
bson_iter_bool
|
||||
bson_iter_code
|
||||
bson_iter_codewscope
|
||||
bson_iter_date_time
|
||||
bson_iter_dbpointer
|
||||
bson_iter_document
|
||||
bson_iter_double
|
||||
bson_iter_dup_utf8
|
||||
bson_iter_find
|
||||
bson_iter_find_case
|
||||
bson_iter_find_descendant
|
||||
bson_iter_init
|
||||
bson_iter_init_find
|
||||
bson_iter_init_find_case
|
||||
bson_iter_int32
|
||||
bson_iter_int64
|
||||
bson_iter_key
|
||||
bson_iter_next
|
||||
bson_iter_oid
|
||||
bson_iter_overwrite_bool
|
||||
bson_iter_overwrite_double
|
||||
bson_iter_overwrite_int32
|
||||
bson_iter_overwrite_int64
|
||||
bson_iter_recurse
|
||||
bson_iter_regex
|
||||
bson_iter_symbol
|
||||
bson_iter_timestamp
|
||||
bson_iter_time_t
|
||||
bson_iter_timeval
|
||||
bson_iter_type
|
||||
bson_iter_utf8
|
||||
bson_iter_value
|
||||
bson_iter_visit_all
|
||||
bson_json_data_reader_ingest
|
||||
bson_json_data_reader_new
|
||||
bson_json_reader_destroy
|
||||
bson_json_reader_new
|
||||
bson_json_reader_new_from_fd
|
||||
bson_json_reader_new_from_file
|
||||
bson_json_reader_read
|
||||
bson_malloc
|
||||
bson_malloc0
|
||||
bson_md5_init
|
||||
bson_md5_finish
|
||||
bson_md5_append
|
||||
bson_mem_restore_vtable
|
||||
bson_mem_set_vtable
|
||||
bson_new
|
||||
bson_new_from_buffer
|
||||
bson_new_from_data
|
||||
bson_new_from_json
|
||||
bson_oid_compare
|
||||
bson_oid_copy
|
||||
bson_oid_equal
|
||||
bson_oid_get_time_t
|
||||
bson_oid_hash
|
||||
bson_oid_init
|
||||
bson_oid_init_from_data
|
||||
bson_oid_init_from_string
|
||||
bson_oid_init_sequence
|
||||
bson_oid_is_valid
|
||||
bson_oid_to_string
|
||||
bson_reader_destroy
|
||||
bson_reader_new_from_data
|
||||
bson_reader_new_from_fd
|
||||
bson_reader_new_from_file
|
||||
bson_reader_new_from_handle
|
||||
bson_reader_read
|
||||
bson_reader_set_read_func
|
||||
bson_reader_set_destroy_func
|
||||
bson_reader_tell
|
||||
bson_realloc
|
||||
bson_realloc_ctx
|
||||
bson_reinit
|
||||
bson_set_error
|
||||
bson_sized_new
|
||||
bson_snprintf
|
||||
bson_strdup
|
||||
bson_strdup_printf
|
||||
bson_strdupv_printf
|
||||
bson_strfreev
|
||||
bson_strerror_r
|
||||
bson_string_append
|
||||
bson_string_append_c
|
||||
bson_string_append_printf
|
||||
bson_string_append_unichar
|
||||
bson_string_free
|
||||
bson_string_new
|
||||
bson_string_truncate
|
||||
bson_strncpy
|
||||
bson_strndup
|
||||
bson_strnlen
|
||||
bson_uint32_to_string
|
||||
bson_utf8_escape_for_json
|
||||
bson_utf8_from_unichar
|
||||
bson_utf8_get_char
|
||||
bson_utf8_next_char
|
||||
bson_utf8_validate
|
||||
bson_validate
|
||||
bson_value_copy
|
||||
bson_value_destroy
|
||||
bson_vsnprintf
|
||||
bson_writer_begin
|
||||
bson_writer_destroy
|
||||
bson_writer_end
|
||||
bson_writer_get_length
|
||||
bson_writer_new
|
||||
bson_writer_rollback
|
||||
bson_zero_free
|
||||
LIBBSON_1.0
|
||||
LIBBSON_1.1
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yajl_parse.h"
|
||||
#include "yajl_lex.h"
|
||||
#include "yajl_parser.h"
|
||||
#include "yajl_alloc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
|
||||
const char *
|
||||
yajl_status_to_string(yajl_status stat)
|
||||
{
|
||||
const char * statStr = "unknown";
|
||||
switch (stat) {
|
||||
case yajl_status_ok:
|
||||
statStr = "ok, no error";
|
||||
break;
|
||||
case yajl_status_client_canceled:
|
||||
statStr = "client canceled parse";
|
||||
break;
|
||||
case yajl_status_error:
|
||||
statStr = "parse error";
|
||||
break;
|
||||
}
|
||||
return statStr;
|
||||
}
|
||||
|
||||
yajl_handle
|
||||
yajl_alloc(const yajl_callbacks * callbacks,
|
||||
yajl_alloc_funcs * afs,
|
||||
void * ctx)
|
||||
{
|
||||
yajl_handle hand = NULL;
|
||||
yajl_alloc_funcs afsBuffer;
|
||||
|
||||
/* first order of business is to set up memory allocation routines */
|
||||
if (afs != NULL) {
|
||||
if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
yajl_set_default_alloc_funcs(&afsBuffer);
|
||||
afs = &afsBuffer;
|
||||
}
|
||||
|
||||
hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t));
|
||||
|
||||
/* copy in pointers to allocation routines */
|
||||
memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
|
||||
|
||||
hand->callbacks = callbacks;
|
||||
hand->ctx = ctx;
|
||||
hand->lexer = NULL;
|
||||
hand->bytesConsumed = 0;
|
||||
hand->decodeBuf = yajl_buf_alloc(&(hand->alloc));
|
||||
hand->flags = 0;
|
||||
yajl_bs_init(hand->stateStack, &(hand->alloc));
|
||||
yajl_bs_push(hand->stateStack, yajl_state_start);
|
||||
|
||||
return hand;
|
||||
}
|
||||
|
||||
int
|
||||
yajl_config(yajl_handle h, yajl_option opt, ...)
|
||||
{
|
||||
int rv = 1;
|
||||
va_list ap;
|
||||
va_start(ap, opt);
|
||||
|
||||
switch(opt) {
|
||||
case yajl_allow_comments:
|
||||
case yajl_dont_validate_strings:
|
||||
case yajl_allow_trailing_garbage:
|
||||
case yajl_allow_multiple_values:
|
||||
case yajl_allow_partial_values:
|
||||
if (va_arg(ap, int)) h->flags |= opt;
|
||||
else h->flags &= ~opt;
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_free(yajl_handle handle)
|
||||
{
|
||||
yajl_bs_free(handle->stateStack);
|
||||
yajl_buf_free(handle->decodeBuf);
|
||||
if (handle->lexer) {
|
||||
yajl_lex_free(handle->lexer);
|
||||
handle->lexer = NULL;
|
||||
}
|
||||
YA_FREE(&(handle->alloc), handle);
|
||||
}
|
||||
|
||||
yajl_status
|
||||
yajl_parse(yajl_handle hand, const unsigned char * jsonText,
|
||||
size_t jsonTextLen)
|
||||
{
|
||||
yajl_status status;
|
||||
|
||||
/* lazy allocation of the lexer */
|
||||
if (hand->lexer == NULL) {
|
||||
hand->lexer = yajl_lex_alloc(&(hand->alloc),
|
||||
hand->flags & yajl_allow_comments,
|
||||
!(hand->flags & yajl_dont_validate_strings));
|
||||
}
|
||||
|
||||
status = yajl_do_parse(hand, jsonText, jsonTextLen);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
yajl_status
|
||||
yajl_complete_parse(yajl_handle hand)
|
||||
{
|
||||
/* The lexer is lazy allocated in the first call to parse. if parse is
|
||||
* never called, then no data was provided to parse at all. This is a
|
||||
* "premature EOF" error unless yajl_allow_partial_values is specified.
|
||||
* allocating the lexer now is the simplest possible way to handle this
|
||||
* case while preserving all the other semantics of the parser
|
||||
* (multiple values, partial values, etc). */
|
||||
if (hand->lexer == NULL) {
|
||||
hand->lexer = yajl_lex_alloc(&(hand->alloc),
|
||||
hand->flags & yajl_allow_comments,
|
||||
!(hand->flags & yajl_dont_validate_strings));
|
||||
}
|
||||
|
||||
return yajl_do_finish(hand);
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
yajl_get_error(yajl_handle hand, int verbose,
|
||||
const unsigned char * jsonText, size_t jsonTextLen)
|
||||
{
|
||||
return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose);
|
||||
}
|
||||
|
||||
size_t
|
||||
yajl_get_bytes_consumed(yajl_handle hand)
|
||||
{
|
||||
if (!hand) return 0;
|
||||
else return hand->bytesConsumed;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
yajl_free_error(yajl_handle hand, unsigned char * str)
|
||||
{
|
||||
/* use memory allocation functions if set */
|
||||
YA_FREE(&(hand->alloc), str);
|
||||
}
|
||||
|
||||
/* XXX: add utility routines to parse from file */
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_alloc.h
|
||||
* default memory allocation routines for yajl which use malloc/realloc and
|
||||
* free
|
||||
*/
|
||||
|
||||
#include "yajl_alloc.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static void * yajl_internal_malloc(void *ctx, size_t sz)
|
||||
{
|
||||
return malloc(sz);
|
||||
}
|
||||
|
||||
static void * yajl_internal_realloc(void *ctx, void * previous,
|
||||
size_t sz)
|
||||
{
|
||||
return realloc(previous, sz);
|
||||
}
|
||||
|
||||
static void yajl_internal_free(void *ctx, void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf)
|
||||
{
|
||||
yaf->malloc = yajl_internal_malloc;
|
||||
yaf->free = yajl_internal_free;
|
||||
yaf->realloc = yajl_internal_realloc;
|
||||
yaf->ctx = NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_alloc.h
|
||||
* default memory allocation routines for yajl which use malloc/realloc and
|
||||
* free
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_ALLOC_H__
|
||||
#define __YAJL_ALLOC_H__
|
||||
|
||||
#include "yajl_common.h"
|
||||
|
||||
#define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz))
|
||||
#define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr))
|
||||
#define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz))
|
||||
|
||||
void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yajl_buf.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define YAJL_BUF_INIT_SIZE 2048
|
||||
|
||||
struct yajl_buf_t {
|
||||
size_t len;
|
||||
size_t used;
|
||||
unsigned char * data;
|
||||
yajl_alloc_funcs * alloc;
|
||||
};
|
||||
|
||||
static
|
||||
void yajl_buf_ensure_available(yajl_buf buf, size_t want)
|
||||
{
|
||||
size_t need;
|
||||
|
||||
assert(buf != NULL);
|
||||
|
||||
/* first call */
|
||||
if (buf->data == NULL) {
|
||||
buf->len = YAJL_BUF_INIT_SIZE;
|
||||
buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len);
|
||||
buf->data[0] = 0;
|
||||
}
|
||||
|
||||
need = buf->len;
|
||||
|
||||
while (want >= (need - buf->used)) need <<= 1;
|
||||
|
||||
if (need != buf->len) {
|
||||
buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need);
|
||||
buf->len = need;
|
||||
}
|
||||
}
|
||||
|
||||
yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc)
|
||||
{
|
||||
yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t));
|
||||
memset((void *) b, 0, sizeof(struct yajl_buf_t));
|
||||
b->alloc = alloc;
|
||||
return b;
|
||||
}
|
||||
|
||||
void yajl_buf_free(yajl_buf buf)
|
||||
{
|
||||
assert(buf != NULL);
|
||||
if (buf->data) YA_FREE(buf->alloc, buf->data);
|
||||
YA_FREE(buf->alloc, buf);
|
||||
}
|
||||
|
||||
void yajl_buf_append(yajl_buf buf, const void * data, size_t len)
|
||||
{
|
||||
yajl_buf_ensure_available(buf, len);
|
||||
if (len > 0) {
|
||||
assert(data != NULL);
|
||||
memcpy(buf->data + buf->used, data, len);
|
||||
buf->used += len;
|
||||
buf->data[buf->used] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void yajl_buf_clear(yajl_buf buf)
|
||||
{
|
||||
buf->used = 0;
|
||||
if (buf->data) buf->data[buf->used] = 0;
|
||||
}
|
||||
|
||||
const unsigned char * yajl_buf_data(yajl_buf buf)
|
||||
{
|
||||
return buf->data;
|
||||
}
|
||||
|
||||
size_t yajl_buf_len(yajl_buf buf)
|
||||
{
|
||||
return buf->used;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_buf_truncate(yajl_buf buf, size_t len)
|
||||
{
|
||||
assert(len <= buf->used);
|
||||
buf->used = len;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_BUF_H__
|
||||
#define __YAJL_BUF_H__
|
||||
|
||||
#include "yajl_common.h"
|
||||
#include "yajl_alloc.h"
|
||||
|
||||
/*
|
||||
* Implementation/performance notes. If this were moved to a header
|
||||
* only implementation using #define's where possible we might be
|
||||
* able to sqeeze a little performance out of the guy by killing function
|
||||
* call overhead. YMMV.
|
||||
*/
|
||||
|
||||
/**
|
||||
* yajl_buf is a buffer with exponential growth. the buffer ensures that
|
||||
* you are always null padded.
|
||||
*/
|
||||
typedef struct yajl_buf_t * yajl_buf;
|
||||
|
||||
/* allocate a new buffer */
|
||||
yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc);
|
||||
|
||||
/* free the buffer */
|
||||
void yajl_buf_free(yajl_buf buf);
|
||||
|
||||
/* append a number of bytes to the buffer */
|
||||
void yajl_buf_append(yajl_buf buf, const void * data, size_t len);
|
||||
|
||||
/* empty the buffer */
|
||||
void yajl_buf_clear(yajl_buf buf);
|
||||
|
||||
/* get a pointer to the beginning of the buffer */
|
||||
const unsigned char * yajl_buf_data(yajl_buf buf);
|
||||
|
||||
/* get the length of the buffer */
|
||||
size_t yajl_buf_len(yajl_buf buf);
|
||||
|
||||
/* truncate the buffer */
|
||||
void yajl_buf_truncate(yajl_buf buf, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A header only implementation of a simple stack of bytes, used in YAJL
|
||||
* to maintain parse state.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_BYTESTACK_H__
|
||||
#define __YAJL_BYTESTACK_H__
|
||||
|
||||
#include "yajl_common.h"
|
||||
|
||||
#define YAJL_BS_INC 128
|
||||
|
||||
typedef struct yajl_bytestack_t
|
||||
{
|
||||
unsigned char * stack;
|
||||
size_t size;
|
||||
size_t used;
|
||||
yajl_alloc_funcs * yaf;
|
||||
} yajl_bytestack;
|
||||
|
||||
/* initialize a bytestack */
|
||||
#define yajl_bs_init(obs, _yaf) { \
|
||||
(obs).stack = NULL; \
|
||||
(obs).size = 0; \
|
||||
(obs).used = 0; \
|
||||
(obs).yaf = (_yaf); \
|
||||
} \
|
||||
|
||||
|
||||
/* initialize a bytestack */
|
||||
#define yajl_bs_free(obs) \
|
||||
if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack);
|
||||
|
||||
#define yajl_bs_current(obs) \
|
||||
(assert((obs).used > 0), (obs).stack[(obs).used - 1])
|
||||
|
||||
#define yajl_bs_push(obs, byte) { \
|
||||
if (((obs).size - (obs).used) == 0) { \
|
||||
(obs).size += YAJL_BS_INC; \
|
||||
(obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\
|
||||
(void *) (obs).stack, (obs).size);\
|
||||
} \
|
||||
(obs).stack[((obs).used)++] = (byte); \
|
||||
}
|
||||
|
||||
/* removes the top item of the stack, returns nothing */
|
||||
#define yajl_bs_pop(obs) { ((obs).used)--; }
|
||||
|
||||
#define yajl_bs_set(obs, byte) \
|
||||
(obs).stack[((obs).used) - 1] = (byte);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_COMMON_H__
|
||||
#define __YAJL_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define YAJL_MAX_DEPTH 128
|
||||
|
||||
/* msft dll export gunk. To build a DLL on windows, you
|
||||
* must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared
|
||||
* DLL, you must define YAJL_SHARED and WIN32 */
|
||||
#if (defined(_WIN32) || defined(WIN32)) && defined(YAJL_SHARED)
|
||||
# ifdef YAJL_BUILD
|
||||
# define YAJL_API __declspec(dllexport)
|
||||
# else
|
||||
# define YAJL_API __declspec(dllimport)
|
||||
# endif
|
||||
#else
|
||||
# if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303
|
||||
# define YAJL_API __attribute__ ((visibility("default")))
|
||||
# else
|
||||
# define YAJL_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/** pointer to a malloc function, supporting client overriding memory
|
||||
* allocation routines */
|
||||
typedef void * (*yajl_malloc_func)(void *ctx, size_t sz);
|
||||
|
||||
/** pointer to a free function, supporting client overriding memory
|
||||
* allocation routines */
|
||||
typedef void (*yajl_free_func)(void *ctx, void * ptr);
|
||||
|
||||
/** pointer to a realloc function which can resize an allocation. */
|
||||
typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, size_t sz);
|
||||
|
||||
/** A structure which can be passed to yajl_*_alloc routines to allow the
|
||||
* client to specify memory allocation functions to be used. */
|
||||
typedef struct
|
||||
{
|
||||
/** pointer to a function that can allocate uninitialized memory */
|
||||
yajl_malloc_func malloc;
|
||||
/** pointer to a function that can resize memory allocations */
|
||||
yajl_realloc_func realloc;
|
||||
/** pointer to a function that can free memory allocated using
|
||||
* reallocFunction or mallocFunction */
|
||||
yajl_free_func free;
|
||||
/** a context pointer that will be passed to above allocation routines */
|
||||
void * ctx;
|
||||
} yajl_alloc_funcs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yajl_encode.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void CharToHex(unsigned char c, char * hexBuf)
|
||||
{
|
||||
const char * hexchar = "0123456789ABCDEF";
|
||||
hexBuf[0] = hexchar[c >> 4];
|
||||
hexBuf[1] = hexchar[c & 0x0F];
|
||||
}
|
||||
|
||||
void
|
||||
yajl_string_encode(const yajl_print_t print,
|
||||
void * ctx,
|
||||
const unsigned char * str,
|
||||
size_t len,
|
||||
int escape_solidus)
|
||||
{
|
||||
size_t beg = 0;
|
||||
size_t end = 0;
|
||||
char hexBuf[7];
|
||||
hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0';
|
||||
hexBuf[6] = 0;
|
||||
|
||||
while (end < len) {
|
||||
const char * escaped = NULL;
|
||||
switch (str[end]) {
|
||||
case '\r': escaped = "\\r"; break;
|
||||
case '\n': escaped = "\\n"; break;
|
||||
case '\\': escaped = "\\\\"; break;
|
||||
/* it is not required to escape a solidus in JSON:
|
||||
* read sec. 2.5: http://www.ietf.org/rfc/rfc4627.txt
|
||||
* specifically, this production from the grammar:
|
||||
* unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
|
||||
*/
|
||||
case '/': if (escape_solidus) escaped = "\\/"; break;
|
||||
case '"': escaped = "\\\""; break;
|
||||
case '\f': escaped = "\\f"; break;
|
||||
case '\b': escaped = "\\b"; break;
|
||||
case '\t': escaped = "\\t"; break;
|
||||
default:
|
||||
if ((unsigned char) str[end] < 32) {
|
||||
CharToHex(str[end], hexBuf + 4);
|
||||
escaped = hexBuf;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (escaped != NULL) {
|
||||
print(ctx, (const char *) (str + beg), end - beg);
|
||||
print(ctx, escaped, (unsigned int)strlen(escaped));
|
||||
beg = ++end;
|
||||
} else {
|
||||
++end;
|
||||
}
|
||||
}
|
||||
print(ctx, (const char *) (str + beg), end - beg);
|
||||
}
|
||||
|
||||
static void hexToDigit(unsigned int * val, const unsigned char * hex)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i=0;i<4;i++) {
|
||||
unsigned char c = hex[i];
|
||||
if (c >= 'A') c = (c & ~0x20) - 7;
|
||||
c -= '0';
|
||||
assert(!(c & 0xF0));
|
||||
*val = (*val << 4) | c;
|
||||
}
|
||||
}
|
||||
|
||||
static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf)
|
||||
{
|
||||
if (codepoint < 0x80) {
|
||||
utf8Buf[0] = (char) codepoint;
|
||||
utf8Buf[1] = 0;
|
||||
} else if (codepoint < 0x0800) {
|
||||
utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0);
|
||||
utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80);
|
||||
utf8Buf[2] = 0;
|
||||
} else if (codepoint < 0x10000) {
|
||||
utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0);
|
||||
utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80);
|
||||
utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80);
|
||||
utf8Buf[3] = 0;
|
||||
} else if (codepoint < 0x200000) {
|
||||
utf8Buf[0] =(char)((codepoint >> 18) | 0xF0);
|
||||
utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80);
|
||||
utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80);
|
||||
utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80);
|
||||
utf8Buf[4] = 0;
|
||||
} else {
|
||||
utf8Buf[0] = '?';
|
||||
utf8Buf[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void yajl_string_decode(yajl_buf buf, const unsigned char * str,
|
||||
size_t len)
|
||||
{
|
||||
size_t beg = 0;
|
||||
size_t end = 0;
|
||||
|
||||
while (end < len) {
|
||||
if (str[end] == '\\') {
|
||||
char utf8Buf[5];
|
||||
const char * unescaped = "?";
|
||||
yajl_buf_append(buf, str + beg, end - beg);
|
||||
switch (str[++end]) {
|
||||
case 'r': unescaped = "\r"; break;
|
||||
case 'n': unescaped = "\n"; break;
|
||||
case '\\': unescaped = "\\"; break;
|
||||
case '/': unescaped = "/"; break;
|
||||
case '"': unescaped = "\""; break;
|
||||
case 'f': unescaped = "\f"; break;
|
||||
case 'b': unescaped = "\b"; break;
|
||||
case 't': unescaped = "\t"; break;
|
||||
case 'u': {
|
||||
unsigned int codepoint = 0;
|
||||
hexToDigit(&codepoint, str + ++end);
|
||||
end+=3;
|
||||
/* check if this is a surrogate */
|
||||
if ((codepoint & 0xFC00) == 0xD800) {
|
||||
end++;
|
||||
if (str[end] == '\\' && str[end + 1] == 'u') {
|
||||
unsigned int surrogate = 0;
|
||||
hexToDigit(&surrogate, str + end + 2);
|
||||
codepoint =
|
||||
(((codepoint & 0x3F) << 10) |
|
||||
((((codepoint >> 6) & 0xF) + 1) << 16) |
|
||||
(surrogate & 0x3FF));
|
||||
end += 5;
|
||||
} else {
|
||||
unescaped = "?";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Utf32toUtf8(codepoint, utf8Buf);
|
||||
unescaped = utf8Buf;
|
||||
|
||||
if (codepoint == 0) {
|
||||
yajl_buf_append(buf, unescaped, 1);
|
||||
beg = ++end;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert("this should never happen" == NULL);
|
||||
}
|
||||
yajl_buf_append(buf, unescaped, (unsigned int)strlen(unescaped));
|
||||
beg = ++end;
|
||||
} else {
|
||||
end++;
|
||||
}
|
||||
}
|
||||
yajl_buf_append(buf, str + beg, end - beg);
|
||||
}
|
||||
|
||||
#define ADV_PTR s++; if (!(len--)) return 0;
|
||||
|
||||
int yajl_string_validate_utf8(const unsigned char * s, size_t len)
|
||||
{
|
||||
if (!len) return 1;
|
||||
if (!s) return 0;
|
||||
|
||||
while (len--) {
|
||||
/* single byte */
|
||||
if (*s <= 0x7f) {
|
||||
/* noop */
|
||||
}
|
||||
/* two byte */
|
||||
else if ((*s >> 5) == 0x6) {
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
}
|
||||
/* three byte */
|
||||
else if ((*s >> 4) == 0x0e) {
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
}
|
||||
/* four byte */
|
||||
else if ((*s >> 3) == 0x1e) {
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
ADV_PTR;
|
||||
if (!((*s >> 6) == 0x2)) return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_ENCODE_H__
|
||||
#define __YAJL_ENCODE_H__
|
||||
|
||||
#include "yajl_buf.h"
|
||||
#include "yajl_gen.h"
|
||||
|
||||
void yajl_string_encode(const yajl_print_t printer,
|
||||
void * ctx,
|
||||
const unsigned char * str,
|
||||
size_t length,
|
||||
int escape_solidus);
|
||||
|
||||
void yajl_string_decode(yajl_buf buf, const unsigned char * str,
|
||||
size_t length);
|
||||
|
||||
int yajl_string_validate_utf8(const unsigned char * s, size_t len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yajl_gen.h"
|
||||
#include "yajl_buf.h"
|
||||
#include "yajl_encode.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef enum {
|
||||
yajl_gen_start,
|
||||
yajl_gen_map_start,
|
||||
yajl_gen_map_key,
|
||||
yajl_gen_map_val,
|
||||
yajl_gen_array_start,
|
||||
yajl_gen_in_array,
|
||||
yajl_gen_complete,
|
||||
yajl_gen_error
|
||||
} yajl_gen_state;
|
||||
|
||||
struct yajl_gen_t
|
||||
{
|
||||
unsigned int flags;
|
||||
unsigned int depth;
|
||||
const char * indentString;
|
||||
yajl_gen_state state[YAJL_MAX_DEPTH];
|
||||
yajl_print_t print;
|
||||
void * ctx; /* yajl_buf */
|
||||
/* memory allocation routines */
|
||||
yajl_alloc_funcs alloc;
|
||||
};
|
||||
|
||||
int
|
||||
yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...)
|
||||
{
|
||||
int rv = 1;
|
||||
va_list ap;
|
||||
va_start(ap, opt);
|
||||
|
||||
switch(opt) {
|
||||
case yajl_gen_beautify:
|
||||
case yajl_gen_validate_utf8:
|
||||
case yajl_gen_escape_solidus:
|
||||
if (va_arg(ap, int)) g->flags |= opt;
|
||||
else g->flags &= ~opt;
|
||||
break;
|
||||
case yajl_gen_indent_string: {
|
||||
const char *indent = va_arg(ap, const char *);
|
||||
g->indentString = indent;
|
||||
for (; *indent; indent++) {
|
||||
if (*indent != '\n'
|
||||
&& *indent != '\v'
|
||||
&& *indent != '\f'
|
||||
&& *indent != '\t'
|
||||
&& *indent != '\r'
|
||||
&& *indent != ' ')
|
||||
{
|
||||
g->indentString = NULL;
|
||||
rv = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case yajl_gen_print_callback:
|
||||
yajl_buf_free(g->ctx);
|
||||
g->print = va_arg(ap, const yajl_print_t);
|
||||
g->ctx = va_arg(ap, void *);
|
||||
break;
|
||||
default:
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
yajl_gen
|
||||
yajl_gen_alloc(const yajl_alloc_funcs * afs)
|
||||
{
|
||||
yajl_gen g = NULL;
|
||||
yajl_alloc_funcs afsBuffer;
|
||||
|
||||
/* first order of business is to set up memory allocation routines */
|
||||
if (afs != NULL) {
|
||||
if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
yajl_set_default_alloc_funcs(&afsBuffer);
|
||||
afs = &afsBuffer;
|
||||
}
|
||||
|
||||
g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t));
|
||||
if (!g) return NULL;
|
||||
|
||||
memset((void *) g, 0, sizeof(struct yajl_gen_t));
|
||||
/* copy in pointers to allocation routines */
|
||||
memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
|
||||
|
||||
g->print = (yajl_print_t)&yajl_buf_append;
|
||||
g->ctx = yajl_buf_alloc(&(g->alloc));
|
||||
g->indentString = " ";
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_gen_free(yajl_gen g)
|
||||
{
|
||||
if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_free((yajl_buf)g->ctx);
|
||||
YA_FREE(&(g->alloc), g);
|
||||
}
|
||||
|
||||
#define INSERT_SEP \
|
||||
if (g->state[g->depth] == yajl_gen_map_key || \
|
||||
g->state[g->depth] == yajl_gen_in_array) { \
|
||||
g->print(g->ctx, ",", 1); \
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); \
|
||||
} else if (g->state[g->depth] == yajl_gen_map_val) { \
|
||||
g->print(g->ctx, ":", 1); \
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, " ", 1); \
|
||||
}
|
||||
|
||||
#define INSERT_WHITESPACE \
|
||||
if ((g->flags & yajl_gen_beautify)) { \
|
||||
if (g->state[g->depth] != yajl_gen_map_val) { \
|
||||
unsigned int _i; \
|
||||
for (_i=0;_i<g->depth;_i++) \
|
||||
g->print(g->ctx, \
|
||||
g->indentString, \
|
||||
(unsigned int)strlen(g->indentString)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENSURE_NOT_KEY \
|
||||
if (g->state[g->depth] == yajl_gen_map_key || \
|
||||
g->state[g->depth] == yajl_gen_map_start) { \
|
||||
return yajl_gen_keys_must_be_strings; \
|
||||
} \
|
||||
|
||||
/* check that we're not complete, or in error state. in a valid state
|
||||
* to be generating */
|
||||
#define ENSURE_VALID_STATE \
|
||||
if (g->state[g->depth] == yajl_gen_error) { \
|
||||
return yajl_gen_in_error_state;\
|
||||
} else if (g->state[g->depth] == yajl_gen_complete) { \
|
||||
return yajl_gen_generation_complete; \
|
||||
}
|
||||
|
||||
#define INCREMENT_DEPTH \
|
||||
if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded;
|
||||
|
||||
#define DECREMENT_DEPTH \
|
||||
if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_gen_invalid_string;
|
||||
|
||||
#define APPENDED_ATOM \
|
||||
switch (g->state[g->depth]) { \
|
||||
case yajl_gen_start: \
|
||||
g->state[g->depth] = yajl_gen_complete; \
|
||||
break; \
|
||||
case yajl_gen_map_start: \
|
||||
case yajl_gen_map_key: \
|
||||
g->state[g->depth] = yajl_gen_map_val; \
|
||||
break; \
|
||||
case yajl_gen_array_start: \
|
||||
g->state[g->depth] = yajl_gen_in_array; \
|
||||
break; \
|
||||
case yajl_gen_map_val: \
|
||||
g->state[g->depth] = yajl_gen_map_key; \
|
||||
break; \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
|
||||
#define FINAL_NEWLINE \
|
||||
if ((g->flags & yajl_gen_beautify) && g->state[g->depth] == yajl_gen_complete) \
|
||||
g->print(g->ctx, "\n", 1);
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_integer(yajl_gen g, long long int number)
|
||||
{
|
||||
char i[32];
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
sprintf(i, "%lld", number);
|
||||
g->print(g->ctx, i, (unsigned int)strlen(i));
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
# include <float.h>
|
||||
# ifndef isnan
|
||||
# define isnan _isnan
|
||||
# endif
|
||||
# ifndef isinf
|
||||
# define isinf !_finite
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__sun) && defined(__GNUC__) && __GNUC__ < 4
|
||||
# define isinf !finite
|
||||
#endif
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_double(yajl_gen g, double number)
|
||||
{
|
||||
char i[32];
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY;
|
||||
if (isnan(number) || isinf(number)) return yajl_gen_invalid_number;
|
||||
INSERT_SEP; INSERT_WHITESPACE;
|
||||
sprintf(i, "%.20g", number);
|
||||
if (strspn(i, "0123456789-") == strlen(i)) {
|
||||
strcat(i, ".0");
|
||||
}
|
||||
g->print(g->ctx, i, (unsigned int)strlen(i));
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_number(yajl_gen g, const char * s, size_t l)
|
||||
{
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
g->print(g->ctx, s, l);
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_string(yajl_gen g, const unsigned char * str,
|
||||
size_t len)
|
||||
{
|
||||
// if validation is enabled, check that the string is valid utf8
|
||||
// XXX: This checking could be done a little faster, in the same pass as
|
||||
// the string encoding
|
||||
if (g->flags & yajl_gen_validate_utf8) {
|
||||
if (!yajl_string_validate_utf8(str, len)) {
|
||||
return yajl_gen_invalid_string;
|
||||
}
|
||||
}
|
||||
ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE;
|
||||
g->print(g->ctx, "\"", 1);
|
||||
yajl_string_encode(g->print, g->ctx, str, len, g->flags & yajl_gen_escape_solidus);
|
||||
g->print(g->ctx, "\"", 1);
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_null(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
g->print(g->ctx, "null", strlen("null"));
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_bool(yajl_gen g, int boolean)
|
||||
{
|
||||
const char * val = boolean ? "true" : "false";
|
||||
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
g->print(g->ctx, val, (unsigned int)strlen(val));
|
||||
APPENDED_ATOM;
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_map_open(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
INCREMENT_DEPTH;
|
||||
|
||||
g->state[g->depth] = yajl_gen_map_start;
|
||||
g->print(g->ctx, "{", 1);
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_map_close(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE;
|
||||
DECREMENT_DEPTH;
|
||||
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
|
||||
APPENDED_ATOM;
|
||||
INSERT_WHITESPACE;
|
||||
g->print(g->ctx, "}", 1);
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_array_open(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
||||
INCREMENT_DEPTH;
|
||||
g->state[g->depth] = yajl_gen_array_start;
|
||||
g->print(g->ctx, "[", 1);
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_array_close(yajl_gen g)
|
||||
{
|
||||
ENSURE_VALID_STATE;
|
||||
DECREMENT_DEPTH;
|
||||
if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
|
||||
APPENDED_ATOM;
|
||||
INSERT_WHITESPACE;
|
||||
g->print(g->ctx, "]", 1);
|
||||
FINAL_NEWLINE;
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
yajl_gen_status
|
||||
yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf,
|
||||
size_t * len)
|
||||
{
|
||||
if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf;
|
||||
*buf = yajl_buf_data((yajl_buf)g->ctx);
|
||||
*len = yajl_buf_len((yajl_buf)g->ctx);
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_gen_clear(yajl_gen g)
|
||||
{
|
||||
if (g->print == (yajl_print_t)&yajl_buf_append) yajl_buf_clear((yajl_buf)g->ctx);
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_gen.h
|
||||
* Interface to YAJL's JSON generation facilities.
|
||||
*/
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
#ifndef __YAJL_GEN_H__
|
||||
#define __YAJL_GEN_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/** generator status codes */
|
||||
typedef enum {
|
||||
/** no error */
|
||||
yajl_gen_status_ok = 0,
|
||||
/** at a point where a map key is generated, a function other than
|
||||
* yajl_gen_string was called */
|
||||
yajl_gen_keys_must_be_strings,
|
||||
/** YAJL's maximum generation depth was exceeded. see
|
||||
* YAJL_MAX_DEPTH */
|
||||
yajl_max_depth_exceeded,
|
||||
/** A generator function (yajl_gen_XXX) was called while in an error
|
||||
* state */
|
||||
yajl_gen_in_error_state,
|
||||
/** A complete JSON document has been generated */
|
||||
yajl_gen_generation_complete,
|
||||
/** yajl_gen_double was passed an invalid floating point value
|
||||
* (infinity or NaN). */
|
||||
yajl_gen_invalid_number,
|
||||
/** A print callback was passed in, so there is no internal
|
||||
* buffer to get from */
|
||||
yajl_gen_no_buf,
|
||||
/** returned from yajl_gen_string() when the yajl_gen_validate_utf8
|
||||
* option is enabled and an invalid was passed by client code.
|
||||
*/
|
||||
yajl_gen_invalid_string
|
||||
} yajl_gen_status;
|
||||
|
||||
/** an opaque handle to a generator */
|
||||
typedef struct yajl_gen_t * yajl_gen;
|
||||
|
||||
/** a callback used for "printing" the results. */
|
||||
typedef void (*yajl_print_t)(void * ctx,
|
||||
const char * str,
|
||||
size_t len);
|
||||
|
||||
/** configuration parameters for the parser, these may be passed to
|
||||
* yajl_gen_config() along with option specific argument(s). In general,
|
||||
* all configuration parameters default to *off*. */
|
||||
typedef enum {
|
||||
/** generate indented (beautiful) output */
|
||||
yajl_gen_beautify = 0x01,
|
||||
/**
|
||||
* Set an indent string which is used when yajl_gen_beautify
|
||||
* is enabled. Maybe something like \\t or some number of
|
||||
* spaces. The default is four spaces ' '.
|
||||
*/
|
||||
yajl_gen_indent_string = 0x02,
|
||||
/**
|
||||
* Set a function and context argument that should be used to
|
||||
* output generated json. the function should conform to the
|
||||
* yajl_print_t prototype while the context argument is a
|
||||
* void * of your choosing.
|
||||
*
|
||||
* example:
|
||||
* yajl_gen_config(g, yajl_gen_print_callback, myFunc, myVoidPtr);
|
||||
*/
|
||||
yajl_gen_print_callback = 0x04,
|
||||
/**
|
||||
* Normally the generator does not validate that strings you
|
||||
* pass to it via yajl_gen_string() are valid UTF8. Enabling
|
||||
* this option will cause it to do so.
|
||||
*/
|
||||
yajl_gen_validate_utf8 = 0x08,
|
||||
/**
|
||||
* the forward solidus (slash or '/' in human) is not required to be
|
||||
* escaped in json text. By default, YAJL will not escape it in the
|
||||
* iterest of saving bytes. Setting this flag will cause YAJL to
|
||||
* always escape '/' in generated JSON strings.
|
||||
*/
|
||||
yajl_gen_escape_solidus = 0x10
|
||||
} yajl_gen_option;
|
||||
|
||||
/** allow the modification of generator options subsequent to handle
|
||||
* allocation (via yajl_alloc)
|
||||
* \returns zero in case of errors, non-zero otherwise
|
||||
*/
|
||||
YAJL_API int yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...);
|
||||
|
||||
/** allocate a generator handle
|
||||
* \param allocFuncs an optional pointer to a structure which allows
|
||||
* the client to overide the memory allocation
|
||||
* used by yajl. May be NULL, in which case
|
||||
* malloc/free/realloc will be used.
|
||||
*
|
||||
* \returns an allocated handle on success, NULL on failure (bad params)
|
||||
*/
|
||||
YAJL_API yajl_gen yajl_gen_alloc(const yajl_alloc_funcs * allocFuncs);
|
||||
|
||||
/** free a generator handle */
|
||||
YAJL_API void yajl_gen_free(yajl_gen handle);
|
||||
|
||||
YAJL_API yajl_gen_status yajl_gen_integer(yajl_gen hand, long long int number);
|
||||
/** generate a floating point number. number may not be infinity or
|
||||
* NaN, as these have no representation in JSON. In these cases the
|
||||
* generator will return 'yajl_gen_invalid_number' */
|
||||
YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number);
|
||||
YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand,
|
||||
const char * num,
|
||||
size_t len);
|
||||
YAJL_API yajl_gen_status yajl_gen_string(yajl_gen hand,
|
||||
const unsigned char * str,
|
||||
size_t len);
|
||||
YAJL_API yajl_gen_status yajl_gen_null(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_bool(yajl_gen hand, int boolean);
|
||||
YAJL_API yajl_gen_status yajl_gen_map_open(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_map_close(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_array_open(yajl_gen hand);
|
||||
YAJL_API yajl_gen_status yajl_gen_array_close(yajl_gen hand);
|
||||
|
||||
/** access the null terminated generator buffer. If incrementally
|
||||
* outputing JSON, one should call yajl_gen_clear to clear the
|
||||
* buffer. This allows stream generation. */
|
||||
YAJL_API yajl_gen_status yajl_gen_get_buf(yajl_gen hand,
|
||||
const unsigned char ** buf,
|
||||
size_t * len);
|
||||
|
||||
/** clear yajl's output buffer, but maintain all internal generation
|
||||
* state. This function will not "reset" the generator state, and is
|
||||
* intended to enable incremental JSON outputing. */
|
||||
YAJL_API void yajl_gen_clear(yajl_gen hand);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,763 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yajl_lex.h"
|
||||
#include "yajl_buf.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef YAJL_LEXER_DEBUG
|
||||
static const char *
|
||||
tokToStr(yajl_tok tok)
|
||||
{
|
||||
switch (tok) {
|
||||
case yajl_tok_bool: return "bool";
|
||||
case yajl_tok_colon: return "colon";
|
||||
case yajl_tok_comma: return "comma";
|
||||
case yajl_tok_eof: return "eof";
|
||||
case yajl_tok_error: return "error";
|
||||
case yajl_tok_left_brace: return "brace";
|
||||
case yajl_tok_left_bracket: return "bracket";
|
||||
case yajl_tok_null: return "null";
|
||||
case yajl_tok_integer: return "integer";
|
||||
case yajl_tok_double: return "double";
|
||||
case yajl_tok_right_brace: return "brace";
|
||||
case yajl_tok_right_bracket: return "bracket";
|
||||
case yajl_tok_string: return "string";
|
||||
case yajl_tok_string_with_escapes: return "string_with_escapes";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Impact of the stream parsing feature on the lexer:
|
||||
*
|
||||
* YAJL support stream parsing. That is, the ability to parse the first
|
||||
* bits of a chunk of JSON before the last bits are available (still on
|
||||
* the network or disk). This makes the lexer more complex. The
|
||||
* responsibility of the lexer is to handle transparently the case where
|
||||
* a chunk boundary falls in the middle of a token. This is
|
||||
* accomplished is via a buffer and a character reading abstraction.
|
||||
*
|
||||
* Overview of implementation
|
||||
*
|
||||
* When we lex to end of input string before end of token is hit, we
|
||||
* copy all of the input text composing the token into our lexBuf.
|
||||
*
|
||||
* Every time we read a character, we do so through the readChar function.
|
||||
* readChar's responsibility is to handle pulling all chars from the buffer
|
||||
* before pulling chars from input text
|
||||
*/
|
||||
|
||||
struct yajl_lexer_t {
|
||||
/* the overal line and char offset into the data */
|
||||
size_t lineOff;
|
||||
size_t charOff;
|
||||
|
||||
/* error */
|
||||
yajl_lex_error error;
|
||||
|
||||
/* a input buffer to handle the case where a token is spread over
|
||||
* multiple chunks */
|
||||
yajl_buf buf;
|
||||
|
||||
/* in the case where we have data in the lexBuf, bufOff holds
|
||||
* the current offset into the lexBuf. */
|
||||
size_t bufOff;
|
||||
|
||||
/* are we using the lex buf? */
|
||||
unsigned int bufInUse;
|
||||
|
||||
/* shall we allow comments? */
|
||||
unsigned int allowComments;
|
||||
|
||||
/* shall we validate utf8 inside strings? */
|
||||
unsigned int validateUTF8;
|
||||
|
||||
yajl_alloc_funcs * alloc;
|
||||
};
|
||||
|
||||
#define readChar(lxr, txt, off) \
|
||||
(((lxr)->bufInUse && yajl_buf_len((lxr)->buf) && lxr->bufOff < yajl_buf_len((lxr)->buf)) ? \
|
||||
(*((const unsigned char *) yajl_buf_data((lxr)->buf) + ((lxr)->bufOff)++)) : \
|
||||
((txt)[(*(off))++]))
|
||||
|
||||
#define unreadChar(lxr, off) ((*(off) > 0) ? (*(off))-- : ((lxr)->bufOff--))
|
||||
|
||||
yajl_lexer
|
||||
yajl_lex_alloc(yajl_alloc_funcs * alloc,
|
||||
unsigned int allowComments, unsigned int validateUTF8)
|
||||
{
|
||||
yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t));
|
||||
memset((void *) lxr, 0, sizeof(struct yajl_lexer_t));
|
||||
lxr->buf = yajl_buf_alloc(alloc);
|
||||
lxr->allowComments = allowComments;
|
||||
lxr->validateUTF8 = validateUTF8;
|
||||
lxr->alloc = alloc;
|
||||
return lxr;
|
||||
}
|
||||
|
||||
void
|
||||
yajl_lex_free(yajl_lexer lxr)
|
||||
{
|
||||
yajl_buf_free(lxr->buf);
|
||||
YA_FREE(lxr->alloc, lxr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* a lookup table which lets us quickly determine three things:
|
||||
* VEC - valid escaped control char
|
||||
* note. the solidus '/' may be escaped or not.
|
||||
* IJC - invalid json char
|
||||
* VHC - valid hex char
|
||||
* NFP - needs further processing (from a string scanning perspective)
|
||||
* NUC - needs utf8 checking when enabled (from a string scanning perspective)
|
||||
*/
|
||||
#define VEC 0x01
|
||||
#define IJC 0x02
|
||||
#define VHC 0x04
|
||||
#define NFP 0x08
|
||||
#define NUC 0x10
|
||||
|
||||
static const char charLookupTable[256] =
|
||||
{
|
||||
/*00*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
|
||||
/*08*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
|
||||
/*10*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
|
||||
/*18*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
|
||||
|
||||
/*20*/ 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 , 0 , 0 ,
|
||||
/*28*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , VEC ,
|
||||
/*30*/ VHC , VHC , VHC , VHC , VHC , VHC , VHC , VHC ,
|
||||
/*38*/ VHC , VHC , 0 , 0 , 0 , 0 , 0 , 0 ,
|
||||
|
||||
/*40*/ 0 , VHC , VHC , VHC , VHC , VHC , VHC , 0 ,
|
||||
/*48*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
|
||||
/*50*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
|
||||
/*58*/ 0 , 0 , 0 , 0 , NFP|VEC|IJC, 0 , 0 , 0 ,
|
||||
|
||||
/*60*/ 0 , VHC , VEC|VHC, VHC , VHC , VHC , VEC|VHC, 0 ,
|
||||
/*68*/ 0 , 0 , 0 , 0 , 0 , 0 , VEC , 0 ,
|
||||
/*70*/ 0 , 0 , VEC , 0 , VEC , 0 , 0 , 0 ,
|
||||
/*78*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
|
||||
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC ,
|
||||
NUC , NUC , NUC , NUC , NUC , NUC , NUC , NUC
|
||||
};
|
||||
|
||||
/** process a variable length utf8 encoded codepoint.
|
||||
*
|
||||
* returns:
|
||||
* yajl_tok_string - if valid utf8 char was parsed and offset was
|
||||
* advanced
|
||||
* yajl_tok_eof - if end of input was hit before validation could
|
||||
* complete
|
||||
* yajl_tok_error - if invalid utf8 was encountered
|
||||
*
|
||||
* NOTE: on error the offset will point to the first char of the
|
||||
* invalid utf8 */
|
||||
#define UTF8_CHECK_EOF if (*offset >= jsonTextLen) { return yajl_tok_eof; }
|
||||
|
||||
static yajl_tok
|
||||
yajl_lex_utf8_char(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset,
|
||||
unsigned char curChar)
|
||||
{
|
||||
if (curChar <= 0x7f) {
|
||||
/* single byte */
|
||||
return yajl_tok_string;
|
||||
} else if ((curChar >> 5) == 0x6) {
|
||||
/* two byte */
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) return yajl_tok_string;
|
||||
} else if ((curChar >> 4) == 0x0e) {
|
||||
/* three byte */
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) {
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) return yajl_tok_string;
|
||||
}
|
||||
} else if ((curChar >> 3) == 0x1e) {
|
||||
/* four byte */
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) {
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) {
|
||||
UTF8_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if ((curChar >> 6) == 0x2) return yajl_tok_string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return yajl_tok_error;
|
||||
}
|
||||
|
||||
/* lex a string. input is the lexer, pointer to beginning of
|
||||
* json text, and start of string (offset).
|
||||
* a token is returned which has the following meanings:
|
||||
* yajl_tok_string: lex of string was successful. offset points to
|
||||
* terminating '"'.
|
||||
* yajl_tok_eof: end of text was encountered before we could complete
|
||||
* the lex.
|
||||
* yajl_tok_error: embedded in the string were unallowable chars. offset
|
||||
* points to the offending char
|
||||
*/
|
||||
#define STR_CHECK_EOF \
|
||||
if (*offset >= jsonTextLen) { \
|
||||
tok = yajl_tok_eof; \
|
||||
goto finish_string_lex; \
|
||||
}
|
||||
|
||||
/** scan a string for interesting characters that might need further
|
||||
* review. return the number of chars that are uninteresting and can
|
||||
* be skipped.
|
||||
* (lth) hi world, any thoughts on how to make this routine faster? */
|
||||
static size_t
|
||||
yajl_string_scan(const unsigned char * buf, size_t len, int utf8check)
|
||||
{
|
||||
unsigned char mask = IJC|NFP|(utf8check ? NUC : 0);
|
||||
size_t skip = 0;
|
||||
while (skip < len && !(charLookupTable[*buf] & mask))
|
||||
{
|
||||
skip++;
|
||||
buf++;
|
||||
}
|
||||
return skip;
|
||||
}
|
||||
|
||||
static yajl_tok
|
||||
yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset)
|
||||
{
|
||||
yajl_tok tok = yajl_tok_error;
|
||||
int hasEscapes = 0;
|
||||
|
||||
for (;;) {
|
||||
unsigned char curChar;
|
||||
|
||||
/* now jump into a faster scanning routine to skip as much
|
||||
* of the buffers as possible */
|
||||
{
|
||||
const unsigned char * p;
|
||||
size_t len;
|
||||
|
||||
if ((lexer->bufInUse && yajl_buf_len(lexer->buf) &&
|
||||
lexer->bufOff < yajl_buf_len(lexer->buf)))
|
||||
{
|
||||
p = ((const unsigned char *) yajl_buf_data(lexer->buf) +
|
||||
(lexer->bufOff));
|
||||
len = yajl_buf_len(lexer->buf) - lexer->bufOff;
|
||||
lexer->bufOff += yajl_string_scan(p, len, lexer->validateUTF8);
|
||||
}
|
||||
else if (*offset < jsonTextLen)
|
||||
{
|
||||
p = jsonText + *offset;
|
||||
len = jsonTextLen - *offset;
|
||||
*offset += yajl_string_scan(p, len, lexer->validateUTF8);
|
||||
}
|
||||
}
|
||||
|
||||
STR_CHECK_EOF;
|
||||
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
|
||||
/* quote terminates */
|
||||
if (curChar == '"') {
|
||||
tok = yajl_tok_string;
|
||||
break;
|
||||
}
|
||||
/* backslash escapes a set of control chars, */
|
||||
else if (curChar == '\\') {
|
||||
hasEscapes = 1;
|
||||
STR_CHECK_EOF;
|
||||
|
||||
/* special case \u */
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if (curChar == 'u') {
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i=0;i<4;i++) {
|
||||
STR_CHECK_EOF;
|
||||
curChar = readChar(lexer, jsonText, offset);
|
||||
if (!(charLookupTable[curChar] & VHC)) {
|
||||
/* back up to offending char */
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_string_invalid_hex_char;
|
||||
goto finish_string_lex;
|
||||
}
|
||||
}
|
||||
} else if (!(charLookupTable[curChar] & VEC)) {
|
||||
/* back up to offending char */
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_string_invalid_escaped_char;
|
||||
goto finish_string_lex;
|
||||
}
|
||||
}
|
||||
/* when not validating UTF8 it's a simple table lookup to determine
|
||||
* if the present character is invalid */
|
||||
else if(charLookupTable[curChar] & IJC) {
|
||||
/* back up to offending char */
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_string_invalid_json_char;
|
||||
goto finish_string_lex;
|
||||
}
|
||||
/* when in validate UTF8 mode we need to do some extra work */
|
||||
else if (lexer->validateUTF8) {
|
||||
yajl_tok t = yajl_lex_utf8_char(lexer, jsonText, jsonTextLen,
|
||||
offset, curChar);
|
||||
|
||||
if (t == yajl_tok_eof) {
|
||||
tok = yajl_tok_eof;
|
||||
goto finish_string_lex;
|
||||
} else if (t == yajl_tok_error) {
|
||||
lexer->error = yajl_lex_string_invalid_utf8;
|
||||
goto finish_string_lex;
|
||||
}
|
||||
}
|
||||
/* accept it, and move on */
|
||||
}
|
||||
finish_string_lex:
|
||||
/* tell our buddy, the parser, wether he needs to process this string
|
||||
* again */
|
||||
if (hasEscapes && tok == yajl_tok_string) {
|
||||
tok = yajl_tok_string_with_escapes;
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
#define RETURN_IF_EOF if (*offset >= jsonTextLen) return yajl_tok_eof;
|
||||
|
||||
static yajl_tok
|
||||
yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset)
|
||||
{
|
||||
/** XXX: numbers are the only entities in json that we must lex
|
||||
* _beyond_ in order to know that they are complete. There
|
||||
* is an ambiguous case for integers at EOF. */
|
||||
|
||||
unsigned char c;
|
||||
|
||||
yajl_tok tok = yajl_tok_integer;
|
||||
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
/* optional leading minus */
|
||||
if (c == '-') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
}
|
||||
|
||||
/* a single zero, or a series of integers */
|
||||
if (c == '0') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
} else if (c >= '1' && c <= '9') {
|
||||
do {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
} while (c >= '0' && c <= '9');
|
||||
} else {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_missing_integer_after_minus;
|
||||
return yajl_tok_error;
|
||||
}
|
||||
|
||||
/* optional fraction (indicates this is floating point) */
|
||||
if (c == '.') {
|
||||
int numRd = 0;
|
||||
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
while (c >= '0' && c <= '9') {
|
||||
numRd++;
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
}
|
||||
|
||||
if (!numRd) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_missing_integer_after_decimal;
|
||||
return yajl_tok_error;
|
||||
}
|
||||
tok = yajl_tok_double;
|
||||
}
|
||||
|
||||
/* optional exponent (indicates this is floating point) */
|
||||
if (c == 'e' || c == 'E') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
/* optional sign */
|
||||
if (c == '+' || c == '-') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
}
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
do {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
} while (c >= '0' && c <= '9');
|
||||
} else {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_missing_integer_after_exponent;
|
||||
return yajl_tok_error;
|
||||
}
|
||||
tok = yajl_tok_double;
|
||||
}
|
||||
|
||||
/* we always go "one too far" */
|
||||
unreadChar(lexer, offset);
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
static yajl_tok
|
||||
yajl_lex_comment(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset)
|
||||
{
|
||||
unsigned char c;
|
||||
|
||||
yajl_tok tok = yajl_tok_comment;
|
||||
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
/* either slash or star expected */
|
||||
if (c == '/') {
|
||||
/* now we throw away until end of line */
|
||||
do {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
} while (c != '\n');
|
||||
} else if (c == '*') {
|
||||
/* now we throw away until end of comment */
|
||||
for (;;) {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c == '*') {
|
||||
RETURN_IF_EOF;
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c == '/') {
|
||||
break;
|
||||
} else {
|
||||
unreadChar(lexer, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lexer->error = yajl_lex_invalid_char;
|
||||
tok = yajl_tok_error;
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
yajl_tok
|
||||
yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset,
|
||||
const unsigned char ** outBuf, size_t * outLen)
|
||||
{
|
||||
yajl_tok tok = yajl_tok_error;
|
||||
unsigned char c;
|
||||
size_t startOffset = *offset;
|
||||
|
||||
*outBuf = NULL;
|
||||
*outLen = 0;
|
||||
|
||||
for (;;) {
|
||||
assert(*offset <= jsonTextLen);
|
||||
|
||||
if (*offset >= jsonTextLen) {
|
||||
tok = yajl_tok_eof;
|
||||
goto lexed;
|
||||
}
|
||||
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
|
||||
switch (c) {
|
||||
case '{':
|
||||
tok = yajl_tok_left_bracket;
|
||||
goto lexed;
|
||||
case '}':
|
||||
tok = yajl_tok_right_bracket;
|
||||
goto lexed;
|
||||
case '[':
|
||||
tok = yajl_tok_left_brace;
|
||||
goto lexed;
|
||||
case ']':
|
||||
tok = yajl_tok_right_brace;
|
||||
goto lexed;
|
||||
case ',':
|
||||
tok = yajl_tok_comma;
|
||||
goto lexed;
|
||||
case ':':
|
||||
tok = yajl_tok_colon;
|
||||
goto lexed;
|
||||
case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
|
||||
startOffset++;
|
||||
break;
|
||||
case 't': {
|
||||
const char * want = "rue";
|
||||
do {
|
||||
if (*offset >= jsonTextLen) {
|
||||
tok = yajl_tok_eof;
|
||||
goto lexed;
|
||||
}
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c != *want) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_invalid_string;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
} while (*(++want));
|
||||
tok = yajl_tok_bool;
|
||||
goto lexed;
|
||||
}
|
||||
case 'f': {
|
||||
const char * want = "alse";
|
||||
do {
|
||||
if (*offset >= jsonTextLen) {
|
||||
tok = yajl_tok_eof;
|
||||
goto lexed;
|
||||
}
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c != *want) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_invalid_string;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
} while (*(++want));
|
||||
tok = yajl_tok_bool;
|
||||
goto lexed;
|
||||
}
|
||||
case 'n': {
|
||||
const char * want = "ull";
|
||||
do {
|
||||
if (*offset >= jsonTextLen) {
|
||||
tok = yajl_tok_eof;
|
||||
goto lexed;
|
||||
}
|
||||
c = readChar(lexer, jsonText, offset);
|
||||
if (c != *want) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_invalid_string;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
} while (*(++want));
|
||||
tok = yajl_tok_null;
|
||||
goto lexed;
|
||||
}
|
||||
case '"': {
|
||||
tok = yajl_lex_string(lexer, (const unsigned char *) jsonText,
|
||||
jsonTextLen, offset);
|
||||
goto lexed;
|
||||
}
|
||||
case '-':
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9': {
|
||||
/* integer parsing wants to start from the beginning */
|
||||
unreadChar(lexer, offset);
|
||||
tok = yajl_lex_number(lexer, (const unsigned char *) jsonText,
|
||||
jsonTextLen, offset);
|
||||
goto lexed;
|
||||
}
|
||||
case '/':
|
||||
/* hey, look, a probable comment! If comments are disabled
|
||||
* it's an error. */
|
||||
if (!lexer->allowComments) {
|
||||
unreadChar(lexer, offset);
|
||||
lexer->error = yajl_lex_unallowed_comment;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
/* if comments are enabled, then we should try to lex
|
||||
* the thing. possible outcomes are
|
||||
* - successful lex (tok_comment, which means continue),
|
||||
* - malformed comment opening (slash not followed by
|
||||
* '*' or '/') (tok_error)
|
||||
* - eof hit. (tok_eof) */
|
||||
tok = yajl_lex_comment(lexer, (const unsigned char *) jsonText,
|
||||
jsonTextLen, offset);
|
||||
if (tok == yajl_tok_comment) {
|
||||
/* "error" is silly, but that's the initial
|
||||
* state of tok. guilty until proven innocent. */
|
||||
tok = yajl_tok_error;
|
||||
yajl_buf_clear(lexer->buf);
|
||||
lexer->bufInUse = 0;
|
||||
startOffset = *offset;
|
||||
break;
|
||||
}
|
||||
/* hit error or eof, bail */
|
||||
goto lexed;
|
||||
default:
|
||||
lexer->error = yajl_lex_invalid_char;
|
||||
tok = yajl_tok_error;
|
||||
goto lexed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lexed:
|
||||
/* need to append to buffer if the buffer is in use or
|
||||
* if it's an EOF token */
|
||||
if (tok == yajl_tok_eof || lexer->bufInUse) {
|
||||
if (!lexer->bufInUse) yajl_buf_clear(lexer->buf);
|
||||
lexer->bufInUse = 1;
|
||||
yajl_buf_append(lexer->buf, jsonText + startOffset, *offset - startOffset);
|
||||
lexer->bufOff = 0;
|
||||
|
||||
if (tok != yajl_tok_eof) {
|
||||
*outBuf = yajl_buf_data(lexer->buf);
|
||||
*outLen = yajl_buf_len(lexer->buf);
|
||||
lexer->bufInUse = 0;
|
||||
}
|
||||
} else if (tok != yajl_tok_error) {
|
||||
*outBuf = jsonText + startOffset;
|
||||
*outLen = *offset - startOffset;
|
||||
}
|
||||
|
||||
/* special case for strings. skip the quotes. */
|
||||
if (tok == yajl_tok_string || tok == yajl_tok_string_with_escapes)
|
||||
{
|
||||
assert(*outLen >= 2);
|
||||
(*outBuf)++;
|
||||
*outLen -= 2;
|
||||
}
|
||||
|
||||
|
||||
#ifdef YAJL_LEXER_DEBUG
|
||||
if (tok == yajl_tok_error) {
|
||||
printf("lexical error: %s\n",
|
||||
yajl_lex_error_to_string(yajl_lex_get_error(lexer)));
|
||||
} else if (tok == yajl_tok_eof) {
|
||||
printf("EOF hit\n");
|
||||
} else {
|
||||
printf("lexed %s: '", tokToStr(tok));
|
||||
fwrite(*outBuf, 1, *outLen, stdout);
|
||||
printf("'\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
const char *
|
||||
yajl_lex_error_to_string(yajl_lex_error error)
|
||||
{
|
||||
switch (error) {
|
||||
case yajl_lex_e_ok:
|
||||
return "ok, no error";
|
||||
case yajl_lex_string_invalid_utf8:
|
||||
return "invalid bytes in UTF8 string.";
|
||||
case yajl_lex_string_invalid_escaped_char:
|
||||
return "inside a string, '\\' occurs before a character "
|
||||
"which it may not.";
|
||||
case yajl_lex_string_invalid_json_char:
|
||||
return "invalid character inside string.";
|
||||
case yajl_lex_string_invalid_hex_char:
|
||||
return "invalid (non-hex) character occurs after '\\u' inside "
|
||||
"string.";
|
||||
case yajl_lex_invalid_char:
|
||||
return "invalid char in json text.";
|
||||
case yajl_lex_invalid_string:
|
||||
return "invalid string in json text.";
|
||||
case yajl_lex_missing_integer_after_exponent:
|
||||
return "malformed number, a digit is required after the exponent.";
|
||||
case yajl_lex_missing_integer_after_decimal:
|
||||
return "malformed number, a digit is required after the "
|
||||
"decimal point.";
|
||||
case yajl_lex_missing_integer_after_minus:
|
||||
return "malformed number, a digit is required after the "
|
||||
"minus sign.";
|
||||
case yajl_lex_unallowed_comment:
|
||||
return "probable comment found in input text, comments are "
|
||||
"not enabled.";
|
||||
}
|
||||
return "unknown error code";
|
||||
}
|
||||
|
||||
|
||||
/** allows access to more specific information about the lexical
|
||||
* error when yajl_lex_lex returns yajl_tok_error. */
|
||||
yajl_lex_error
|
||||
yajl_lex_get_error(yajl_lexer lexer)
|
||||
{
|
||||
if (lexer == NULL) return (yajl_lex_error) -1;
|
||||
return lexer->error;
|
||||
}
|
||||
|
||||
size_t yajl_lex_current_line(yajl_lexer lexer)
|
||||
{
|
||||
return lexer->lineOff;
|
||||
}
|
||||
|
||||
size_t yajl_lex_current_char(yajl_lexer lexer)
|
||||
{
|
||||
return lexer->charOff;
|
||||
}
|
||||
|
||||
yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t offset)
|
||||
{
|
||||
const unsigned char * outBuf;
|
||||
size_t outLen;
|
||||
size_t bufLen = yajl_buf_len(lexer->buf);
|
||||
size_t bufOff = lexer->bufOff;
|
||||
unsigned int bufInUse = lexer->bufInUse;
|
||||
yajl_tok tok;
|
||||
|
||||
tok = yajl_lex_lex(lexer, jsonText, jsonTextLen, &offset,
|
||||
&outBuf, &outLen);
|
||||
|
||||
lexer->bufOff = bufOff;
|
||||
lexer->bufInUse = bufInUse;
|
||||
yajl_buf_truncate(lexer->buf, bufLen);
|
||||
|
||||
return tok;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_LEX_H__
|
||||
#define __YAJL_LEX_H__
|
||||
|
||||
#include "yajl_common.h"
|
||||
|
||||
typedef enum {
|
||||
yajl_tok_bool,
|
||||
yajl_tok_colon,
|
||||
yajl_tok_comma,
|
||||
yajl_tok_eof,
|
||||
yajl_tok_error,
|
||||
yajl_tok_left_brace,
|
||||
yajl_tok_left_bracket,
|
||||
yajl_tok_null,
|
||||
yajl_tok_right_brace,
|
||||
yajl_tok_right_bracket,
|
||||
|
||||
/* we differentiate between integers and doubles to allow the
|
||||
* parser to interpret the number without re-scanning */
|
||||
yajl_tok_integer,
|
||||
yajl_tok_double,
|
||||
|
||||
/* we differentiate between strings which require further processing,
|
||||
* and strings that do not */
|
||||
yajl_tok_string,
|
||||
yajl_tok_string_with_escapes,
|
||||
|
||||
/* comment tokens are not currently returned to the parser, ever */
|
||||
yajl_tok_comment
|
||||
} yajl_tok;
|
||||
|
||||
typedef struct yajl_lexer_t * yajl_lexer;
|
||||
|
||||
yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc,
|
||||
unsigned int allowComments,
|
||||
unsigned int validateUTF8);
|
||||
|
||||
void yajl_lex_free(yajl_lexer lexer);
|
||||
|
||||
/**
|
||||
* run/continue a lex. "offset" is an input/output parameter.
|
||||
* It should be initialized to zero for a
|
||||
* new chunk of target text, and upon subsetquent calls with the same
|
||||
* target text should passed with the value of the previous invocation.
|
||||
*
|
||||
* the client may be interested in the value of offset when an error is
|
||||
* returned from the lexer. This allows the client to render useful
|
||||
n * error messages.
|
||||
*
|
||||
* When you pass the next chunk of data, context should be reinitialized
|
||||
* to zero.
|
||||
*
|
||||
* Finally, the output buffer is usually just a pointer into the jsonText,
|
||||
* however in cases where the entity being lexed spans multiple chunks,
|
||||
* the lexer will buffer the entity and the data returned will be
|
||||
* a pointer into that buffer.
|
||||
*
|
||||
* This behavior is abstracted from client code except for the performance
|
||||
* implications which require that the client choose a reasonable chunk
|
||||
* size to get adequate performance.
|
||||
*/
|
||||
yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t * offset,
|
||||
const unsigned char ** outBuf, size_t * outLen);
|
||||
|
||||
/** have a peek at the next token, but don't move the lexer forward */
|
||||
yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, size_t offset);
|
||||
|
||||
|
||||
typedef enum {
|
||||
yajl_lex_e_ok = 0,
|
||||
yajl_lex_string_invalid_utf8,
|
||||
yajl_lex_string_invalid_escaped_char,
|
||||
yajl_lex_string_invalid_json_char,
|
||||
yajl_lex_string_invalid_hex_char,
|
||||
yajl_lex_invalid_char,
|
||||
yajl_lex_invalid_string,
|
||||
yajl_lex_missing_integer_after_decimal,
|
||||
yajl_lex_missing_integer_after_exponent,
|
||||
yajl_lex_missing_integer_after_minus,
|
||||
yajl_lex_unallowed_comment
|
||||
} yajl_lex_error;
|
||||
|
||||
const char * yajl_lex_error_to_string(yajl_lex_error error);
|
||||
|
||||
/** allows access to more specific information about the lexical
|
||||
* error when yajl_lex_lex returns yajl_tok_error. */
|
||||
yajl_lex_error yajl_lex_get_error(yajl_lexer lexer);
|
||||
|
||||
/** get the current offset into the most recently lexed json string. */
|
||||
size_t yajl_lex_current_offset(yajl_lexer lexer);
|
||||
|
||||
/** get the number of lines lexed by this lexer instance */
|
||||
size_t yajl_lex_current_line(yajl_lexer lexer);
|
||||
|
||||
/** get the number of chars lexed by this lexer instance since the last
|
||||
* \n or \r */
|
||||
size_t yajl_lex_current_char(yajl_lexer lexer);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_parse.h
|
||||
* Interface to YAJL's JSON stream parsing facilities.
|
||||
*/
|
||||
|
||||
#include "bson-compat.h"
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
#ifndef __YAJL_PARSE_H__
|
||||
#define __YAJL_PARSE_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/** error codes returned from this interface */
|
||||
typedef enum {
|
||||
/** no error was encountered */
|
||||
yajl_status_ok,
|
||||
/** a client callback returned zero, stopping the parse */
|
||||
yajl_status_client_canceled,
|
||||
/** An error occured during the parse. Call yajl_get_error for
|
||||
* more information about the encountered error */
|
||||
yajl_status_error
|
||||
} yajl_status;
|
||||
|
||||
/** attain a human readable, english, string for an error */
|
||||
YAJL_API const char * yajl_status_to_string(yajl_status code);
|
||||
|
||||
/** an opaque handle to a parser */
|
||||
typedef struct yajl_handle_t * yajl_handle;
|
||||
|
||||
/** yajl is an event driven parser. this means as json elements are
|
||||
* parsed, you are called back to do something with the data. The
|
||||
* functions in this table indicate the various events for which
|
||||
* you will be called back. Each callback accepts a "context"
|
||||
* pointer, this is a void * that is passed into the yajl_parse
|
||||
* function which the client code may use to pass around context.
|
||||
*
|
||||
* All callbacks return an integer. If non-zero, the parse will
|
||||
* continue. If zero, the parse will be canceled and
|
||||
* yajl_status_client_canceled will be returned from the parse.
|
||||
*
|
||||
* \attention {
|
||||
* A note about the handling of numbers:
|
||||
*
|
||||
* yajl will only convert numbers that can be represented in a
|
||||
* double or a 64 bit (long long) int. All other numbers will
|
||||
* be passed to the client in string form using the yajl_number
|
||||
* callback. Furthermore, if yajl_number is not NULL, it will
|
||||
* always be used to return numbers, that is yajl_integer and
|
||||
* yajl_double will be ignored. If yajl_number is NULL but one
|
||||
* of yajl_integer or yajl_double are defined, parsing of a
|
||||
* number larger than is representable in a double or 64 bit
|
||||
* integer will result in a parse error.
|
||||
* }
|
||||
*/
|
||||
typedef struct {
|
||||
int (* yajl_null)(void * ctx);
|
||||
int (* yajl_boolean)(void * ctx, int boolVal);
|
||||
int (* yajl_integer)(void * ctx, int64_t integerVal);
|
||||
int (* yajl_double)(void * ctx, double doubleVal);
|
||||
/** A callback which passes the string representation of the number
|
||||
* back to the client. Will be used for all numbers when present */
|
||||
int (* yajl_number)(void * ctx, const char * numberVal,
|
||||
size_t numberLen);
|
||||
|
||||
/** strings are returned as pointers into the JSON text when,
|
||||
* possible, as a result, they are _not_ null padded */
|
||||
int (* yajl_string)(void * ctx, const unsigned char * stringVal,
|
||||
size_t stringLen);
|
||||
|
||||
int (* yajl_start_map)(void * ctx);
|
||||
int (* yajl_map_key)(void * ctx, const unsigned char * key,
|
||||
size_t stringLen);
|
||||
int (* yajl_end_map)(void * ctx);
|
||||
|
||||
int (* yajl_start_array)(void * ctx);
|
||||
int (* yajl_end_array)(void * ctx);
|
||||
} yajl_callbacks;
|
||||
|
||||
/** allocate a parser handle
|
||||
* \param callbacks a yajl callbacks structure specifying the
|
||||
* functions to call when different JSON entities
|
||||
* are encountered in the input text. May be NULL,
|
||||
* which is only useful for validation.
|
||||
* \param afs memory allocation functions, may be NULL for to use
|
||||
* C runtime library routines (malloc and friends)
|
||||
* \param ctx a context pointer that will be passed to callbacks.
|
||||
*/
|
||||
YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks,
|
||||
yajl_alloc_funcs * afs,
|
||||
void * ctx);
|
||||
|
||||
|
||||
/** configuration parameters for the parser, these may be passed to
|
||||
* yajl_config() along with option specific argument(s). In general,
|
||||
* all configuration parameters default to *off*. */
|
||||
typedef enum {
|
||||
/** Ignore javascript style comments present in
|
||||
* JSON input. Non-standard, but rather fun
|
||||
* arguments: toggled off with integer zero, on otherwise.
|
||||
*
|
||||
* example:
|
||||
* yajl_config(h, yajl_allow_comments, 1); // turn comment support on
|
||||
*/
|
||||
yajl_allow_comments = 0x01,
|
||||
/**
|
||||
* When set the parser will verify that all strings in JSON input are
|
||||
* valid UTF8 and will emit a parse error if this is not so. When set,
|
||||
* this option makes parsing slightly more expensive (~7% depending
|
||||
* on processor and compiler in use)
|
||||
*
|
||||
* example:
|
||||
* yajl_config(h, yajl_dont_validate_strings, 1); // disable utf8 checking
|
||||
*/
|
||||
yajl_dont_validate_strings = 0x02,
|
||||
/**
|
||||
* By default, upon calls to yajl_complete_parse(), yajl will
|
||||
* ensure the entire input text was consumed and will raise an error
|
||||
* otherwise. Enabling this flag will cause yajl to disable this
|
||||
* check. This can be useful when parsing json out of a that contains more
|
||||
* than a single JSON document.
|
||||
*/
|
||||
yajl_allow_trailing_garbage = 0x04,
|
||||
/**
|
||||
* Allow multiple values to be parsed by a single handle. The
|
||||
* entire text must be valid JSON, and values can be seperated
|
||||
* by any kind of whitespace. This flag will change the
|
||||
* behavior of the parser, and cause it continue parsing after
|
||||
* a value is parsed, rather than transitioning into a
|
||||
* complete state. This option can be useful when parsing multiple
|
||||
* values from an input stream.
|
||||
*/
|
||||
yajl_allow_multiple_values = 0x08,
|
||||
/**
|
||||
* When yajl_complete_parse() is called the parser will
|
||||
* check that the top level value was completely consumed. I.E.,
|
||||
* if called whilst in the middle of parsing a value
|
||||
* yajl will enter an error state (premature EOF). Setting this
|
||||
* flag suppresses that check and the corresponding error.
|
||||
*/
|
||||
yajl_allow_partial_values = 0x10
|
||||
} yajl_option;
|
||||
|
||||
/** allow the modification of parser options subsequent to handle
|
||||
* allocation (via yajl_alloc)
|
||||
* \returns zero in case of errors, non-zero otherwise
|
||||
*/
|
||||
YAJL_API int yajl_config(yajl_handle h, yajl_option opt, ...);
|
||||
|
||||
/** free a parser handle */
|
||||
YAJL_API void yajl_free(yajl_handle handle);
|
||||
|
||||
/** Parse some json!
|
||||
* \param hand - a handle to the json parser allocated with yajl_alloc
|
||||
* \param jsonText - a pointer to the UTF8 json text to be parsed
|
||||
* \param jsonTextLength - the length, in bytes, of input text
|
||||
*/
|
||||
YAJL_API yajl_status yajl_parse(yajl_handle hand,
|
||||
const unsigned char * jsonText,
|
||||
size_t jsonTextLength);
|
||||
|
||||
/** Parse any remaining buffered json.
|
||||
* Since yajl is a stream-based parser, without an explicit end of
|
||||
* input, yajl sometimes can't decide if content at the end of the
|
||||
* stream is valid or not. For example, if "1" has been fed in,
|
||||
* yajl can't know whether another digit is next or some character
|
||||
* that would terminate the integer token.
|
||||
*
|
||||
* \param hand - a handle to the json parser allocated with yajl_alloc
|
||||
*/
|
||||
YAJL_API yajl_status yajl_complete_parse(yajl_handle hand);
|
||||
|
||||
/** get an error string describing the state of the
|
||||
* parse.
|
||||
*
|
||||
* If verbose is non-zero, the message will include the JSON
|
||||
* text where the error occured, along with an arrow pointing to
|
||||
* the specific char.
|
||||
*
|
||||
* \returns A dynamically allocated string will be returned which should
|
||||
* be freed with yajl_free_error
|
||||
*/
|
||||
YAJL_API unsigned char * yajl_get_error(yajl_handle hand, int verbose,
|
||||
const unsigned char * jsonText,
|
||||
size_t jsonTextLength);
|
||||
|
||||
/**
|
||||
* get the amount of data consumed from the last chunk passed to YAJL.
|
||||
*
|
||||
* In the case of a successful parse this can help you understand if
|
||||
* the entire buffer was consumed (which will allow you to handle
|
||||
* "junk at end of input").
|
||||
*
|
||||
* In the event an error is encountered during parsing, this function
|
||||
* affords the client a way to get the offset into the most recent
|
||||
* chunk where the error occured. 0 will be returned if no error
|
||||
* was encountered.
|
||||
*/
|
||||
YAJL_API size_t yajl_get_bytes_consumed(yajl_handle hand);
|
||||
|
||||
/** free an error returned from yajl_get_error */
|
||||
YAJL_API void yajl_free_error(yajl_handle hand, unsigned char * str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "yajl_parse.h"
|
||||
#include "yajl_lex.h"
|
||||
#include "yajl_parser.h"
|
||||
#include "yajl_encode.h"
|
||||
#include "yajl_bytestack.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#define MAX_VALUE_TO_MULTIPLY ((INT64_MAX / 10) + (INT64_MAX % 10))
|
||||
|
||||
/* same semantics as strtol */
|
||||
int64_t
|
||||
yajl_parse_integer(const unsigned char *number, unsigned int length)
|
||||
{
|
||||
int64_t ret = 0;
|
||||
long sign = 1;
|
||||
const unsigned char *pos = number;
|
||||
if (*pos == '-') { pos++; sign = -1; }
|
||||
if (*pos == '+') { pos++; }
|
||||
|
||||
while (pos < number + length) {
|
||||
if ( ret > MAX_VALUE_TO_MULTIPLY ) {
|
||||
errno = ERANGE;
|
||||
return sign == 1 ? INT64_MAX : INT64_MIN;
|
||||
}
|
||||
ret *= 10;
|
||||
if (INT64_MAX - ret < (*pos - '0')) {
|
||||
errno = ERANGE;
|
||||
return sign == 1 ? INT64_MAX : INT64_MIN;
|
||||
}
|
||||
if (*pos < '0' || *pos > '9') {
|
||||
errno = ERANGE;
|
||||
return sign == 1 ? INT64_MAX : INT64_MIN;
|
||||
}
|
||||
ret += (*pos++ - '0');
|
||||
}
|
||||
|
||||
return sign * ret;
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, int verbose)
|
||||
{
|
||||
size_t offset = hand->bytesConsumed;
|
||||
unsigned char * str;
|
||||
const char * errorType = NULL;
|
||||
const char * errorText = NULL;
|
||||
char text[72];
|
||||
const char * arrow = " (right here) ------^\n";
|
||||
|
||||
if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) {
|
||||
errorType = "parse";
|
||||
errorText = hand->parseError;
|
||||
} else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) {
|
||||
errorType = "lexical";
|
||||
errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer));
|
||||
} else {
|
||||
errorType = "unknown";
|
||||
}
|
||||
|
||||
{
|
||||
size_t memneeded = 0;
|
||||
memneeded += strlen(errorType);
|
||||
memneeded += strlen(" error");
|
||||
if (errorText != NULL) {
|
||||
memneeded += strlen(": ");
|
||||
memneeded += strlen(errorText);
|
||||
}
|
||||
str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2);
|
||||
if (!str) return NULL;
|
||||
str[0] = 0;
|
||||
strcat((char *) str, errorType);
|
||||
strcat((char *) str, " error");
|
||||
if (errorText != NULL) {
|
||||
strcat((char *) str, ": ");
|
||||
strcat((char *) str, errorText);
|
||||
}
|
||||
strcat((char *) str, "\n");
|
||||
}
|
||||
|
||||
/* now we append as many spaces as needed to make sure the error
|
||||
* falls at char 41, if verbose was specified */
|
||||
if (verbose) {
|
||||
size_t start, end, i;
|
||||
size_t spacesNeeded;
|
||||
|
||||
spacesNeeded = (offset < 30 ? 40 - offset : 10);
|
||||
start = (offset >= 30 ? offset - 30 : 0);
|
||||
end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30);
|
||||
|
||||
for (i=0;i<spacesNeeded;i++) text[i] = ' ';
|
||||
|
||||
for (;start < end;start++, i++) {
|
||||
if (jsonText[start] != '\n' && jsonText[start] != '\r')
|
||||
{
|
||||
text[i] = jsonText[start];
|
||||
}
|
||||
else
|
||||
{
|
||||
text[i] = ' ';
|
||||
}
|
||||
}
|
||||
assert(i <= 71);
|
||||
text[i++] = '\n';
|
||||
text[i] = 0;
|
||||
{
|
||||
char * newStr = (char *)
|
||||
YA_MALLOC(&(hand->alloc), (unsigned int)(strlen((char *) str) +
|
||||
strlen((char *) text) +
|
||||
strlen(arrow) + 1));
|
||||
if (newStr) {
|
||||
newStr[0] = 0;
|
||||
strcat((char *) newStr, (char *) str);
|
||||
strcat((char *) newStr, text);
|
||||
strcat((char *) newStr, arrow);
|
||||
}
|
||||
YA_FREE(&(hand->alloc), str);
|
||||
str = (unsigned char *) newStr;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/* check for client cancelation */
|
||||
#define _CC_CHK(x) \
|
||||
if (!(x)) { \
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error); \
|
||||
hand->parseError = \
|
||||
"client cancelled parse via callback return value"; \
|
||||
return yajl_status_client_canceled; \
|
||||
}
|
||||
|
||||
|
||||
yajl_status
|
||||
yajl_do_finish(yajl_handle hand)
|
||||
{
|
||||
yajl_status stat;
|
||||
stat = yajl_do_parse(hand,(const unsigned char *) " ",1);
|
||||
|
||||
if (stat != yajl_status_ok) return stat;
|
||||
|
||||
switch(yajl_bs_current(hand->stateStack))
|
||||
{
|
||||
case yajl_state_parse_error:
|
||||
case yajl_state_lexical_error:
|
||||
return yajl_status_error;
|
||||
case yajl_state_got_value:
|
||||
case yajl_state_parse_complete:
|
||||
return yajl_status_ok;
|
||||
default:
|
||||
if (!(hand->flags & yajl_allow_partial_values))
|
||||
{
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "premature EOF";
|
||||
return yajl_status_error;
|
||||
}
|
||||
return yajl_status_ok;
|
||||
}
|
||||
}
|
||||
|
||||
yajl_status
|
||||
yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
|
||||
size_t jsonTextLen)
|
||||
{
|
||||
yajl_tok tok;
|
||||
const unsigned char * buf;
|
||||
size_t bufLen;
|
||||
size_t * offset = &(hand->bytesConsumed);
|
||||
|
||||
*offset = 0;
|
||||
|
||||
around_again:
|
||||
switch (yajl_bs_current(hand->stateStack)) {
|
||||
case yajl_state_parse_complete:
|
||||
if (hand->flags & yajl_allow_multiple_values) {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_got_value);
|
||||
goto around_again;
|
||||
}
|
||||
if (!(hand->flags & yajl_allow_trailing_garbage)) {
|
||||
if (*offset != jsonTextLen) {
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
if (tok != yajl_tok_eof) {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "trailing garbage";
|
||||
}
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
return yajl_status_ok;
|
||||
case yajl_state_lexical_error:
|
||||
case yajl_state_parse_error:
|
||||
return yajl_status_error;
|
||||
case yajl_state_start:
|
||||
case yajl_state_got_value:
|
||||
case yajl_state_map_need_val:
|
||||
case yajl_state_array_need_val:
|
||||
case yajl_state_array_start: {
|
||||
/* for arrays and maps, we advance the state for this
|
||||
* depth, then push the state of the next depth.
|
||||
* If an error occurs during the parsing of the nesting
|
||||
* enitity, the state at this level will not matter.
|
||||
* a state that needs pushing will be anything other
|
||||
* than state_start */
|
||||
|
||||
yajl_state stateToPush = yajl_state_start;
|
||||
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
|
||||
switch (tok) {
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
case yajl_tok_string:
|
||||
if (hand->callbacks && hand->callbacks->yajl_string) {
|
||||
_CC_CHK(hand->callbacks->yajl_string(hand->ctx,
|
||||
buf, bufLen));
|
||||
}
|
||||
break;
|
||||
case yajl_tok_string_with_escapes:
|
||||
if (hand->callbacks && hand->callbacks->yajl_string) {
|
||||
yajl_buf_clear(hand->decodeBuf);
|
||||
yajl_string_decode(hand->decodeBuf, buf, bufLen);
|
||||
_CC_CHK(hand->callbacks->yajl_string(
|
||||
hand->ctx, yajl_buf_data(hand->decodeBuf),
|
||||
yajl_buf_len(hand->decodeBuf)));
|
||||
}
|
||||
break;
|
||||
case yajl_tok_bool:
|
||||
if (hand->callbacks && hand->callbacks->yajl_boolean) {
|
||||
_CC_CHK(hand->callbacks->yajl_boolean(hand->ctx,
|
||||
*buf == 't'));
|
||||
}
|
||||
break;
|
||||
case yajl_tok_null:
|
||||
if (hand->callbacks && hand->callbacks->yajl_null) {
|
||||
_CC_CHK(hand->callbacks->yajl_null(hand->ctx));
|
||||
}
|
||||
break;
|
||||
case yajl_tok_left_bracket:
|
||||
if (hand->callbacks && hand->callbacks->yajl_start_map) {
|
||||
_CC_CHK(hand->callbacks->yajl_start_map(hand->ctx));
|
||||
}
|
||||
stateToPush = yajl_state_map_start;
|
||||
break;
|
||||
case yajl_tok_left_brace:
|
||||
if (hand->callbacks && hand->callbacks->yajl_start_array) {
|
||||
_CC_CHK(hand->callbacks->yajl_start_array(hand->ctx));
|
||||
}
|
||||
stateToPush = yajl_state_array_start;
|
||||
break;
|
||||
case yajl_tok_integer:
|
||||
if (hand->callbacks) {
|
||||
if (hand->callbacks->yajl_number) {
|
||||
_CC_CHK(hand->callbacks->yajl_number(
|
||||
hand->ctx,(const char *) buf, bufLen));
|
||||
} else if (hand->callbacks->yajl_integer) {
|
||||
int64_t i = 0;
|
||||
errno = 0;
|
||||
i = yajl_parse_integer(buf, (unsigned int)bufLen);
|
||||
if ((i == INT64_MIN || i == INT64_MAX) &&
|
||||
errno == ERANGE)
|
||||
{
|
||||
yajl_bs_set(hand->stateStack,
|
||||
yajl_state_parse_error);
|
||||
hand->parseError = "integer overflow" ;
|
||||
/* try to restore error offset */
|
||||
if (*offset >= bufLen) *offset -= bufLen;
|
||||
else *offset = 0;
|
||||
goto around_again;
|
||||
}
|
||||
_CC_CHK(hand->callbacks->yajl_integer(hand->ctx,
|
||||
i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case yajl_tok_double:
|
||||
if (hand->callbacks) {
|
||||
if (hand->callbacks->yajl_number) {
|
||||
_CC_CHK(hand->callbacks->yajl_number(
|
||||
hand->ctx, (const char *) buf, bufLen));
|
||||
} else if (hand->callbacks->yajl_double) {
|
||||
double d = 0.0;
|
||||
yajl_buf_clear(hand->decodeBuf);
|
||||
yajl_buf_append(hand->decodeBuf, buf, bufLen);
|
||||
buf = yajl_buf_data(hand->decodeBuf);
|
||||
errno = 0;
|
||||
d = strtod((char *) buf, NULL);
|
||||
if ((d == HUGE_VAL || d == -HUGE_VAL) &&
|
||||
errno == ERANGE)
|
||||
{
|
||||
yajl_bs_set(hand->stateStack,
|
||||
yajl_state_parse_error);
|
||||
hand->parseError = "numeric (floating point) "
|
||||
"overflow";
|
||||
/* try to restore error offset */
|
||||
if (*offset >= bufLen) *offset -= bufLen;
|
||||
else *offset = 0;
|
||||
goto around_again;
|
||||
}
|
||||
_CC_CHK(hand->callbacks->yajl_double(hand->ctx,
|
||||
d));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case yajl_tok_right_brace: {
|
||||
if (yajl_bs_current(hand->stateStack) ==
|
||||
yajl_state_array_start)
|
||||
{
|
||||
if (hand->callbacks &&
|
||||
hand->callbacks->yajl_end_array)
|
||||
{
|
||||
_CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
|
||||
}
|
||||
yajl_bs_pop(hand->stateStack);
|
||||
goto around_again;
|
||||
}
|
||||
/* intentional fall-through */
|
||||
}
|
||||
case yajl_tok_colon:
|
||||
case yajl_tok_comma:
|
||||
case yajl_tok_right_bracket:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError =
|
||||
"unallowed token at this point in JSON text";
|
||||
goto around_again;
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "invalid token, internal error";
|
||||
goto around_again;
|
||||
}
|
||||
/* got a value. transition depends on the state we're in. */
|
||||
{
|
||||
yajl_state s = yajl_bs_current(hand->stateStack);
|
||||
if (s == yajl_state_start || s == yajl_state_got_value) {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_complete);
|
||||
} else if (s == yajl_state_map_need_val) {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_map_got_val);
|
||||
} else {
|
||||
yajl_bs_set(hand->stateStack, yajl_state_array_got_val);
|
||||
}
|
||||
}
|
||||
if (stateToPush != yajl_state_start) {
|
||||
yajl_bs_push(hand->stateStack, stateToPush);
|
||||
}
|
||||
|
||||
goto around_again;
|
||||
}
|
||||
case yajl_state_map_start:
|
||||
case yajl_state_map_need_key: {
|
||||
/* only difference between these two states is that in
|
||||
* start '}' is valid, whereas in need_key, we've parsed
|
||||
* a comma, and a string key _must_ follow */
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
switch (tok) {
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
case yajl_tok_string_with_escapes:
|
||||
if (hand->callbacks && hand->callbacks->yajl_map_key) {
|
||||
yajl_buf_clear(hand->decodeBuf);
|
||||
yajl_string_decode(hand->decodeBuf, buf, bufLen);
|
||||
buf = yajl_buf_data(hand->decodeBuf);
|
||||
bufLen = yajl_buf_len(hand->decodeBuf);
|
||||
}
|
||||
/* intentional fall-through */
|
||||
case yajl_tok_string:
|
||||
if (hand->callbacks && hand->callbacks->yajl_map_key) {
|
||||
_CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf,
|
||||
bufLen));
|
||||
}
|
||||
yajl_bs_set(hand->stateStack, yajl_state_map_sep);
|
||||
goto around_again;
|
||||
case yajl_tok_right_bracket:
|
||||
if (yajl_bs_current(hand->stateStack) ==
|
||||
yajl_state_map_start)
|
||||
{
|
||||
if (hand->callbacks && hand->callbacks->yajl_end_map) {
|
||||
_CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
|
||||
}
|
||||
yajl_bs_pop(hand->stateStack);
|
||||
goto around_again;
|
||||
}
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError =
|
||||
"invalid object key (must be a string)";
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
case yajl_state_map_sep: {
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
switch (tok) {
|
||||
case yajl_tok_colon:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_map_need_val);
|
||||
goto around_again;
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "object key and value must "
|
||||
"be separated by a colon (':')";
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
case yajl_state_map_got_val: {
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
switch (tok) {
|
||||
case yajl_tok_right_bracket:
|
||||
if (hand->callbacks && hand->callbacks->yajl_end_map) {
|
||||
_CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
|
||||
}
|
||||
yajl_bs_pop(hand->stateStack);
|
||||
goto around_again;
|
||||
case yajl_tok_comma:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_map_need_key);
|
||||
goto around_again;
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError = "after key and value, inside map, "
|
||||
"I expect ',' or '}'";
|
||||
/* try to restore error offset */
|
||||
if (*offset >= bufLen) *offset -= bufLen;
|
||||
else *offset = 0;
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
case yajl_state_array_got_val: {
|
||||
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
|
||||
offset, &buf, &bufLen);
|
||||
switch (tok) {
|
||||
case yajl_tok_right_brace:
|
||||
if (hand->callbacks && hand->callbacks->yajl_end_array) {
|
||||
_CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
|
||||
}
|
||||
yajl_bs_pop(hand->stateStack);
|
||||
goto around_again;
|
||||
case yajl_tok_comma:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_array_need_val);
|
||||
goto around_again;
|
||||
case yajl_tok_eof:
|
||||
return yajl_status_ok;
|
||||
case yajl_tok_error:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
|
||||
goto around_again;
|
||||
default:
|
||||
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
|
||||
hand->parseError =
|
||||
"after array element, I expect ',' or ']'";
|
||||
goto around_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abort();
|
||||
return yajl_status_error;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2011, Lloyd Hilaiel <lloyd@hilaiel.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __YAJL_PARSER_H__
|
||||
#define __YAJL_PARSER_H__
|
||||
|
||||
#include "bson-compat.h"
|
||||
|
||||
#include "yajl_parse.h"
|
||||
#include "yajl_bytestack.h"
|
||||
#include "yajl_buf.h"
|
||||
#include "yajl_lex.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
yajl_state_start = 0,
|
||||
yajl_state_parse_complete,
|
||||
yajl_state_parse_error,
|
||||
yajl_state_lexical_error,
|
||||
yajl_state_map_start,
|
||||
yajl_state_map_sep,
|
||||
yajl_state_map_need_val,
|
||||
yajl_state_map_got_val,
|
||||
yajl_state_map_need_key,
|
||||
yajl_state_array_start,
|
||||
yajl_state_array_got_val,
|
||||
yajl_state_array_need_val,
|
||||
yajl_state_got_value,
|
||||
} yajl_state;
|
||||
|
||||
struct yajl_handle_t {
|
||||
const yajl_callbacks * callbacks;
|
||||
void * ctx;
|
||||
yajl_lexer lexer;
|
||||
const char * parseError;
|
||||
/* the number of bytes consumed from the last client buffer,
|
||||
* in the case of an error this will be an error offset, in the
|
||||
* case of an error this can be used as the error offset */
|
||||
size_t bytesConsumed;
|
||||
/* temporary storage for decoded strings */
|
||||
yajl_buf decodeBuf;
|
||||
/* a stack of states. access with yajl_state_XXX routines */
|
||||
yajl_bytestack stateStack;
|
||||
/* memory allocation routines */
|
||||
yajl_alloc_funcs alloc;
|
||||
/* bitfield */
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
yajl_status
|
||||
yajl_do_parse(yajl_handle handle, const unsigned char * jsonText,
|
||||
size_t jsonTextLen);
|
||||
|
||||
yajl_status
|
||||
yajl_do_finish(yajl_handle handle);
|
||||
|
||||
unsigned char *
|
||||
yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
|
||||
size_t jsonTextLen, int verbose);
|
||||
|
||||
/* A little built in integer parsing routine with the same semantics as strtol
|
||||
* that's unaffected by LOCALE. */
|
||||
int64_t
|
||||
yajl_parse_integer(const unsigned char *number, unsigned int length);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011 Florian Forster <ff at octo.it>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "yajl_tree.h"
|
||||
#include "yajl_parse.h"
|
||||
|
||||
#include "yajl_parser.h"
|
||||
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
#define snprintf sprintf_s
|
||||
#endif
|
||||
|
||||
#define STATUS_CONTINUE 1
|
||||
#define STATUS_ABORT 0
|
||||
|
||||
struct stack_elem_s;
|
||||
typedef struct stack_elem_s stack_elem_t;
|
||||
struct stack_elem_s
|
||||
{
|
||||
char * key;
|
||||
yajl_val value;
|
||||
stack_elem_t *next;
|
||||
};
|
||||
|
||||
struct context_s
|
||||
{
|
||||
stack_elem_t *stack;
|
||||
yajl_val root;
|
||||
char *errbuf;
|
||||
size_t errbuf_size;
|
||||
};
|
||||
typedef struct context_s context_t;
|
||||
|
||||
#define RETURN_ERROR(ctx,retval,...) { \
|
||||
if ((ctx)->errbuf != NULL) \
|
||||
snprintf ((ctx)->errbuf, (ctx)->errbuf_size, __VA_ARGS__); \
|
||||
return (retval); \
|
||||
}
|
||||
|
||||
static yajl_val value_alloc (yajl_type type)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = malloc (sizeof (*v));
|
||||
if (v == NULL) return (NULL);
|
||||
memset (v, 0, sizeof (*v));
|
||||
v->type = type;
|
||||
|
||||
return (v);
|
||||
}
|
||||
|
||||
static void yajl_object_free (yajl_val v)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!YAJL_IS_OBJECT(v)) return;
|
||||
|
||||
for (i = 0; i < v->u.object.len; i++)
|
||||
{
|
||||
free((char *) v->u.object.keys[i]);
|
||||
v->u.object.keys[i] = NULL;
|
||||
yajl_tree_free (v->u.object.values[i]);
|
||||
v->u.object.values[i] = NULL;
|
||||
}
|
||||
|
||||
free((void*) v->u.object.keys);
|
||||
free(v->u.object.values);
|
||||
free(v);
|
||||
}
|
||||
|
||||
static void yajl_array_free (yajl_val v)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!YAJL_IS_ARRAY(v)) return;
|
||||
|
||||
for (i = 0; i < v->u.array.len; i++)
|
||||
{
|
||||
yajl_tree_free (v->u.array.values[i]);
|
||||
v->u.array.values[i] = NULL;
|
||||
}
|
||||
|
||||
free(v->u.array.values);
|
||||
free(v);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing nested objects and arrays is implemented using a stack. When a new
|
||||
* object or array starts (a curly or a square opening bracket is read), an
|
||||
* appropriate value is pushed on the stack. When the end of the object is
|
||||
* reached (an appropriate closing bracket has been read), the value is popped
|
||||
* off the stack and added to the enclosing object using "context_add_value".
|
||||
*/
|
||||
static int context_push(context_t *ctx, yajl_val v)
|
||||
{
|
||||
stack_elem_t *stack;
|
||||
|
||||
stack = malloc (sizeof (*stack));
|
||||
if (stack == NULL)
|
||||
RETURN_ERROR (ctx, ENOMEM, "Out of memory");
|
||||
memset (stack, 0, sizeof (*stack));
|
||||
|
||||
assert ((ctx->stack == NULL)
|
||||
|| YAJL_IS_OBJECT (v)
|
||||
|| YAJL_IS_ARRAY (v));
|
||||
|
||||
stack->value = v;
|
||||
stack->next = ctx->stack;
|
||||
ctx->stack = stack;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static yajl_val context_pop(context_t *ctx)
|
||||
{
|
||||
stack_elem_t *stack;
|
||||
yajl_val v;
|
||||
|
||||
if (ctx->stack == NULL)
|
||||
RETURN_ERROR (ctx, NULL, "context_pop: "
|
||||
"Bottom of stack reached prematurely");
|
||||
|
||||
stack = ctx->stack;
|
||||
ctx->stack = stack->next;
|
||||
|
||||
v = stack->value;
|
||||
|
||||
free (stack);
|
||||
|
||||
return (v);
|
||||
}
|
||||
|
||||
static int object_add_keyval(context_t *ctx,
|
||||
yajl_val obj, char *key, yajl_val value)
|
||||
{
|
||||
const char **tmpk;
|
||||
yajl_val *tmpv;
|
||||
|
||||
/* We're checking for NULL in "context_add_value" or its callers. */
|
||||
assert (ctx != NULL);
|
||||
assert (obj != NULL);
|
||||
assert (key != NULL);
|
||||
assert (value != NULL);
|
||||
|
||||
/* We're assuring that "obj" is an object in "context_add_value". */
|
||||
assert(YAJL_IS_OBJECT(obj));
|
||||
|
||||
tmpk = realloc((void *) obj->u.object.keys, sizeof(*(obj->u.object.keys)) * (obj->u.object.len + 1));
|
||||
if (tmpk == NULL)
|
||||
RETURN_ERROR(ctx, ENOMEM, "Out of memory");
|
||||
obj->u.object.keys = tmpk;
|
||||
|
||||
tmpv = realloc(obj->u.object.values, sizeof (*obj->u.object.values) * (obj->u.object.len + 1));
|
||||
if (tmpv == NULL)
|
||||
RETURN_ERROR(ctx, ENOMEM, "Out of memory");
|
||||
obj->u.object.values = tmpv;
|
||||
|
||||
obj->u.object.keys[obj->u.object.len] = key;
|
||||
obj->u.object.values[obj->u.object.len] = value;
|
||||
obj->u.object.len++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int array_add_value (context_t *ctx,
|
||||
yajl_val array, yajl_val value)
|
||||
{
|
||||
yajl_val *tmp;
|
||||
|
||||
/* We're checking for NULL pointers in "context_add_value" or its
|
||||
* callers. */
|
||||
assert (ctx != NULL);
|
||||
assert (array != NULL);
|
||||
assert (value != NULL);
|
||||
|
||||
/* "context_add_value" will only call us with array values. */
|
||||
assert(YAJL_IS_ARRAY(array));
|
||||
|
||||
tmp = realloc(array->u.array.values,
|
||||
sizeof(*(array->u.array.values)) * (array->u.array.len + 1));
|
||||
if (tmp == NULL)
|
||||
RETURN_ERROR(ctx, ENOMEM, "Out of memory");
|
||||
array->u.array.values = tmp;
|
||||
array->u.array.values[array->u.array.len] = value;
|
||||
array->u.array.len++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a value to the value on top of the stack or the "root" member in the
|
||||
* context if the end of the parsing process is reached.
|
||||
*/
|
||||
static int context_add_value (context_t *ctx, yajl_val v)
|
||||
{
|
||||
/* We're checking for NULL values in all the calling functions. */
|
||||
assert (ctx != NULL);
|
||||
assert (v != NULL);
|
||||
|
||||
/*
|
||||
* There are three valid states in which this function may be called:
|
||||
* - There is no value on the stack => This is the only value. This is the
|
||||
* last step done when parsing a document. We assign the value to the
|
||||
* "root" member and return.
|
||||
* - The value on the stack is an object. In this case store the key on the
|
||||
* stack or, if the key has already been read, add key and value to the
|
||||
* object.
|
||||
* - The value on the stack is an array. In this case simply add the value
|
||||
* and return.
|
||||
*/
|
||||
if (ctx->stack == NULL)
|
||||
{
|
||||
assert (ctx->root == NULL);
|
||||
ctx->root = v;
|
||||
return (0);
|
||||
}
|
||||
else if (YAJL_IS_OBJECT (ctx->stack->value))
|
||||
{
|
||||
if (ctx->stack->key == NULL)
|
||||
{
|
||||
if (!YAJL_IS_STRING (v))
|
||||
RETURN_ERROR (ctx, EINVAL, "context_add_value: "
|
||||
"Object key is not a string (%#04x)",
|
||||
v->type);
|
||||
|
||||
ctx->stack->key = v->u.string;
|
||||
v->u.string = NULL;
|
||||
free(v);
|
||||
return (0);
|
||||
}
|
||||
else /* if (ctx->key != NULL) */
|
||||
{
|
||||
char * key;
|
||||
|
||||
key = ctx->stack->key;
|
||||
ctx->stack->key = NULL;
|
||||
return (object_add_keyval (ctx, ctx->stack->value, key, v));
|
||||
}
|
||||
}
|
||||
else if (YAJL_IS_ARRAY (ctx->stack->value))
|
||||
{
|
||||
return (array_add_value (ctx, ctx->stack->value, v));
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURN_ERROR (ctx, EINVAL, "context_add_value: Cannot add value to "
|
||||
"a value of type %#04x (not a composite type)",
|
||||
ctx->stack->value->type);
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_string (void *ctx,
|
||||
const unsigned char *string, size_t string_length)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc (yajl_t_string);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
v->u.string = malloc (string_length + 1);
|
||||
if (v->u.string == NULL)
|
||||
{
|
||||
free (v);
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
}
|
||||
memcpy(v->u.string, string, string_length);
|
||||
v->u.string[string_length] = 0;
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_number (void *ctx, const char *string, size_t string_length)
|
||||
{
|
||||
yajl_val v;
|
||||
char *endptr;
|
||||
|
||||
v = value_alloc(yajl_t_number);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
v->u.number.r = malloc(string_length + 1);
|
||||
if (v->u.number.r == NULL)
|
||||
{
|
||||
free(v);
|
||||
RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
}
|
||||
memcpy(v->u.number.r, string, string_length);
|
||||
v->u.number.r[string_length] = 0;
|
||||
|
||||
v->u.number.flags = 0;
|
||||
|
||||
errno = 0;
|
||||
v->u.number.i = yajl_parse_integer((const unsigned char *) v->u.number.r,
|
||||
(unsigned int)strlen(v->u.number.r));
|
||||
if (errno == 0)
|
||||
v->u.number.flags |= YAJL_NUMBER_INT_VALID;
|
||||
|
||||
endptr = NULL;
|
||||
errno = 0;
|
||||
v->u.number.d = strtod(v->u.number.r, &endptr);
|
||||
if ((errno == 0) && (endptr != NULL) && (*endptr == 0))
|
||||
v->u.number.flags |= YAJL_NUMBER_DOUBLE_VALID;
|
||||
|
||||
return ((context_add_value(ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_start_map (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc(yajl_t_object);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
v->u.object.keys = NULL;
|
||||
v->u.object.values = NULL;
|
||||
v->u.object.len = 0;
|
||||
|
||||
return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_end_map (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = context_pop (ctx);
|
||||
if (v == NULL)
|
||||
return (STATUS_ABORT);
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_start_array (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc(yajl_t_array);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
v->u.array.values = NULL;
|
||||
v->u.array.len = 0;
|
||||
|
||||
return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_end_array (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = context_pop (ctx);
|
||||
if (v == NULL)
|
||||
return (STATUS_ABORT);
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_boolean (void *ctx, int boolean_value)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc (boolean_value ? yajl_t_true : yajl_t_false);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
static int handle_null (void *ctx)
|
||||
{
|
||||
yajl_val v;
|
||||
|
||||
v = value_alloc (yajl_t_null);
|
||||
if (v == NULL)
|
||||
RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory");
|
||||
|
||||
return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
yajl_val yajl_tree_parse (const char *input,
|
||||
char *error_buffer, size_t error_buffer_size)
|
||||
{
|
||||
static const yajl_callbacks callbacks =
|
||||
{
|
||||
/* null = */ handle_null,
|
||||
/* boolean = */ handle_boolean,
|
||||
/* integer = */ NULL,
|
||||
/* double = */ NULL,
|
||||
/* number = */ handle_number,
|
||||
/* string = */ handle_string,
|
||||
/* start map = */ handle_start_map,
|
||||
/* map key = */ handle_string,
|
||||
/* end map = */ handle_end_map,
|
||||
/* start array = */ handle_start_array,
|
||||
/* end array = */ handle_end_array
|
||||
};
|
||||
|
||||
yajl_handle handle;
|
||||
yajl_status status;
|
||||
char * internal_err_str;
|
||||
context_t ctx = { NULL, NULL, NULL, 0 };
|
||||
|
||||
ctx.errbuf = error_buffer;
|
||||
ctx.errbuf_size = error_buffer_size;
|
||||
|
||||
if (error_buffer != NULL)
|
||||
memset (error_buffer, 0, error_buffer_size);
|
||||
|
||||
handle = yajl_alloc (&callbacks, NULL, &ctx);
|
||||
yajl_config(handle, yajl_allow_comments, 1);
|
||||
|
||||
status = yajl_parse(handle,
|
||||
(unsigned char *) input,
|
||||
strlen (input));
|
||||
status = yajl_complete_parse (handle);
|
||||
if (status != yajl_status_ok) {
|
||||
if (error_buffer != NULL && error_buffer_size > 0) {
|
||||
internal_err_str = (char *) yajl_get_error(handle, 1,
|
||||
(const unsigned char *) input,
|
||||
strlen(input));
|
||||
snprintf(error_buffer, error_buffer_size, "%s", internal_err_str);
|
||||
YA_FREE(&(handle->alloc), internal_err_str);
|
||||
}
|
||||
yajl_free (handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
yajl_free (handle);
|
||||
return (ctx.root);
|
||||
}
|
||||
|
||||
yajl_val yajl_tree_get(yajl_val n, const char ** path, yajl_type type)
|
||||
{
|
||||
if (!path) return NULL;
|
||||
while (n && *path) {
|
||||
size_t i;
|
||||
size_t len;
|
||||
|
||||
if (n->type != yajl_t_object) return NULL;
|
||||
len = n->u.object.len;
|
||||
for (i = 0; i < (unsigned int)len; i++) {
|
||||
if (!strcmp(*path, n->u.object.keys[i])) {
|
||||
n = n->u.object.values[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == len) return NULL;
|
||||
path++;
|
||||
}
|
||||
if (n && type != yajl_t_any && type != n->type) n = NULL;
|
||||
return n;
|
||||
}
|
||||
|
||||
void yajl_tree_free (yajl_val v)
|
||||
{
|
||||
if (v == NULL) return;
|
||||
|
||||
if (YAJL_IS_STRING(v))
|
||||
{
|
||||
free(v->u.string);
|
||||
free(v);
|
||||
}
|
||||
else if (YAJL_IS_NUMBER(v))
|
||||
{
|
||||
free(v->u.number.r);
|
||||
free(v);
|
||||
}
|
||||
else if (YAJL_GET_OBJECT(v))
|
||||
{
|
||||
yajl_object_free(v);
|
||||
}
|
||||
else if (YAJL_GET_ARRAY(v))
|
||||
{
|
||||
yajl_array_free(v);
|
||||
}
|
||||
else /* if (yajl_t_true or yajl_t_false or yajl_t_null) */
|
||||
{
|
||||
free(v);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011 Florian Forster <ff at octo.it>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file yajl_tree.h
|
||||
*
|
||||
* Parses JSON data and returns the data in tree form.
|
||||
*
|
||||
* \author Florian Forster
|
||||
* \date August 2010
|
||||
*
|
||||
* This interface makes quick parsing and extraction of
|
||||
* smallish JSON docs trivial:
|
||||
*
|
||||
* \include example/parse_config.c
|
||||
*/
|
||||
|
||||
#ifndef YAJL_TREE_H
|
||||
#define YAJL_TREE_H 1
|
||||
|
||||
#include <yajl/yajl_common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** possible data types that a yajl_val_s can hold */
|
||||
typedef enum {
|
||||
yajl_t_string = 1,
|
||||
yajl_t_number = 2,
|
||||
yajl_t_object = 3,
|
||||
yajl_t_array = 4,
|
||||
yajl_t_true = 5,
|
||||
yajl_t_false = 6,
|
||||
yajl_t_null = 7,
|
||||
/** The any type isn't valid for yajl_val_s.type, but can be
|
||||
* used as an argument to routines like yajl_tree_get().
|
||||
*/
|
||||
yajl_t_any = 8
|
||||
} yajl_type;
|
||||
|
||||
#define YAJL_NUMBER_INT_VALID 0x01
|
||||
#define YAJL_NUMBER_DOUBLE_VALID 0x02
|
||||
|
||||
/** A pointer to a node in the parse tree */
|
||||
typedef struct yajl_val_s * yajl_val;
|
||||
|
||||
/**
|
||||
* A JSON value representation capable of holding one of the seven
|
||||
* types above. For "string", "number", "object", and "array"
|
||||
* additional data is available in the union. The "YAJL_IS_*"
|
||||
* and "YAJL_GET_*" macros below allow type checking and convenient
|
||||
* value extraction.
|
||||
*/
|
||||
struct yajl_val_s
|
||||
{
|
||||
/** Type of the value contained. Use the "YAJL_IS_*" macors to check for a
|
||||
* specific type. */
|
||||
yajl_type type;
|
||||
/** Type-specific data. You may use the "YAJL_GET_*" macros to access these
|
||||
* members. */
|
||||
union
|
||||
{
|
||||
char * string;
|
||||
struct {
|
||||
long long i; /*< integer value, if representable. */
|
||||
double d; /*< double value, if representable. */
|
||||
/** Signals whether the \em i and \em d members are
|
||||
* valid. See \c YAJL_NUMBER_INT_VALID and
|
||||
* \c YAJL_NUMBER_DOUBLE_VALID. */
|
||||
char *r; /*< unparsed number in string form. */
|
||||
unsigned int flags;
|
||||
} number;
|
||||
struct {
|
||||
const char **keys; /*< Array of keys */
|
||||
yajl_val *values; /*< Array of values. */
|
||||
size_t len; /*< Number of key-value-pairs. */
|
||||
} object;
|
||||
struct {
|
||||
yajl_val *values; /*< Array of elements. */
|
||||
size_t len; /*< Number of elements. */
|
||||
} array;
|
||||
} u;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a string.
|
||||
*
|
||||
* Parses an null-terminated string containing JSON data and returns a pointer
|
||||
* to the top-level value (root of the parse tree).
|
||||
*
|
||||
* \param input Pointer to a null-terminated utf8 string containing
|
||||
* JSON data.
|
||||
* \param error_buffer Pointer to a buffer in which an error message will
|
||||
* be stored if \em yajl_tree_parse fails, or
|
||||
* \c NULL. The buffer will be initialized before
|
||||
* parsing, so its content will be destroyed even if
|
||||
* \em yajl_tree_parse succeeds.
|
||||
* \param error_buffer_size Size of the memory area pointed to by
|
||||
* \em error_buffer_size. If \em error_buffer_size is
|
||||
* \c NULL, this argument is ignored.
|
||||
*
|
||||
* \returns Pointer to the top-level value or \c NULL on error. The memory
|
||||
* pointed to must be freed using \em yajl_tree_free. In case of an error, a
|
||||
* null terminated message describing the error in more detail is stored in
|
||||
* \em error_buffer if it is not \c NULL.
|
||||
*/
|
||||
YAJL_API yajl_val yajl_tree_parse (const char *input,
|
||||
char *error_buffer, size_t error_buffer_size);
|
||||
|
||||
/**
|
||||
* Free a parse tree returned by "yajl_tree_parse".
|
||||
*
|
||||
* \param v Pointer to a JSON value returned by "yajl_tree_parse". Passing NULL
|
||||
* is valid and results in a no-op.
|
||||
*/
|
||||
YAJL_API void yajl_tree_free (yajl_val v);
|
||||
|
||||
/**
|
||||
* Access a nested value inside a tree.
|
||||
*
|
||||
* \param parent the node under which you'd like to extract values.
|
||||
* \param path A null terminated array of strings, each the name of an object key
|
||||
* \param type the yajl_type of the object you seek, or yajl_t_any if any will do.
|
||||
*
|
||||
* \returns a pointer to the found value, or NULL if we came up empty.
|
||||
*
|
||||
* Future Ideas: it'd be nice to move path to a string and implement support for
|
||||
* a teeny tiny micro language here, so you can extract array elements, do things
|
||||
* like .first and .last, even .length. Inspiration from JSONPath and css selectors?
|
||||
* No it wouldn't be fast, but that's not what this API is about.
|
||||
*/
|
||||
YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type type);
|
||||
|
||||
/* Various convenience macros to check the type of a `yajl_val` */
|
||||
#define YAJL_IS_STRING(v) (((v) != NULL) && ((v)->type == yajl_t_string))
|
||||
#define YAJL_IS_NUMBER(v) (((v) != NULL) && ((v)->type == yajl_t_number))
|
||||
#define YAJL_IS_INTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->u.number.flags & YAJL_NUMBER_INT_VALID))
|
||||
#define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->u.number.flags & YAJL_NUMBER_DOUBLE_VALID))
|
||||
#define YAJL_IS_OBJECT(v) (((v) != NULL) && ((v)->type == yajl_t_object))
|
||||
#define YAJL_IS_ARRAY(v) (((v) != NULL) && ((v)->type == yajl_t_array ))
|
||||
#define YAJL_IS_TRUE(v) (((v) != NULL) && ((v)->type == yajl_t_true ))
|
||||
#define YAJL_IS_FALSE(v) (((v) != NULL) && ((v)->type == yajl_t_false ))
|
||||
#define YAJL_IS_NULL(v) (((v) != NULL) && ((v)->type == yajl_t_null ))
|
||||
|
||||
/** Given a yajl_val_string return a ptr to the bare string it contains,
|
||||
* or NULL if the value is not a string. */
|
||||
#define YAJL_GET_STRING(v) (YAJL_IS_STRING(v) ? (v)->u.string : NULL)
|
||||
|
||||
/** Get the string representation of a number. You should check type first,
|
||||
* perhaps using YAJL_IS_NUMBER */
|
||||
#define YAJL_GET_NUMBER(v) ((v)->u.number.r)
|
||||
|
||||
/** Get the double representation of a number. You should check type first,
|
||||
* perhaps using YAJL_IS_DOUBLE */
|
||||
#define YAJL_GET_DOUBLE(v) ((v)->u.number.d)
|
||||
|
||||
/** Get the 64bit (long long) integer representation of a number. You should
|
||||
* check type first, perhaps using YAJL_IS_INTEGER */
|
||||
#define YAJL_GET_INTEGER(v) ((v)->u.number.i)
|
||||
|
||||
/** Get a pointer to a yajl_val_object or NULL if the value is not an object. */
|
||||
#define YAJL_GET_OBJECT(v) (YAJL_IS_OBJECT(v) ? &(v)->u.object : NULL)
|
||||
|
||||
/** Get a pointer to a yajl_val_array or NULL if the value is not an object. */
|
||||
#define YAJL_GET_ARRAY(v) (YAJL_IS_ARRAY(v) ? &(v)->u.array : NULL)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* YAJL_TREE_H */
|
||||
@@ -0,0 +1,7 @@
|
||||
#include <yajl/yajl_version.h>
|
||||
|
||||
int yajl_version(void)
|
||||
{
|
||||
return YAJL_VERSION;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user